diff --git a/.gitignore b/.gitignore
index 89c81664..f9f952a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,6 +48,7 @@
 tags
 Thumbs.db
 v8.log
+vs-chromium-project.txt
 # Settings directories for eclipse
 /.externalToolBuilders/
 /.settings/
diff --git a/.gn b/.gn
index 3ffa5a5b..4b0b203 100644
--- a/.gn
+++ b/.gn
@@ -42,7 +42,7 @@
   "//device/*",
 
   #"//extensions/*",  # Lots of errors.
-  #"//gin/*",  # Easy.
+  "//gin/*",
   "//google_apis/*",
   "//google_update/*",
 
diff --git a/AUTHORS b/AUTHORS
index 253a383a..ddd50da 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -422,6 +422,7 @@
 Nikita Ofitserov <himikof@gmail.com>
 Ningxin Hu <ningxin.hu@intel.com>
 Nitish Mehrotra <nitish.m@samsung.com>
+Nolan Cao <nolan.robin.cao@gmail.com>
 Pan Deng <pan.deng@intel.com>
 Parag Radke <nrqv63@motorola.com>
 Paritosh Kumar <paritosh.in@samsung.com>
diff --git a/BUILD.gn b/BUILD.gn
index 60a313e..9845ff4d 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -185,8 +185,8 @@
       #"//mojo/edk/test:mojo_public_environment_unittests",
       #"//mojo/edk/test:mojo_public_system_unittests",
       #"//mojo/edk/test:mojo_public_utility_unittests",
-      "//third_party/WebKit/Source/platform:heap_unittests",
-      "//third_party/WebKit/Source/platform:platform_unittests",
+      "//third_party/WebKit/Source/platform:blink_heap_unittests",
+      "//third_party/WebKit/Source/platform:blink_platform_unittests",
       "//third_party/WebKit/Source/web:webkit_unit_tests",
       "//third_party/WebKit/Source/wtf:wtf_unittests",
       "//third_party/mojo/src/mojo/edk/system:mojo_system_unittests",
@@ -276,6 +276,7 @@
       "//testing/android/junit:junit_unittests",
       "//third_party/errorprone:chromium_errorprone",
       "//tools/android:android_tools",
+      "//tools/android:memconsumer",
       "//tools/android/heap_profiler:heap_profiler_unittests",
       "//tools/android/kerberos/SpnegoAuthenticator:spnego_authenticator_apk",
       "//tools/imagediff($host_toolchain)",
diff --git a/DEPS b/DEPS
index 09743ea..507ebe0c 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': 'dfd6c6e3bb8c951fcd2bf85995629f1c8ef76590',
+  'skia_revision': '2028d7ff744c36855ed36d602e3e050e9f18ec9f',
   # 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': '366fa3fda6016dd232d50a7b4d0134e53902e97e',
+  'v8_revision': '1266d06c4aebbf0227723f472b6e856db1f8363e',
   # 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.
@@ -59,7 +59,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '628f7053cc646c58c61add247c75bc65ac135327',
+  'pdfium_revision': '0c92bed7ade20fe193dce0a481dad48e1be41622',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -187,7 +187,7 @@
    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '23831545a0a148a066b905c0f1e011375c97d790',
 
   'src/third_party/ffmpeg':
-   Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'b5b1d0e988d68b2bba2eb2deeacf77079f70ddfa',
+   Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '070a9786327261f6f91d565fda5c39269a192638',
 
   'src/third_party/libjingle/source/talk':
     Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '917ba7e47b92bea2e157c4a42f091bfa44b0836f', # commit position 10903
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 52e3b62..9a7f4c34 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -164,6 +164,7 @@
       ),
       True,
       (
+        r"^base[\\\/]process[\\\/]process_linux\.cc$",
         r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
         r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
         r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 381a4a1..b5f5fbc 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -10,9 +10,11 @@
 import("webview_repack_locales.gni")
 
 group("android_webview") {
-  deps = [
-    ":system_webview_apk",
-  ]
+  if (!use_webview_internal_framework) {
+    deps = [
+      ":system_webview_apk",
+    ]
+  }
 }
 
 jinja_template("system_webview_manifest") {
@@ -643,13 +645,15 @@
   ]
 }
 
-system_webview_apk_tmpl("system_webview_apk") {
-  android_manifest = get_target_outputs(":system_webview_manifest")
-  android_manifest = android_manifest[1]
-  android_manifest_dep = ":system_webview_manifest"
-  deps = [
-    ":system_webview_resources",
-    "//android_webview/glue",
-  ]
-  apk_name = "SystemWebView"
+if (!use_webview_internal_framework) {
+  system_webview_apk_tmpl("system_webview_apk") {
+    android_manifest = get_target_outputs(":system_webview_manifest")
+    android_manifest = android_manifest[1]
+    android_manifest_dep = ":system_webview_manifest"
+    deps = [
+      ":system_webview_resources",
+      "//android_webview/glue",
+    ]
+    apk_name = "SystemWebView"
+  }
 }
diff --git a/android_webview/android_webview.gyp b/android_webview/android_webview.gyp
index 00ecd5e..6b9e7b0 100644
--- a/android_webview/android_webview.gyp
+++ b/android_webview/android_webview.gyp
@@ -469,21 +469,27 @@
       },
       'includes': [ 'apk/system_webview_glue_common.gypi' ],
     },
-    # GN version:  //android_webview:system_webview_apk
-    {
-      'target_name': 'system_webview_apk',
-      'dependencies': [
-        'system_webview_glue_java',
+  ],
+  'conditions': [
+    ['use_webview_internal_framework==0', {
+      'targets': [
+        # GN version:  //android_webview:system_webview_apk
+        {
+          'target_name': 'system_webview_apk',
+          'dependencies': [
+            'system_webview_glue_java',
+          ],
+          'variables': {
+            'apk_name': 'SystemWebView',
+            'android_sdk_jar': '../third_party/android_platform/webview/frameworks_6.0.jar',
+            'java_in_dir': '../build/android/empty',
+            'resource_dir': 'apk/java/res',
+            'android_manifest_template_vars': ['package=<(system_webview_package_name)'],
+          },
+          'includes': [ 'apk/system_webview_apk_common.gypi' ],
+        },
       ],
-      'variables': {
-        'apk_name': 'SystemWebView',
-        'android_sdk_jar': '../third_party/android_platform/webview/frameworks_6.0.jar',
-        'java_in_dir': '../build/android/empty',
-        'resource_dir': 'apk/java/res',
-        'android_manifest_template_vars': ['package=<(system_webview_package_name)'],
-      },
-      'includes': [ 'apk/system_webview_apk_common.gypi' ],
-    },
+    }]
   ],
   'includes': [
     'android_webview_tests.gypi',
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index 4f3fdb1..12a2fb63 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -60,6 +60,8 @@
 }  // namespace prefs
 
 namespace {
+// Name of the preference that governs enabling the Data Reduction Proxy.
+const char kDataReductionProxyEnabled[] = "data_reduction_proxy.enabled";
 
 // Shows notifications which correspond to PersistentPrefStore's reading errors.
 void HandleReadError(PersistentPrefStore::PrefReadError error) {
@@ -243,6 +245,7 @@
 
   // TODO(dgn) lazy init, see http://crbug.com/521542
   data_reduction_proxy_settings_->InitDataReductionProxySettings(
+      kDataReductionProxyEnabled,
       user_pref_service_.get(), data_reduction_proxy_io_data_.get(),
       data_reduction_proxy_service_.Pass());
   data_reduction_proxy_settings_->MaybeActivateDataReductionProxy(true);
@@ -325,6 +328,7 @@
       autofill::prefs::kAutofillPositiveUploadRate, 0.0);
   pref_registry->RegisterDoublePref(
       autofill::prefs::kAutofillNegativeUploadRate, 0.0);
+  pref_registry->RegisterBooleanPref(kDataReductionProxyEnabled, false);
   data_reduction_proxy::RegisterSimpleProfilePrefs(pref_registry);
   policy::URLBlacklistManager::RegisterProfilePrefs(pref_registry);
 
diff --git a/android_webview/browser/net/android_stream_reader_url_request_job_unittest.cc b/android_webview/browser/net/android_stream_reader_url_request_job_unittest.cc
index 37416ba..50b0cc4 100644
--- a/android_webview/browser/net/android_stream_reader_url_request_job_unittest.cc
+++ b/android_webview/browser/net/android_stream_reader_url_request_job_unittest.cc
@@ -166,13 +166,14 @@
     task_runner_ = base::ThreadTaskRunnerHandle::Get();
   }
 
+  ~TestStreamReaderJob() override {}
+
   scoped_ptr<InputStreamReader> CreateStreamReader(
       InputStream* stream) override {
     return stream_reader_.Pass();
   }
- protected:
-  ~TestStreamReaderJob() override {}
 
+ protected:
   base::TaskRunner* GetWorkerThreadRunner() override {
     return task_runner_.get();
   }
@@ -214,23 +215,15 @@
   void SetUpTestJob(scoped_ptr<InputStreamReader> stream_reader,
                     scoped_ptr<AndroidStreamReaderURLRequestJob::Delegate>
                         stream_reader_delegate) {
-    TestStreamReaderJob* test_stream_reader_job =
-        new TestStreamReaderJob(
-            req_.get(),
-            &network_delegate_,
-            stream_reader_delegate.Pass(),
-            stream_reader.Pass());
+    scoped_ptr<TestStreamReaderJob> test_stream_reader_job(
+        new TestStreamReaderJob(req_.get(), &network_delegate_,
+                                stream_reader_delegate.Pass(),
+                                stream_reader.Pass()));
     // The Interceptor is owned by the |factory_|.
-    TestJobInterceptor* protocol_handler = new TestJobInterceptor;
-    protocol_handler->set_main_intercept_job(test_stream_reader_job);
+    scoped_ptr<TestJobInterceptor> protocol_handler(new TestJobInterceptor);
+    protocol_handler->set_main_intercept_job(std::move(test_stream_reader_job));
     bool set_protocol =
-        factory_.SetProtocolHandler("http", make_scoped_ptr(protocol_handler));
-    DCHECK(set_protocol);
-
-    protocol_handler = new TestJobInterceptor;
-    protocol_handler->set_main_intercept_job(test_stream_reader_job);
-    set_protocol = factory_.SetProtocolHandler(
-        "content", make_scoped_ptr(protocol_handler));
+        factory_.SetProtocolHandler("content", std::move(protocol_handler));
     DCHECK(set_protocol);
   }
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFaviconTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFaviconTest.java
index 2c0408a..86c10a2 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFaviconTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFaviconTest.java
@@ -12,12 +12,10 @@
 
 import org.chromium.android_webview.AwContents;
 import org.chromium.android_webview.test.util.CommonResources;
-import org.chromium.content.browser.test.util.CallbackHelper;
 import org.chromium.net.test.util.TestWebServer;
 
 import java.io.InputStream;
 import java.net.URL;
-import java.util.HashMap;
 import java.util.concurrent.Callable;
 
 /**
@@ -46,42 +44,7 @@
     // Maximum number of milliseconds within which a request to web server is made.
     private static final long MAX_REQUEST_WAITING_LIMIT_MS = scaleTimeout(500);
 
-    private static class FaviconHelper extends CallbackHelper {
-        private Bitmap mIcon;
-        private HashMap<String, Boolean> mTouchIcons = new HashMap<String, Boolean>();
-
-        public void notifyFavicon(Bitmap icon) {
-            mIcon = icon;
-            super.notifyCalled();
-        }
-
-        public void notifyTouchIcon(String url, boolean precomposed) {
-            mTouchIcons.put(url, precomposed);
-            super.notifyCalled();
-        }
-    }
-
-    private static class TestAwContentsClientBase
-            extends org.chromium.android_webview.test.TestAwContentsClient {
-        FaviconHelper mFaviconHelper = new FaviconHelper();
-    }
-
-    private static class TestAwContentsClientFavicon extends TestAwContentsClientBase {
-        @Override
-        public void onReceivedIcon(Bitmap bitmap) {
-            // We don't inform the API client about the URL of the icon.
-            mFaviconHelper.notifyFavicon(bitmap);
-        }
-    }
-
-    private static class TestAwContentsClientTouchIcon extends TestAwContentsClientBase {
-        @Override
-        public void onReceivedTouchIconUrl(String url, boolean precomposed) {
-            mFaviconHelper.notifyTouchIcon(url, precomposed);
-        }
-    }
-
-    private TestAwContentsClientBase mContentsClient;
+    private TestAwContentsClient mContentsClient;
     private AwContents mAwContents;
     private TestWebServer mWebServer;
 
@@ -89,14 +52,11 @@
     protected void setUp() throws Exception {
         super.setUp();
         AwContents.setShouldDownloadFavicons();
-        mWebServer = TestWebServer.start();
-    }
-
-    private void init(TestAwContentsClientBase contentsClient) throws Exception {
-        mContentsClient = contentsClient;
+        mContentsClient = new TestAwContentsClient();
         AwTestContainerView testContainerView =
                 createAwTestContainerViewOnMainSync(mContentsClient);
         mAwContents = testContainerView.getAwContents();
+        mWebServer = TestWebServer.start();
     }
 
     @Override
@@ -107,8 +67,7 @@
 
     @SmallTest
     public void testReceiveBasicFavicon() throws Throwable {
-        init(new TestAwContentsClientFavicon());
-        int callCount = mContentsClient.mFaviconHelper.getCallCount();
+        int callCount = mContentsClient.getFaviconHelper().getCallCount();
 
         final String faviconUrl = mWebServer.setResponseBase64(FAVICON1_URL,
                 CommonResources.FAVICON_DATA_BASE64, CommonResources.getImagePngHeaders(true));
@@ -117,25 +76,23 @@
 
         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageUrl);
 
-        mContentsClient.mFaviconHelper.waitForCallback(callCount);
+        mContentsClient.getFaviconHelper().waitForCallback(callCount);
         assertEquals(1, mWebServer.getRequestCount(FAVICON1_URL));
         Object originalFaviconSource = (new URL(faviconUrl)).getContent();
         Bitmap originalFavicon = BitmapFactory.decodeStream((InputStream) originalFaviconSource);
         assertNotNull(originalFavicon);
-        assertNotNull(mContentsClient.mFaviconHelper.mIcon);
-        assertTrue(mContentsClient.mFaviconHelper.mIcon.sameAs(originalFavicon));
+        assertNotNull(mContentsClient.getFaviconHelper().getIcon());
+        assertTrue(mContentsClient.getFaviconHelper().getIcon().sameAs(originalFavicon));
 
         // Make sure the request counter for favicon is incremented when the page is loaded again
         // successfully.
         loadUrlAsync(mAwContents, pageUrl);
-        mContentsClient.mFaviconHelper.waitForCallback(callCount);
+        mContentsClient.getFaviconHelper().waitForCallback(callCount);
         assertEquals(2, mWebServer.getRequestCount(FAVICON1_URL));
     }
 
     @SmallTest
     public void testDoNotMakeRequestForFaviconAfter404() throws Throwable {
-        init(new TestAwContentsClientFavicon());
-
         mWebServer.setResponseWithNotFoundStatus(FAVICON1_URL);
         final String pageUrl = mWebServer.setResponse(FAVICON1_PAGE_URL, FAVICON1_PAGE_HTML,
                 CommonResources.getTextHtmlHeaders(true));
@@ -157,18 +114,18 @@
 
     @SmallTest
     public void testReceiveBasicTouchIconLinkRel() throws Throwable {
-        init(new TestAwContentsClientTouchIcon());
-        int callCount = mContentsClient.mFaviconHelper.getCallCount();
+        int callCount = mContentsClient.getFaviconHelper().getCallCount();
 
         final String pageUrl = mWebServer.setResponse(TOUCHICON_REL_URL, TOUCHICON_REL_PAGE_HTML,
                 CommonResources.getTextHtmlHeaders(true));
 
         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageUrl);
 
-        mContentsClient.mFaviconHelper.waitForCallback(callCount, 2);
-        HashMap<String, Boolean> touchIcons = mContentsClient.mFaviconHelper.mTouchIcons;
-        assertEquals(2, touchIcons.size());
-        assertFalse(touchIcons.get(mWebServer.getBaseUrl() + TOUCHICON_REL_LINK));
-        assertFalse(touchIcons.get(mWebServer.getBaseUrl() + TOUCHICON_REL_LINK_72));
+        mContentsClient.getTouchIconHelper().waitForCallback(callCount, 2);
+        assertEquals(2, mContentsClient.getTouchIconHelper().getTouchIconsCount());
+        assertFalse(mContentsClient.getTouchIconHelper().hasTouchIcon(
+                        mWebServer.getBaseUrl() + TOUCHICON_REL_LINK));
+        assertFalse(mContentsClient.getTouchIconHelper().hasTouchIcon(
+                        mWebServer.getBaseUrl() + TOUCHICON_REL_LINK_72));
     }
 }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/NavigationHistoryTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/NavigationHistoryTest.java
index 380fc68..612ae69 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/NavigationHistoryTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/NavigationHistoryTest.java
@@ -9,7 +9,6 @@
 import org.chromium.android_webview.AwContents;
 import org.chromium.android_webview.test.util.CommonResources;
 import org.chromium.base.ThreadUtils;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.content.browser.test.util.HistoryUtils;
 import org.chromium.content.browser.test.util.TestCallbackHelperContainer;
 import org.chromium.content_public.browser.NavigationEntry;
@@ -188,27 +187,20 @@
         assertEquals(0, list.getCurrentEntryIndex());
     }
 
-    /**
-     * Disabled until favicons are getting fetched when using ContentView.
-     *
-     * @SmallTest
-     * @throws Throwable
-     */
-    @DisabledTest
     public void testFavicon() throws Throwable {
-        NavigationHistory list = getNavigationHistory(mAwContents);
-
         mWebServer.setResponseBase64("/" + CommonResources.FAVICON_FILENAME,
                 CommonResources.FAVICON_DATA_BASE64, CommonResources.getImagePngHeaders(false));
         final String url = mWebServer.setResponse("/favicon.html",
                 CommonResources.FAVICON_STATIC_HTML, null);
 
+        NavigationHistory list = getNavigationHistory(mAwContents);
         assertEquals(0, list.getEntryCount());
         getAwSettingsOnUiThread(mAwContents).setImagesEnabled(true);
+        int faviconLoadCount = mContentsClient.getFaviconHelper().getCallCount();
         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), url);
+        mContentsClient.getFaviconHelper().waitForCallback(faviconLoadCount);
 
         list = getNavigationHistory(mAwContents);
-
         // Make sure the first entry is still okay.
         checkHistoryItem(list.getEntryAtIndex(0), url, url, "", false);
     }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java b/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
index 798a2149..428e97c 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
@@ -4,6 +4,7 @@
 
 package org.chromium.android_webview.test;
 
+import android.graphics.Bitmap;
 import android.graphics.Picture;
 import android.net.http.SslError;
 import android.webkit.ConsoleMessage;
@@ -20,6 +21,7 @@
 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnReceivedErrorHelper;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -45,6 +47,8 @@
     private final ShouldOverrideUrlLoadingHelper mShouldOverrideUrlLoadingHelper;
     private final DoUpdateVisitedHistoryHelper mDoUpdateVisitedHistoryHelper;
     private final OnCreateWindowHelper mOnCreateWindowHelper;
+    private final FaviconHelper mFaviconHelper;
+    private final TouchIconHelper mTouchIconHelper;
 
     public TestAwContentsClient() {
         super(ThreadUtils.getUiThreadLooper());
@@ -66,6 +70,8 @@
         mShouldOverrideUrlLoadingHelper = new ShouldOverrideUrlLoadingHelper();
         mDoUpdateVisitedHistoryHelper = new DoUpdateVisitedHistoryHelper();
         mOnCreateWindowHelper = new OnCreateWindowHelper();
+        mFaviconHelper = new FaviconHelper();
+        mTouchIconHelper = new TouchIconHelper();
         mAllowSslError = true;
     }
 
@@ -144,6 +150,14 @@
         return mOnCreateWindowHelper;
     }
 
+    public FaviconHelper getFaviconHelper() {
+        return mFaviconHelper;
+    }
+
+    public TouchIconHelper getTouchIconHelper() {
+        return mTouchIconHelper;
+    }
+
     /**
      * Callback helper for onScaleChangedScaled.
      */
@@ -581,4 +595,53 @@
         super.onReceivedHttpError(request, response);
         mOnReceivedHttpErrorHelper.notifyCalled(request, response);
     }
+
+    /**
+     * CallbackHelper for onReceivedIcon.
+     */
+    public static class FaviconHelper extends CallbackHelper {
+        private Bitmap mIcon;
+
+        public void notifyFavicon(Bitmap icon) {
+            mIcon = icon;
+            super.notifyCalled();
+        }
+
+        public Bitmap getIcon() {
+            assert getCallCount() > 0;
+            return mIcon;
+        }
+    }
+
+    @Override
+    public void onReceivedIcon(Bitmap bitmap) {
+        // We don't inform the API client about the URL of the icon.
+        mFaviconHelper.notifyFavicon(bitmap);
+    }
+
+    /**
+     * CallbackHelper for onReceivedTouchIconUrl.
+     */
+    public static class TouchIconHelper extends CallbackHelper {
+        private HashMap<String, Boolean> mTouchIcons = new HashMap<String, Boolean>();
+
+        public void notifyTouchIcon(String url, boolean precomposed) {
+            mTouchIcons.put(url, precomposed);
+            super.notifyCalled();
+        }
+
+        public int getTouchIconsCount() {
+            assert getCallCount() > 0;
+            return mTouchIcons.size();
+        }
+
+        public boolean hasTouchIcon(String url) {
+            return mTouchIcons.get(url);
+        }
+    }
+
+    @Override
+    public void onReceivedTouchIconUrl(String url, boolean precomposed) {
+        mTouchIconHelper.notifyTouchIcon(url, precomposed);
+    }
 }
diff --git a/apps/saved_files_service.cc b/apps/saved_files_service.cc
index e4a4fd9..49d9667 100644
--- a/apps/saved_files_service.cc
+++ b/apps/saved_files_service.cc
@@ -17,7 +17,6 @@
 #include "extensions/browser/extension_host.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_system.h"
-#include "extensions/browser/extension_util.h"
 #include "extensions/browser/notification_types.h"
 #include "extensions/common/permissions/api_permission.h"
 #include "extensions/common/permissions/permission_set.h"
@@ -261,8 +260,7 @@
 
 void SavedFilesService::ClearQueueIfNoRetainPermission(
     const Extension* extension) {
-  if (extensions::util::IsEphemeralApp(extension->id(), profile_) ||
-      !extension->permissions_data()->active_permissions().HasAPIPermission(
+  if (!extension->permissions_data()->active_permissions().HasAPIPermission(
           APIPermission::kFileSystemRetainEntries)) {
     ClearQueue(extension);
   }
diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc
index 7b0d5a0..fa706e05b 100644
--- a/ash/test/ash_test_base.cc
+++ b/ash/test/ash_test_base.cc
@@ -75,6 +75,12 @@
     return aura::client::GetScreenPositionClient(window->GetRootWindow());
   }
 
+  void DispatchKeyEventToIME(ui::EventTarget* target,
+                             ui::KeyEvent* event) override {
+    // In Ash environment, the key event will be processed by event rewriters
+    // first.
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(AshEventGeneratorDelegate);
 };
diff --git a/ash/wm/toplevel_window_event_handler.cc b/ash/wm/toplevel_window_event_handler.cc
index ecb4b3b..1b7ae90 100644
--- a/ash/wm/toplevel_window_event_handler.cc
+++ b/ash/wm/toplevel_window_event_handler.cc
@@ -582,8 +582,12 @@
 }
 
 void ToplevelWindowEventHandler::HandleCaptureLost(ui::LocatedEvent* event) {
-  if (event->phase() == ui::EP_PRETARGET)
-    CompleteDrag(DRAG_REVERT);
+  if (event->phase() == ui::EP_PRETARGET) {
+    // We complete the drag instead of reverting it, as reverting it will result
+    // in a weird behavior when a dragged tab produces a modal dialog while the
+    // drag is in progress. crbug.com/558201.
+    CompleteDrag(DRAG_COMPLETE);
+  }
 }
 
 void ToplevelWindowEventHandler::SetWindowStateTypeFromGesture(
diff --git a/ash/wm/toplevel_window_event_handler_unittest.cc b/ash/wm/toplevel_window_event_handler_unittest.cc
index bec3eae0..c2d708f 100644
--- a/ash/wm/toplevel_window_event_handler_unittest.cc
+++ b/ash/wm/toplevel_window_event_handler_unittest.cc
@@ -736,7 +736,7 @@
 
 }  // namespace
 
-// Test that releasing capture cancels an in-progress gesture drag.
+// Test that releasing capture completes an in-progress gesture drag.
 TEST_F(ToplevelWindowEventHandlerTest, GestureDragCaptureLoss) {
   scoped_ptr<aura::Window> window(CreateWindow(HTNOWHERE));
   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
@@ -747,7 +747,7 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&CheckHasCaptureAndReleaseCapture,
                             base::Unretained(window.get())));
-  EXPECT_EQ(aura::client::MOVE_CANCELED,
+  EXPECT_EQ(aura::client::MOVE_SUCCESSFUL,
             move_client->RunMoveLoop(window.get(), gfx::Vector2d(),
                                      aura::client::WINDOW_MOVE_SOURCE_TOUCH));
 }
diff --git a/base/android/java/src/org/chromium/base/PathUtils.java b/base/android/java/src/org/chromium/base/PathUtils.java
index 81c74f4..fe14c278 100644
--- a/base/android/java/src/org/chromium/base/PathUtils.java
+++ b/base/android/java/src/org/chromium/base/PathUtils.java
@@ -102,7 +102,14 @@
 
     public static File getThumbnailCacheDirectory(Context appContext) {
         if (sThumbnailDirectory == null) {
-            sThumbnailDirectory = appContext.getDir(THUMBNAIL_DIRECTORY, Context.MODE_PRIVATE);
+            // Temporarily allowing disk access while fixing. TODO: http://crbug.com/473356
+            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+            StrictMode.allowThreadDiskWrites();
+            try {
+                sThumbnailDirectory = appContext.getDir(THUMBNAIL_DIRECTORY, Context.MODE_PRIVATE);
+            } finally {
+                StrictMode.setThreadPolicy(oldPolicy);
+            }
         }
         return sThumbnailDirectory;
     }
diff --git a/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java b/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java
index c1fc667..aaa37de6 100644
--- a/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java
+++ b/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java
@@ -125,14 +125,14 @@
     // This is triggered by the @CalledByNative annotation; the methods may be named as you wish.
 
     // Exported to C++ as:
-    // Java_Example_javaMethod(JNIEnv* env, jobject caller, jint foo, jint bar)
+    // Java_SampleForTests_javaMethod(JNIEnv* env, jobject caller, jint foo, jint bar)
     // Typically the C++ code would have obtained the jobject via the Init() call described above.
     @CalledByNative
     public int javaMethod(int foo, int bar) {
         return 0;
     }
 
-    // Exported to C++ as Java_Example_staticJavaMethod(JNIEnv* env)
+    // Exported to C++ as Java_SampleForTests_staticJavaMethod(JNIEnv* env)
     // Note no jobject argument, as it is static.
     @CalledByNative
     public static boolean staticJavaMethod() {
diff --git a/base/android/linker/config.gni b/base/android/linker/config.gni
index a84aca6..d07caa6 100644
--- a/base/android/linker/config.gni
+++ b/base/android/linker/config.gni
@@ -3,7 +3,9 @@
 # found in the LICENSE file.
 
 import("//build/config/android/config.gni")
+import("//build/config/sanitizers/sanitizers.gni")
 
 # Chromium linker crashes on component builds on Android 4.4. See b/11379966
 # Chromium linker causes instrumentation to return incorrect results.
-chromium_linker_supported = !is_component_build && !use_order_profiling
+chromium_linker_supported =
+    !is_component_build && !use_order_profiling && !is_asan
diff --git a/base/basictypes.h b/base/basictypes.h
index e39e29fb..0d9d24c0 100644
--- a/base/basictypes.h
+++ b/base/basictypes.h
@@ -26,8 +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 uint64 kuint64max =  0xFFFFFFFFFFFFFFFFULL;
 const  int32 kint32max  =  0x7FFFFFFF;
-const  int64 kint64max  =  0x7FFFFFFFFFFFFFFFLL;
 
 #endif  // BASE_BASICTYPES_H_
diff --git a/base/file_version_info_unittest.cc b/base/file_version_info_unittest.cc
index c5e98594..d4ab9541 100644
--- a/base/file_version_info_unittest.cc
+++ b/base/file_version_info_unittest.cc
@@ -93,7 +93,7 @@
   // Test consistency check.
   ASSERT_EQ(arraysize(kDLLNames), arraysize(kExpected));
 
-  for (int i = 0; i < arraysize(kDLLNames); ++i) {
+  for (size_t i = 0; i < arraysize(kDLLNames); ++i) {
     FilePath dll_path = GetTestDataPath();
     dll_path = dll_path.Append(kDLLNames[i]);
 
diff --git a/base/file_version_info_win.cc b/base/file_version_info_win.cc
index ca3e4b1..a7dc216 100644
--- a/base/file_version_info_win.cc
+++ b/base/file_version_info_win.cc
@@ -149,7 +149,7 @@
 bool FileVersionInfoWin::GetValue(const wchar_t* name,
                                   std::wstring* value_str) {
   WORD lang_codepage[8];
-  int i = 0;
+  size_t i = 0;
   // Use the language and codepage from the DLL.
   lang_codepage[i++] = language_;
   lang_codepage[i++] = code_page_;
diff --git a/base/files/file_util_unittest.cc b/base/files/file_util_unittest.cc
index 933cb7f..748301d 100644
--- a/base/files/file_util_unittest.cc
+++ b/base/files/file_util_unittest.cc
@@ -353,7 +353,8 @@
 
   FilePath long_name = sub_a.Append(FilePath(long_name_str));
   FilePath deep_file = long_name.Append(sub_long_rel).Append(deep_txt);
-  ASSERT_EQ(MAX_PATH - kCreateDirLimit, deep_file.value().length());
+  ASSERT_EQ(static_cast<size_t>(MAX_PATH - kCreateDirLimit),
+            deep_file.value().length());
 
   FilePath sub_long = deep_file.DirName();
   ASSERT_TRUE(CreateDirectory(sub_long));
diff --git a/base/message_loop/message_loop_unittest.cc b/base/message_loop/message_loop_unittest.cc
index dcac6624..c08dc7f 100644
--- a/base/message_loop/message_loop_unittest.cc
+++ b/base/message_loop/message_loop_unittest.cc
@@ -336,7 +336,7 @@
   WaitForSingleObject(event.Get(), INFINITE);
   MessageLoop::current()->Run();
 
-  ASSERT_EQ(order.Size(), 17);
+  ASSERT_EQ(17u, order.Size());
   EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
   EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
   EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
@@ -380,7 +380,7 @@
   WaitForSingleObject(event.Get(), INFINITE);
   MessageLoop::current()->Run();
 
-  ASSERT_EQ(order.Size(), 18);
+  ASSERT_EQ(18u, order.Size());
   EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
   EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
   EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
@@ -522,7 +522,7 @@
 
   DWORD read;
   EXPECT_FALSE(ReadFile(file_.Get(), buffer_, size(), &read, context()));
-  EXPECT_EQ(ERROR_IO_PENDING, GetLastError());
+  EXPECT_EQ(static_cast<DWORD>(ERROR_IO_PENDING), GetLastError());
   if (wait_)
     WaitForIO();
 }
@@ -615,8 +615,9 @@
   DWORD written;
   EXPECT_TRUE(WriteFile(server1.Get(), buffer, sizeof(buffer), &written, NULL));
   PlatformThread::Sleep(2 * delay);
-  EXPECT_EQ(WAIT_TIMEOUT, WaitForSingleObject(callback1_called.Get(), 0)) <<
-      "handler1 has not been called";
+  EXPECT_EQ(static_cast<DWORD>(WAIT_TIMEOUT),
+            WaitForSingleObject(callback1_called.Get(), 0))
+      << "handler1 has not been called";
 
   EXPECT_TRUE(WriteFile(server2.Get(), buffer, sizeof(buffer), &written, NULL));
 
diff --git a/base/posix/unix_domain_socket_linux.cc b/base/posix/unix_domain_socket_linux.cc
index 62c930fd..88a90f6 100644
--- a/base/posix/unix_domain_socket_linux.cc
+++ b/base/posix/unix_domain_socket_linux.cc
@@ -12,7 +12,6 @@
 
 #include "base/files/scoped_file.h"
 #include "base/logging.h"
-#include "base/memory/scoped_vector.h"
 #include "base/pickle.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/stl_util.h"
@@ -86,7 +85,7 @@
 ssize_t UnixDomainSocket::RecvMsg(int fd,
                                   void* buf,
                                   size_t length,
-                                  ScopedVector<ScopedFD>* fds) {
+                                  std::vector<ScopedFD>* fds) {
   return UnixDomainSocket::RecvMsgWithPid(fd, buf, length, fds, NULL);
 }
 
@@ -94,7 +93,7 @@
 ssize_t UnixDomainSocket::RecvMsgWithPid(int fd,
                                          void* buf,
                                          size_t length,
-                                         ScopedVector<ScopedFD>* fds,
+                                         std::vector<ScopedFD>* fds,
                                          ProcessId* pid) {
   return UnixDomainSocket::RecvMsgWithFlags(fd, buf, length, 0, fds, pid);
 }
@@ -104,7 +103,7 @@
                                            void* buf,
                                            size_t length,
                                            int flags,
-                                           ScopedVector<ScopedFD>* fds,
+                                           std::vector<ScopedFD>* fds,
                                            ProcessId* out_pid) {
   fds->clear();
 
@@ -165,7 +164,7 @@
 
   if (wire_fds) {
     for (unsigned i = 0; i < wire_fds_len; ++i)
-      fds->push_back(new ScopedFD(wire_fds[i]));
+      fds->push_back(ScopedFD(wire_fds[i]));  // TODO(mdempsky): emplace_back
   }
 
   if (out_pid) {
@@ -219,7 +218,7 @@
   // return EOF instead of hanging.
   send_sock.reset();
 
-  ScopedVector<ScopedFD> recv_fds;
+  std::vector<ScopedFD> recv_fds;
   // When porting to OSX keep in mind it doesn't support MSG_NOSIGNAL, so the
   // sender might get a SIGPIPE.
   const ssize_t reply_len = RecvMsgWithFlags(
@@ -236,7 +235,7 @@
   }
 
   if (result_fd)
-    *result_fd = recv_fds.empty() ? -1 : recv_fds[0]->release();
+    *result_fd = recv_fds.empty() ? -1 : recv_fds[0].release();
 
   return reply_len;
 }
diff --git a/base/posix/unix_domain_socket_linux.h b/base/posix/unix_domain_socket_linux.h
index 94da4b4..98c9d61 100644
--- a/base/posix/unix_domain_socket_linux.h
+++ b/base/posix/unix_domain_socket_linux.h
@@ -11,7 +11,6 @@
 
 #include "base/base_export.h"
 #include "base/files/scoped_file.h"
-#include "base/memory/scoped_vector.h"
 #include "base/process/process_handle.h"
 
 namespace base {
@@ -42,7 +41,7 @@
   static ssize_t RecvMsg(int fd,
                          void* msg,
                          size_t length,
-                         ScopedVector<ScopedFD>* fds);
+                         std::vector<ScopedFD>* fds);
 
   // Same as RecvMsg above, but also returns the sender's process ID (as seen
   // from the caller's namespace).  However, before using this function to
@@ -51,7 +50,7 @@
   static ssize_t RecvMsgWithPid(int fd,
                                 void* msg,
                                 size_t length,
-                                ScopedVector<ScopedFD>* fds,
+                                std::vector<ScopedFD>* fds,
                                 ProcessId* pid);
 
 #if !defined(OS_NACL_NONSFI)
@@ -94,7 +93,7 @@
                                   void* msg,
                                   size_t length,
                                   int flags,
-                                  ScopedVector<ScopedFD>* fds,
+                                  std::vector<ScopedFD>* fds,
                                   ProcessId* pid);
 };
 
diff --git a/base/posix/unix_domain_socket_linux_unittest.cc b/base/posix/unix_domain_socket_linux_unittest.cc
index 175ec52..c683e3a 100644
--- a/base/posix/unix_domain_socket_linux_unittest.cc
+++ b/base/posix/unix_domain_socket_linux_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
 #include "base/location.h"
-#include "base/memory/scoped_vector.h"
 #include "base/pickle.h"
 #include "base/posix/unix_domain_socket_linux.h"
 #include "base/single_thread_task_runner.h"
@@ -40,7 +39,7 @@
            static_cast<uint8_t*>(NULL), 0U, static_cast<int*>(NULL), request));
 
   // Receive the message.
-  ScopedVector<ScopedFD> message_fds;
+  std::vector<ScopedFD> message_fds;
   uint8_t buffer[16];
   ASSERT_EQ(static_cast<int>(request.size()),
             UnixDomainSocket::RecvMsg(fds[0], buffer, sizeof(buffer),
@@ -95,7 +94,7 @@
   // sizeof(kHello) bytes and it wasn't just truncated to fit the buffer.
   char buf[sizeof(kHello) + 1];
   ProcessId sender_pid;
-  ScopedVector<ScopedFD> fd_vec;
+  std::vector<ScopedFD> fd_vec;
   const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
       recv_sock.get(), buf, sizeof(buf), &fd_vec, &sender_pid);
   ASSERT_EQ(sizeof(kHello), static_cast<size_t>(nread));
@@ -124,7 +123,7 @@
   // sizeof(kHello) bytes and it wasn't just truncated to fit the buffer.
   char buf[sizeof(kHello) + 1];
   ProcessId sender_pid;
-  ScopedVector<ScopedFD> recv_fds;
+  std::vector<ScopedFD> recv_fds;
   const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
       recv_sock.get(), buf, sizeof(buf), &recv_fds, &sender_pid);
   ASSERT_EQ(sizeof(kHello), static_cast<size_t>(nread));
@@ -148,7 +147,7 @@
 
   char ch;
   ProcessId sender_pid;
-  ScopedVector<ScopedFD> recv_fds;
+  std::vector<ScopedFD> recv_fds;
   const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
       recv_sock.get(), &ch, sizeof(ch), &recv_fds, &sender_pid);
   ASSERT_EQ(0, nread);
diff --git a/base/process/process.h b/base/process/process.h
index 36f8574..38bdab7 100644
--- a/base/process/process.h
+++ b/base/process/process.h
@@ -123,6 +123,13 @@
   // of this value is OS dependent.
   int GetPriority() const;
 
+#if defined(OS_CHROMEOS)
+  // Get the PID in its PID namespace.
+  // If the process is not in a PID namespace or /proc/<pid>/status does not
+  // report NSpid, kNullProcessId is returned.
+  ProcessId GetPidInNamespace() const;
+#endif
+
  private:
 #if defined(OS_WIN)
   bool is_current_process_;
diff --git a/base/process/process_handle.h b/base/process/process_handle.h
index 0e667c8..ef7a602 100644
--- a/base/process/process_handle.h
+++ b/base/process/process_handle.h
@@ -68,12 +68,12 @@
 // processes.
 BASE_EXPORT ProcessId GetProcId(ProcessHandle process);
 
+// Returns the ID for the parent of the given process.
+BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process);
+
 #if defined(OS_POSIX)
 // Returns the path to the executable of the given process.
 BASE_EXPORT FilePath GetProcessExecutablePath(ProcessHandle process);
-
-// Returns the ID for the parent of the given process.
-BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process);
 #endif
 
 }  // namespace base
diff --git a/base/process/process_handle_win.cc b/base/process/process_handle_win.cc
index f2ffff8e8..7763f581 100644
--- a/base/process/process_handle_win.cc
+++ b/base/process/process_handle_win.cc
@@ -5,6 +5,7 @@
 #include "base/process/process_handle.h"
 
 #include <windows.h>
+#include <tlhelp32.h>
 
 #include "base/memory/scoped_ptr.h"
 #include "base/win/scoped_handle.h"
@@ -25,4 +26,20 @@
   return GetProcessId(process);
 }
 
+ProcessId GetParentProcessId(ProcessHandle process) {
+  ProcessId child_pid = GetProcId(process);
+  PROCESSENTRY32 process_entry;
+      process_entry.dwSize = sizeof(PROCESSENTRY32);
+
+  win::ScopedHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
+  if (snapshot.IsValid() && Process32First(snapshot.Get(), &process_entry)) {
+    do {
+      if (process_entry.th32ProcessID == child_pid)
+        return process_entry.th32ParentProcessID;
+    } while (Process32Next(snapshot.Get(), &process_entry));
+  }
+
+  return 0u;
+}
+
 }  // namespace base
diff --git a/base/process/process_linux.cc b/base/process/process_linux.cc
index 78000db..b8d8474 100644
--- a/base/process/process_linux.cc
+++ b/base/process/process_linux.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/lock.h"
+#include "base/threading/thread_restrictions.h"
 
 namespace base {
 
@@ -157,4 +158,44 @@
 }
 #endif  // defined(OS_CHROMEOS)
 
+#if defined(OS_CHROMEOS)
+// Reads /proc/<pid>/status and returns the PID in its PID namespace.
+// If the process is not in a PID namespace or /proc/<pid>/status does not
+// report NSpid, kNullProcessId is returned.
+ProcessId Process::GetPidInNamespace() const {
+  std::string status;
+  {
+    // Synchronously reading files in /proc does not hit the disk.
+    ThreadRestrictions::ScopedAllowIO allow_io;
+    FilePath status_file =
+        FilePath("/proc").Append(IntToString(process_)).Append("status");
+    if (!ReadFileToString(status_file, &status)) {
+      return kNullProcessId;
+    }
+  }
+
+  StringPairs pairs;
+  SplitStringIntoKeyValuePairs(status, ':', '\n', &pairs);
+  for (const auto& pair : pairs) {
+    const std::string& key = pair.first;
+    const std::string& value_str = pair.second;
+    if (key == "NSpid") {
+      std::vector<StringPiece> split_value_str = SplitStringPiece(
+          value_str, "\t", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+      if (split_value_str.size() <= 1) {
+        return kNullProcessId;
+      }
+      int value;
+      // The last value in the list is the PID in the namespace.
+      if (!StringToInt(split_value_str.back(), &value)) {
+        NOTREACHED();
+        return kNullProcessId;
+      }
+      return value;
+    }
+  }
+  return kNullProcessId;
+}
+#endif  // defined(OS_CHROMEOS)
+
 }  // namespace base
diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc
index 08144f2..140a65c 100644
--- a/base/process/process_util_unittest.cc
+++ b/base/process/process_util_unittest.cc
@@ -278,7 +278,7 @@
   EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_CRASHED, status);
 
 #if defined(OS_WIN)
-  EXPECT_EQ(0xc0000005, exit_code);
+  EXPECT_EQ(static_cast<int>(0xc0000005), exit_code);
 #elif defined(OS_POSIX)
   int signaled = WIFSIGNALED(exit_code);
   EXPECT_NE(0, signaled);
diff --git a/base/profiler/native_stack_sampler_win.cc b/base/profiler/native_stack_sampler_win.cc
index 87bb6ce..089b158 100644
--- a/base/profiler/native_stack_sampler_win.cc
+++ b/base/profiler/native_stack_sampler_win.cc
@@ -245,8 +245,8 @@
 
 ScopedSuspendThread::ScopedSuspendThread(HANDLE thread_handle)
     : thread_handle_(thread_handle),
-      was_successful_(::SuspendThread(thread_handle) != -1) {
-}
+      was_successful_(::SuspendThread(thread_handle) !=
+                      static_cast<DWORD>(-1)) {}
 
 ScopedSuspendThread::~ScopedSuspendThread() {
   if (!was_successful_)
@@ -263,7 +263,8 @@
   // before priority boost is reenabled. The measured length of this window is
   // ~100us, so this should occur fairly rarely.
   ScopedDisablePriorityBoost disable_priority_boost(thread_handle_);
-  bool resume_thread_succeeded = ::ResumeThread(thread_handle_) != -1;
+  bool resume_thread_succeeded =
+      ::ResumeThread(thread_handle_) != static_cast<DWORD>(-1);
   CHECK(resume_thread_succeeded) << "ResumeThread failed: " << GetLastError();
 }
 
diff --git a/base/rand_util.h b/base/rand_util.h
index 6130c129..e0fb91f 100644
--- a/base/rand_util.h
+++ b/base/rand_util.h
@@ -5,15 +5,17 @@
 #ifndef BASE_RAND_UTIL_H_
 #define BASE_RAND_UTIL_H_
 
+#include <stdint.h>
+
 #include <string>
 
 #include "base/base_export.h"
-#include "base/basictypes.h"
+#include "build/build_config.h"
 
 namespace base {
 
-// Returns a random number in range [0, kuint64max]. Thread-safe.
-BASE_EXPORT uint64 RandUint64();
+// Returns a random number in range [0, UINT64_MAX]. Thread-safe.
+BASE_EXPORT uint64_t RandUint64();
 
 // Returns a random number between min and max (inclusive). Thread-safe.
 BASE_EXPORT int RandInt(int min, int max);
@@ -23,14 +25,14 @@
 // Note that this can be used as an adapter for std::random_shuffle():
 // Given a pre-populated |std::vector<int> myvector|, shuffle it as
 //   std::random_shuffle(myvector.begin(), myvector.end(), base::RandGenerator);
-BASE_EXPORT uint64 RandGenerator(uint64 range);
+BASE_EXPORT uint64_t RandGenerator(uint64_t range);
 
 // Returns a random double in range [0, 1). Thread-safe.
 BASE_EXPORT double RandDouble();
 
 // Given input |bits|, convert with maximum precision to a double in
 // the range [0, 1). Thread-safe.
-BASE_EXPORT double BitsToOpenEndedUnitInterval(uint64 bits);
+BASE_EXPORT double BitsToOpenEndedUnitInterval(uint64_t bits);
 
 // Fills |output_length| bytes of |output| with random data.
 //
diff --git a/base/strings/utf_string_conversions_unittest.cc b/base/strings/utf_string_conversions_unittest.cc
index 97d8cbb..2d5eb41 100644
--- a/base/strings/utf_string_conversions_unittest.cc
+++ b/base/strings/utf_string_conversions_unittest.cc
@@ -139,13 +139,11 @@
     {L"\x597d\xd800", "\xe5\xa5\xbd\xef\xbf\xbd", false},
   };
 
-  for (int i = 0; i < arraysize(convert_cases); i++) {
+  for (const auto& test : convert_cases) {
     std::string converted;
-    EXPECT_EQ(convert_cases[i].success,
-              WideToUTF8(convert_cases[i].utf16,
-                         wcslen(convert_cases[i].utf16),
-                         &converted));
-    std::string expected(convert_cases[i].utf8);
+    EXPECT_EQ(test.success,
+              WideToUTF8(test.utf16, wcslen(test.utf16), &converted));
+    std::string expected(test.utf8);
     EXPECT_EQ(expected, converted);
   }
 }
@@ -172,13 +170,11 @@
     {L"\xdc01Hello", "\xef\xbf\xbdHello", false},
   };
 
-  for (size_t i = 0; i < arraysize(convert_cases); i++) {
+  for (const auto& test : convert_cases) {
     std::string converted;
-    EXPECT_EQ(convert_cases[i].success,
-              WideToUTF8(convert_cases[i].utf32,
-                         wcslen(convert_cases[i].utf32),
-                         &converted));
-    std::string expected(convert_cases[i].utf8);
+    EXPECT_EQ(test.success,
+              WideToUTF8(test.utf32, wcslen(test.utf32), &converted));
+    std::string expected(test.utf8);
     EXPECT_EQ(expected, converted);
   }
 }
diff --git a/base/sys_info.cc b/base/sys_info.cc
index ebc2a2e..21bfb34 100644
--- a/base/sys_info.cc
+++ b/base/sys_info.cc
@@ -59,7 +59,7 @@
   // This code relies on an implementation detail of TimeTicks::Now() - that
   // its return value happens to coincide with the system uptime value in
   // microseconds, on Win/Mac/iOS/Linux/ChromeOS and Android.
-  int64 uptime_in_microseconds = TimeTicks::Now().ToInternalValue();
+  int64_t uptime_in_microseconds = TimeTicks::Now().ToInternalValue();
   return base::TimeDelta::FromMicroseconds(uptime_in_microseconds);
 }
 
diff --git a/base/sys_info.h b/base/sys_info.h
index 67200ae..5777e09 100644
--- a/base/sys_info.h
+++ b/base/sys_info.h
@@ -5,11 +5,12 @@
 #ifndef BASE_SYS_INFO_H_
 #define BASE_SYS_INFO_H_
 
+#include <stdint.h>
+
 #include <map>
 #include <string>
 
 #include "base/base_export.h"
-#include "base/basictypes.h"
 #include "base/files/file_path.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
@@ -22,16 +23,16 @@
   static int NumberOfProcessors();
 
   // Return the number of bytes of physical memory on the current machine.
-  static int64 AmountOfPhysicalMemory();
+  static int64_t AmountOfPhysicalMemory();
 
   // Return the number of bytes of current available physical memory on the
   // machine.
-  static int64 AmountOfAvailablePhysicalMemory();
+  static int64_t AmountOfAvailablePhysicalMemory();
 
   // Return the number of bytes of virtual memory of this process. A return
   // value of zero means that there is no limit on the available virtual
   // memory.
-  static int64 AmountOfVirtualMemory();
+  static int64_t AmountOfVirtualMemory();
 
   // Return the number of megabytes of physical memory on the current machine.
   static int AmountOfPhysicalMemoryMB() {
@@ -46,7 +47,7 @@
 
   // Return the available disk space in bytes on the volume containing |path|,
   // or -1 on failure.
-  static int64 AmountOfFreeDiskSpace(const FilePath& path);
+  static int64_t AmountOfFreeDiskSpace(const FilePath& path);
 
   // Returns system uptime.
   static TimeDelta Uptime();
@@ -71,9 +72,9 @@
   // an OS version check instead of a feature check, use the base::mac::IsOS*
   // family from base/mac/mac_util.h, or base::win::GetVersion from
   // base/win/windows_version.h.
-  static void OperatingSystemVersionNumbers(int32* major_version,
-                                            int32* minor_version,
-                                            int32* bugfix_version);
+  static void OperatingSystemVersionNumbers(int32_t* major_version,
+                                            int32_t* minor_version,
+                                            int32_t* bugfix_version);
 
   // Returns the architecture of the running operating system.
   // Exact return value may differ across platforms.
@@ -94,7 +95,7 @@
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
   // Returns the maximum SysV shared memory segment size, or zero if there is no
   // limit.
-  static uint64 MaxSharedMemorySize();
+  static uint64_t MaxSharedMemorySize();
 #endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
 
 #if defined(OS_CHROMEOS)
diff --git a/base/sys_info_android.cc b/base/sys_info_android.cc
index 0eeb581..4b923d1 100644
--- a/base/sys_info_android.cc
+++ b/base/sys_info_android.cc
@@ -65,9 +65,9 @@
 
 // Parse out the OS version numbers from the system properties.
 void ParseOSVersionNumbers(const char* os_version_str,
-                           int32 *major_version,
-                           int32 *minor_version,
-                           int32 *bugfix_version) {
+                           int32_t* major_version,
+                           int32_t* minor_version,
+                           int32_t* bugfix_version) {
   if (os_version_str[0]) {
     // Try to parse out the version numbers from the string.
     int num_read = sscanf(os_version_str, "%d.%d.%d", major_version,
@@ -90,13 +90,13 @@
 // Parses a system property (specified with unit 'k','m' or 'g').
 // Returns a value in bytes.
 // Returns -1 if the string could not be parsed.
-int64 ParseSystemPropertyBytes(const base::StringPiece& str) {
-  const int64 KB = 1024;
-  const int64 MB = 1024 * KB;
-  const int64 GB = 1024 * MB;
+int64_t ParseSystemPropertyBytes(const base::StringPiece& str) {
+  const int64_t KB = 1024;
+  const int64_t MB = 1024 * KB;
+  const int64_t GB = 1024 * MB;
   if (str.size() == 0u)
     return -1;
-  int64 unit_multiplier = 1;
+  int64_t unit_multiplier = 1;
   size_t length = str.size();
   if (str[length - 1] == 'k') {
     unit_multiplier = KB;
@@ -108,10 +108,11 @@
     unit_multiplier = GB;
     length--;
   }
-  int64 result = 0;
+  int64_t result = 0;
   bool parsed = base::StringToInt64(str.substr(0, length), &result);
   bool negative = result <= 0;
-  bool overflow = result >= std::numeric_limits<int64>::max() / unit_multiplier;
+  bool overflow =
+      result >= std::numeric_limits<int64_t>::max() / unit_multiplier;
   if (!parsed || negative || overflow)
     return -1;
   return result * unit_multiplier;
@@ -123,14 +124,15 @@
   // dalvik.vm.heapsize property is writable by a root user.
   // Clamp it to reasonable range as a sanity check,
   // a typical android device will never have less than 48MB.
-  const int64 MB = 1024 * 1024;
-  int64 result = ParseSystemPropertyBytes(heap_size_str);
+  const int64_t MB = 1024 * 1024;
+  int64_t result = ParseSystemPropertyBytes(heap_size_str);
   if (result == -1) {
      // We should consider not exposing these values if they are not reliable.
      LOG(ERROR) << "Can't parse dalvik.vm.heapsize: " << heap_size_str;
      result = base::SysInfo::AmountOfPhysicalMemoryMB() / 3;
   }
-  result = std::min<int64>(std::max<int64>(32 * MB, result), 1024 * MB) / MB;
+  result =
+      std::min<int64_t>(std::max<int64_t>(32 * MB, result), 1024 * MB) / MB;
   return static_cast<int>(result);
 }
 
@@ -140,14 +142,14 @@
   // dalvik.vm.heapgrowthlimit property is writable by a root user.
   // Clamp it to reasonable range as a sanity check,
   // a typical android device will never have less than 24MB.
-  const int64 MB = 1024 * 1024;
-  int64 result = ParseSystemPropertyBytes(heap_size_str);
+  const int64_t MB = 1024 * 1024;
+  int64_t result = ParseSystemPropertyBytes(heap_size_str);
   if (result == -1) {
      // We should consider not exposing these values if they are not reliable.
      LOG(ERROR) << "Can't parse dalvik.vm.heapgrowthlimit: " << heap_size_str;
      result = base::SysInfo::AmountOfPhysicalMemoryMB() / 6;
   }
-  result = std::min<int64>(std::max<int64>(16 * MB, result), 512 * MB) / MB;
+  result = std::min<int64_t>(std::max<int64_t>(16 * MB, result), 512 * MB) / MB;
   return static_cast<int>(result);
 }
 
@@ -166,14 +168,14 @@
 }
 
 std::string SysInfo::OperatingSystemVersion() {
-  int32 major, minor, bugfix;
+  int32_t major, minor, bugfix;
   OperatingSystemVersionNumbers(&major, &minor, &bugfix);
   return StringPrintf("%d.%d.%d", major, minor, bugfix);
 }
 
-void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
-                                            int32* minor_version,
-                                            int32* bugfix_version) {
+void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
+                                            int32_t* minor_version,
+                                            int32_t* bugfix_version) {
   // Read the version number string out from the properties.
   char os_version_str[PROP_VALUE_MAX];
   __system_property_get("ro.build.version.release", os_version_str);
diff --git a/base/sys_info_chromeos.cc b/base/sys_info_chromeos.cc
index 9915055..9d33e56 100644
--- a/base/sys_info_chromeos.cc
+++ b/base/sys_info_chromeos.cc
@@ -4,7 +4,6 @@
 
 #include "base/sys_info.h"
 
-#include "base/basictypes.h"
 #include "base/environment.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
@@ -90,9 +89,9 @@
     return true;
   }
 
-  void GetVersionNumbers(int32* major_version,
-                         int32* minor_version,
-                         int32* bugfix_version) {
+  void GetVersionNumbers(int32_t* major_version,
+                         int32_t* minor_version,
+                         int32_t* bugfix_version) {
     *major_version = major_version_;
     *minor_version = minor_version_;
     *bugfix_version = bugfix_version_;
@@ -154,9 +153,9 @@
 
   Time lsb_release_time_;
   SysInfo::LsbReleaseMap lsb_release_map_;
-  int32 major_version_;
-  int32 minor_version_;
-  int32 bugfix_version_;
+  int32_t major_version_;
+  int32_t minor_version_;
+  int32_t bugfix_version_;
   bool is_running_on_chromeos_;
 };
 
@@ -170,9 +169,9 @@
 }  // namespace
 
 // static
-void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
-                                            int32* minor_version,
-                                            int32* bugfix_version) {
+void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
+                                            int32_t* minor_version,
+                                            int32_t* bugfix_version) {
   return GetChromeOSVersionInfo().GetVersionNumbers(
       major_version, minor_version, bugfix_version);
 }
diff --git a/base/sys_info_freebsd.cc b/base/sys_info_freebsd.cc
index 515b59d..bc175ed 100644
--- a/base/sys_info_freebsd.cc
+++ b/base/sys_info_freebsd.cc
@@ -10,7 +10,7 @@
 
 namespace base {
 
-int64 SysInfo::AmountOfPhysicalMemory() {
+int64_t SysInfo::AmountOfPhysicalMemory() {
   int pages, page_size;
   size_t size = sizeof(pages);
   sysctlbyname("vm.stats.vm.v_page_count", &pages, &size, NULL, 0);
@@ -19,18 +19,18 @@
     NOTREACHED();
     return 0;
   }
-  return static_cast<int64>(pages) * page_size;
+  return static_cast<int64_t>(pages) * page_size;
 }
 
 // static
-uint64 SysInfo::MaxSharedMemorySize() {
+uint64_t SysInfo::MaxSharedMemorySize() {
   size_t limit;
   size_t size = sizeof(limit);
   if (sysctlbyname("kern.ipc.shmmax", &limit, &size, NULL, 0) < 0) {
     NOTREACHED();
     return 0;
   }
-  return static_cast<uint64>(limit);
+  return static_cast<uint64_t>(limit);
 }
 
 }  // namespace base
diff --git a/base/sys_info_internal.h b/base/sys_info_internal.h
index e7674d5..636a384c 100644
--- a/base/sys_info_internal.h
+++ b/base/sys_info_internal.h
@@ -5,8 +5,6 @@
 #ifndef BASE_SYS_INFO_INTERNAL_H_
 #define BASE_SYS_INFO_INTERNAL_H_
 
-#include "base/basictypes.h"
-
 namespace base {
 
 namespace internal {
diff --git a/base/sys_info_ios.mm b/base/sys_info_ios.mm
index 5aa31809..56e7b55 100644
--- a/base/sys_info_ios.mm
+++ b/base/sys_info_ios.mm
@@ -43,9 +43,9 @@
 }
 
 // static
-void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
-                                            int32* minor_version,
-                                            int32* bugfix_version) {
+void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
+                                            int32_t* minor_version,
+                                            int32_t* bugfix_version) {
   base::mac::ScopedNSAutoreleasePool pool;
   std::string system_version = OperatingSystemVersion();
   if (!system_version.empty()) {
@@ -62,7 +62,7 @@
 }
 
 // static
-int64 SysInfo::AmountOfPhysicalMemory() {
+int64_t SysInfo::AmountOfPhysicalMemory() {
   struct host_basic_info hostinfo;
   mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
   base::mac::ScopedMachSendRight host(mach_host_self());
@@ -75,11 +75,11 @@
     return 0;
   }
   DCHECK_EQ(HOST_BASIC_INFO_COUNT, count);
-  return static_cast<int64>(hostinfo.max_mem);
+  return static_cast<int64_t>(hostinfo.max_mem);
 }
 
 // static
-int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+int64_t SysInfo::AmountOfAvailablePhysicalMemory() {
   base::mac::ScopedMachSendRight host(mach_host_self());
   vm_statistics_data_t vm_info;
   mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
@@ -91,8 +91,8 @@
     return 0;
   }
 
-  return static_cast<int64>(
-      vm_info.free_count - vm_info.speculative_count) * PAGE_SIZE;
+  return static_cast<int64_t>(vm_info.free_count - vm_info.speculative_count) *
+         PAGE_SIZE;
 }
 
 // static
diff --git a/base/sys_info_linux.cc b/base/sys_info_linux.cc
index 1bbfe9c6..8ee967f 100644
--- a/base/sys_info_linux.cc
+++ b/base/sys_info_linux.cc
@@ -15,21 +15,21 @@
 
 namespace {
 
-int64 AmountOfMemory(int pages_name) {
+int64_t AmountOfMemory(int pages_name) {
   long pages = sysconf(pages_name);
   long page_size = sysconf(_SC_PAGESIZE);
   if (pages == -1 || page_size == -1) {
     NOTREACHED();
     return 0;
   }
-  return static_cast<int64>(pages) * page_size;
+  return static_cast<int64_t>(pages) * page_size;
 }
 
-int64 AmountOfPhysicalMemory() {
+int64_t AmountOfPhysicalMemory() {
   return AmountOfMemory(_SC_PHYS_PAGES);
 }
 
-uint64 MaxSharedMemorySize() {
+uint64_t MaxSharedMemorySize() {
   std::string contents;
   base::ReadFileToString(base::FilePath("/proc/sys/kernel/shmmax"), &contents);
   DCHECK(!contents.empty());
@@ -37,7 +37,7 @@
     contents.erase(contents.length() - 1);
   }
 
-  uint64 limit;
+  uint64_t limit;
   if (!base::StringToUint64(contents, &limit)) {
     limit = 0;
   }
@@ -46,10 +46,10 @@
 }
 
 base::LazyInstance<
-    base::internal::LazySysInfoValue<int64, AmountOfPhysicalMemory> >::Leaky
+    base::internal::LazySysInfoValue<int64_t, AmountOfPhysicalMemory>>::Leaky
     g_lazy_physical_memory = LAZY_INSTANCE_INITIALIZER;
 base::LazyInstance<
-    base::internal::LazySysInfoValue<uint64, MaxSharedMemorySize> >::Leaky
+    base::internal::LazySysInfoValue<uint64_t, MaxSharedMemorySize>>::Leaky
     g_lazy_max_shared_memory = LAZY_INSTANCE_INITIALIZER;
 
 }  // namespace
@@ -57,17 +57,17 @@
 namespace base {
 
 // static
-int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+int64_t SysInfo::AmountOfAvailablePhysicalMemory() {
   return AmountOfMemory(_SC_AVPHYS_PAGES);
 }
 
 // static
-int64 SysInfo::AmountOfPhysicalMemory() {
+int64_t SysInfo::AmountOfPhysicalMemory() {
   return g_lazy_physical_memory.Get().value();
 }
 
 // static
-uint64 SysInfo::MaxSharedMemorySize() {
+uint64_t SysInfo::MaxSharedMemorySize() {
   return g_lazy_max_shared_memory.Get().value();
 }
 
diff --git a/base/sys_info_mac.cc b/base/sys_info_mac.cc
index 025c768..919a66fd 100644
--- a/base/sys_info_mac.cc
+++ b/base/sys_info_mac.cc
@@ -24,15 +24,15 @@
 
 // static
 std::string SysInfo::OperatingSystemVersion() {
-  int32 major, minor, bugfix;
+  int32_t major, minor, bugfix;
   OperatingSystemVersionNumbers(&major, &minor, &bugfix);
   return base::StringPrintf("%d.%d.%d", major, minor, bugfix);
 }
 
 // static
-void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
-                                            int32* minor_version,
-                                            int32* bugfix_version) {
+void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
+                                            int32_t* minor_version,
+                                            int32_t* bugfix_version) {
   Gestalt(gestaltSystemVersionMajor,
       reinterpret_cast<SInt32*>(major_version));
   Gestalt(gestaltSystemVersionMinor,
@@ -42,7 +42,7 @@
 }
 
 // static
-int64 SysInfo::AmountOfPhysicalMemory() {
+int64_t SysInfo::AmountOfPhysicalMemory() {
   struct host_basic_info hostinfo;
   mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
   base::mac::ScopedMachSendRight host(mach_host_self());
@@ -55,11 +55,11 @@
     return 0;
   }
   DCHECK_EQ(HOST_BASIC_INFO_COUNT, count);
-  return static_cast<int64>(hostinfo.max_mem);
+  return static_cast<int64_t>(hostinfo.max_mem);
 }
 
 // static
-int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+int64_t SysInfo::AmountOfAvailablePhysicalMemory() {
   base::mac::ScopedMachSendRight host(mach_host_self());
   vm_statistics_data_t vm_info;
   mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
@@ -72,8 +72,8 @@
     return 0;
   }
 
-  return static_cast<int64>(
-      vm_info.free_count - vm_info.speculative_count) * PAGE_SIZE;
+  return static_cast<int64_t>(vm_info.free_count - vm_info.speculative_count) *
+         PAGE_SIZE;
 }
 
 // static
diff --git a/base/sys_info_openbsd.cc b/base/sys_info_openbsd.cc
index 595291b..506b836 100644
--- a/base/sys_info_openbsd.cc
+++ b/base/sys_info_openbsd.cc
@@ -12,14 +12,14 @@
 
 namespace {
 
-int64 AmountOfMemory(int pages_name) {
+int64_t AmountOfMemory(int pages_name) {
   long pages = sysconf(pages_name);
   long page_size = sysconf(_SC_PAGESIZE);
   if (pages == -1 || page_size == -1) {
     NOTREACHED();
     return 0;
   }
-  return static_cast<int64>(pages) * page_size;
+  return static_cast<int64_t>(pages) * page_size;
 }
 
 }  // namespace
@@ -39,17 +39,17 @@
 }
 
 // static
-int64 SysInfo::AmountOfPhysicalMemory() {
+int64_t SysInfo::AmountOfPhysicalMemory() {
   return AmountOfMemory(_SC_PHYS_PAGES);
 }
 
 // static
-int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+int64_t SysInfo::AmountOfAvailablePhysicalMemory() {
   return AmountOfMemory(_SC_AVPHYS_PAGES);
 }
 
 // static
-uint64 SysInfo::MaxSharedMemorySize() {
+uint64_t SysInfo::MaxSharedMemorySize() {
   int mib[] = { CTL_KERN, KERN_SHMINFO, KERN_SHMINFO_SHMMAX };
   size_t limit;
   size_t size = sizeof(limit);
@@ -57,7 +57,7 @@
     NOTREACHED();
     return 0;
   }
-  return static_cast<uint64>(limit);
+  return static_cast<uint64_t>(limit);
 }
 
 // static
diff --git a/base/sys_info_posix.cc b/base/sys_info_posix.cc
index 3d49bf9..407134d 100644
--- a/base/sys_info_posix.cc
+++ b/base/sys_info_posix.cc
@@ -11,7 +11,6 @@
 #include <sys/utsname.h>
 #include <unistd.h>
 
-#include "base/basictypes.h"
 #include "base/files/file_util.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
@@ -57,7 +56,7 @@
     g_lazy_number_of_processors = LAZY_INSTANCE_INITIALIZER;
 #endif
 
-int64 AmountOfVirtualMemory() {
+int64_t AmountOfVirtualMemory() {
   struct rlimit limit;
   int result = getrlimit(RLIMIT_DATA, &limit);
   if (result != 0) {
@@ -68,7 +67,7 @@
 }
 
 base::LazyInstance<
-    base::internal::LazySysInfoValue<int64, AmountOfVirtualMemory> >::Leaky
+    base::internal::LazySysInfoValue<int64_t, AmountOfVirtualMemory>>::Leaky
     g_lazy_virtual_memory = LAZY_INSTANCE_INITIALIZER;
 
 }  // namespace
@@ -82,18 +81,18 @@
 #endif
 
 // static
-int64 SysInfo::AmountOfVirtualMemory() {
+int64_t SysInfo::AmountOfVirtualMemory() {
   return g_lazy_virtual_memory.Get().value();
 }
 
 // static
-int64 SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
+int64_t SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
   base::ThreadRestrictions::AssertIOAllowed();
 
   struct statvfs stats;
   if (HANDLE_EINTR(statvfs(path.value().c_str(), &stats)) != 0)
     return -1;
-  return static_cast<int64>(stats.f_bavail) * stats.f_frsize;
+  return static_cast<int64_t>(stats.f_bavail) * stats.f_frsize;
 }
 
 #if !defined(OS_MACOSX) && !defined(OS_ANDROID)
diff --git a/base/sys_info_unittest.cc b/base/sys_info_unittest.cc
index 127d930..2a54226 100644
--- a/base/sys_info_unittest.cc
+++ b/base/sys_info_unittest.cc
@@ -43,9 +43,9 @@
 
 #if defined(OS_WIN) || defined(OS_MACOSX)
 TEST_F(SysInfoTest, OperatingSystemVersionNumbers) {
-  int32 os_major_version = -1;
-  int32 os_minor_version = -1;
-  int32 os_bugfix_version = -1;
+  int32_t os_major_version = -1;
+  int32_t os_minor_version = -1;
+  int32_t os_bugfix_version = -1;
   base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
                                                &os_minor_version,
                                                &os_bugfix_version);
@@ -75,9 +75,9 @@
 #if defined(OS_CHROMEOS)
 
 TEST_F(SysInfoTest, GoogleChromeOSVersionNumbers) {
-  int32 os_major_version = -1;
-  int32 os_minor_version = -1;
-  int32 os_bugfix_version = -1;
+  int32_t os_major_version = -1;
+  int32_t os_minor_version = -1;
+  int32_t os_bugfix_version = -1;
   const char kLsbRelease[] =
       "FOO=1234123.34.5\n"
       "CHROMEOS_RELEASE_VERSION=1.2.3.4\n";
@@ -91,9 +91,9 @@
 }
 
 TEST_F(SysInfoTest, GoogleChromeOSVersionNumbersFirst) {
-  int32 os_major_version = -1;
-  int32 os_minor_version = -1;
-  int32 os_bugfix_version = -1;
+  int32_t os_major_version = -1;
+  int32_t os_minor_version = -1;
+  int32_t os_bugfix_version = -1;
   const char kLsbRelease[] =
       "CHROMEOS_RELEASE_VERSION=1.2.3.4\n"
       "FOO=1234123.34.5\n";
@@ -107,9 +107,9 @@
 }
 
 TEST_F(SysInfoTest, GoogleChromeOSNoVersionNumbers) {
-  int32 os_major_version = -1;
-  int32 os_minor_version = -1;
-  int32 os_bugfix_version = -1;
+  int32_t os_major_version = -1;
+  int32_t os_minor_version = -1;
+  int32_t os_bugfix_version = -1;
   const char kLsbRelease[] = "FOO=1234123.34.5\n";
   base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
   base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
diff --git a/base/sys_info_win.cc b/base/sys_info_win.cc
index 4eccbd7..3bd1d5c3 100644
--- a/base/sys_info_win.cc
+++ b/base/sys_info_win.cc
@@ -6,6 +6,8 @@
 
 #include <windows.h>
 
+#include <limits>
+
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
@@ -15,7 +17,7 @@
 
 namespace {
 
-int64 AmountOfMemory(DWORDLONG MEMORYSTATUSEX::* memory_field) {
+int64_t AmountOfMemory(DWORDLONG MEMORYSTATUSEX::*memory_field) {
   MEMORYSTATUSEX memory_info;
   memory_info.dwLength = sizeof(memory_info);
   if (!GlobalMemoryStatusEx(&memory_info)) {
@@ -23,8 +25,8 @@
     return 0;
   }
 
-  int64 rv = static_cast<int64>(memory_info.*memory_field);
-  return rv < 0 ? kint64max : rv;
+  int64_t rv = static_cast<int64_t>(memory_info.*memory_field);
+  return rv < 0 ? std::numeric_limits<int64_t>::max() : rv;
 }
 
 }  // namespace
@@ -37,30 +39,30 @@
 }
 
 // static
-int64 SysInfo::AmountOfPhysicalMemory() {
+int64_t SysInfo::AmountOfPhysicalMemory() {
   return AmountOfMemory(&MEMORYSTATUSEX::ullTotalPhys);
 }
 
 // static
-int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+int64_t SysInfo::AmountOfAvailablePhysicalMemory() {
   return AmountOfMemory(&MEMORYSTATUSEX::ullAvailPhys);
 }
 
 // static
-int64 SysInfo::AmountOfVirtualMemory() {
+int64_t SysInfo::AmountOfVirtualMemory() {
   return AmountOfMemory(&MEMORYSTATUSEX::ullTotalVirtual);
 }
 
 // static
-int64 SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
+int64_t SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
   ThreadRestrictions::AssertIOAllowed();
 
   ULARGE_INTEGER available, total, free;
   if (!GetDiskFreeSpaceExW(path.value().c_str(), &available, &total, &free))
     return -1;
 
-  int64 rv = static_cast<int64>(available.QuadPart);
-  return rv < 0 ? kint64max : rv;
+  int64_t rv = static_cast<int64_t>(available.QuadPart);
+  return rv < 0 ? std::numeric_limits<int64_t>::max() : rv;
 }
 
 std::string SysInfo::OperatingSystemName() {
@@ -113,9 +115,9 @@
 }
 
 // static
-void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
-                                            int32* minor_version,
-                                            int32* bugfix_version) {
+void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
+                                            int32_t* minor_version,
+                                            int32_t* bugfix_version) {
   win::OSInfo* os_info = win::OSInfo::GetInstance();
   *major_version = os_info->version_number().major;
   *minor_version = os_info->version_number().minor;
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java b/base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java
index b1feef5d..fa8c0a0 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java
@@ -13,7 +13,7 @@
  */
 public class ScalableTimeout {
     private static Double sTimeoutScale = null;
-    private static final String PROPERTY_FILE = "/data/local/tmp/chrome_timeout_scale";
+    public static final String PROPERTY_FILE = "/data/local/tmp/chrome_timeout_scale";
 
     @SuppressFBWarnings("DMI_HARDCODED_ABSOLUTE_FILENAME")
     public static long scaleTimeout(long timeout) {
diff --git a/base/test/test_reg_util_win_unittest.cc b/base/test/test_reg_util_win_unittest.cc
index 216d58ea..c38baa3 100644
--- a/base/test/test_reg_util_win_unittest.cc
+++ b/base/test/test_reg_util_win_unittest.cc
@@ -89,7 +89,7 @@
             read_key.Open(HKEY_CURRENT_USER, kTestKeyPath, KEY_READ));
   EXPECT_TRUE(read_key.Valid());
   EXPECT_EQ(ERROR_SUCCESS, read_key.ReadValueDW(kTestValueName, &value));
-  EXPECT_EQ(42, value);
+  EXPECT_EQ(42u, value);
   read_key.Close();
 
   manager_.reset();
diff --git a/base/threading/thread_local_storage.cc b/base/threading/thread_local_storage.cc
index 701f6a2..ffa236f0 100644
--- a/base/threading/thread_local_storage.cc
+++ b/base/threading/thread_local_storage.cc
@@ -76,8 +76,10 @@
     // TLS_KEY_OUT_OF_INDEXES, go ahead and set it.  Otherwise, do nothing, as
     // another thread already did our dirty work.
     if (PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES !=
-        base::subtle::NoBarrier_CompareAndSwap(&g_native_tls_key,
-            PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES, key)) {
+        static_cast<PlatformThreadLocalStorage::TLSKey>(
+            base::subtle::NoBarrier_CompareAndSwap(
+                &g_native_tls_key,
+                PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES, key))) {
       // We've been shortcut. Another thread replaced g_native_tls_key first so
       // we need to destroy our index and use the one the other thread got
       // first.
diff --git a/base/threading/thread_local_storage.h b/base/threading/thread_local_storage.h
index 195bff68..fa79eda 100644
--- a/base/threading/thread_local_storage.h
+++ b/base/threading/thread_local_storage.h
@@ -27,7 +27,7 @@
 
 #if defined(OS_WIN)
   typedef unsigned long TLSKey;
-  enum { TLS_KEY_OUT_OF_INDEXES = TLS_OUT_OF_INDEXES };
+  enum : unsigned { TLS_KEY_OUT_OF_INDEXES = TLS_OUT_OF_INDEXES };
 #elif defined(OS_POSIX)
   typedef pthread_key_t TLSKey;
   // The following is a "reserved key" which is used in our generic Chromium
diff --git a/base/time/time_win_unittest.cc b/base/time/time_win_unittest.cc
index baaa322..e2bb893 100644
--- a/base/time/time_win_unittest.cc
+++ b/base/time/time_win_unittest.cc
@@ -150,11 +150,7 @@
 
   TIMECAPS caps;
   MMRESULT status = timeGetDevCaps(&caps, sizeof(caps));
-  EXPECT_EQ(TIMERR_NOERROR, status);
-  if (status != TIMERR_NOERROR) {
-    printf("Could not get timeGetDevCaps\n");
-    return;
-  }
+  ASSERT_EQ(static_cast<MMRESULT>(MMSYSERR_NOERROR), status);
 
   EXPECT_GE(static_cast<int>(caps.wPeriodMin), 1);
   EXPECT_GT(static_cast<int>(caps.wPeriodMax), 1);
diff --git a/base/trace_event/trace_event_etw_export_win.cc b/base/trace_event/trace_event_etw_export_win.cc
index 6822eff6..934c624 100644
--- a/base/trace_event/trace_event_etw_export_win.cc
+++ b/base/trace_event/trace_event_etw_export_win.cc
@@ -177,7 +177,7 @@
   // modifications will be made by the background thread and only affect the
   // values of the keys (no key addition/deletion). Therefore, the map does not
   // require a lock for access.
-  for (int i = 0; i < ARRAYSIZE(kFilteredEventGroupNames); i++)
+  for (size_t i = 0; i < ARRAYSIZE(kFilteredEventGroupNames); i++)
     categories_status_[kFilteredEventGroupNames[i]] = false;
   categories_status_[kOtherEventsGroupName] = false;
   categories_status_[kDisabledOtherEventsGroupName] = false;
@@ -376,7 +376,7 @@
   // recording tools) using the ETW infrastructure. This value will be set in
   // all Chrome processes that have registered their ETW provider.
   etw_match_any_keyword_ = CHROME_Context.MatchAnyKeyword;
-  for (int i = 0; i < ARRAYSIZE(kFilteredEventGroupNames); i++) {
+  for (size_t i = 0; i < ARRAYSIZE(kFilteredEventGroupNames); i++) {
     if (etw_match_any_keyword_ & (1ULL << i)) {
       categories_status_[kFilteredEventGroupNames[i]] = true;
     } else {
diff --git a/base/win/enum_variant_unittest.cc b/base/win/enum_variant_unittest.cc
index 99645a2..288c97e 100644
--- a/base/win/enum_variant_unittest.cc
+++ b/base/win/enum_variant_unittest.cc
@@ -31,7 +31,7 @@
   VARIANT out_element;
   ULONG out_received = 0;
   EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
-  EXPECT_EQ(0, out_received);
+  EXPECT_EQ(0u, out_received);
 
   EXPECT_EQ(S_FALSE, ev->Skip(1));
 
@@ -46,10 +46,10 @@
   EXPECT_EQ(S_OK, ev2->Reset());
 
   ULONG ev2_finalrefcount = ev2->Release();
-  EXPECT_EQ(0, ev2_finalrefcount);
+  EXPECT_EQ(0u, ev2_finalrefcount);
 
   ULONG ev_finalrefcount = ev->Release();
-  EXPECT_EQ(0, ev_finalrefcount);
+  EXPECT_EQ(0u, ev_finalrefcount);
 }
 
 TEST(EnumVariantTest, SimpleEnumVariant) {
@@ -68,12 +68,12 @@
   VARIANT out_element;
   ULONG out_received = 0;
   EXPECT_EQ(S_OK, ev->Next(1, &out_element, &out_received));
-  EXPECT_EQ(1, out_received);
+  EXPECT_EQ(1u, out_received);
   EXPECT_EQ(VT_I4, out_element.vt);
   EXPECT_EQ(10, out_element.lVal);
   EXPECT_EQ(S_OK, ev->Skip(1));
   EXPECT_EQ(S_OK, ev->Next(1, &out_element, &out_received));
-  EXPECT_EQ(1, out_received);
+  EXPECT_EQ(1u, out_received);
   EXPECT_EQ(VT_I4, out_element.vt);
   EXPECT_EQ(30, out_element.lVal);
   EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
@@ -82,7 +82,7 @@
   VARIANT out_elements[3];
   EXPECT_EQ(S_OK, ev->Reset());
   EXPECT_EQ(S_OK, ev->Next(3, out_elements, &out_received));
-  EXPECT_EQ(3, out_received);
+  EXPECT_EQ(3u, out_received);
   EXPECT_EQ(VT_I4, out_elements[0].vt);
   EXPECT_EQ(10, out_elements[0].lVal);
   EXPECT_EQ(VT_I4, out_elements[1].vt);
@@ -98,7 +98,7 @@
   EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
   EXPECT_EQ(S_OK, ev2->Reset());
   EXPECT_EQ(S_OK, ev2->Next(3, out_elements, &out_received));
-  EXPECT_EQ(3, out_received);
+  EXPECT_EQ(3u, out_received);
   EXPECT_EQ(VT_I4, out_elements[0].vt);
   EXPECT_EQ(10, out_elements[0].lVal);
   EXPECT_EQ(VT_I4, out_elements[1].vt);
@@ -108,10 +108,10 @@
   EXPECT_EQ(S_FALSE, ev2->Next(1, &out_element, &out_received));
 
   ULONG ev2_finalrefcount = ev2->Release();
-  EXPECT_EQ(0, ev2_finalrefcount);
+  EXPECT_EQ(0u, ev2_finalrefcount);
 
   ULONG ev_finalrefcount = ev->Release();
-  EXPECT_EQ(0, ev_finalrefcount);
+  EXPECT_EQ(0u, ev_finalrefcount);
 }
 
 }  // namespace win
diff --git a/base/win/event_trace_consumer_unittest.cc b/base/win/event_trace_consumer_unittest.cc
index ecbf238..b159b93 100644
--- a/base/win/event_trace_consumer_unittest.cc
+++ b/base/win/event_trace_consumer_unittest.cc
@@ -209,7 +209,8 @@
   ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
 
   // Wait around for the consumer_ thread a bit.
-  ASSERT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(consumer_thread_.Get(), 50));
+  ASSERT_EQ(static_cast<DWORD>(WAIT_TIMEOUT),
+            ::WaitForSingleObject(consumer_thread_.Get(), 50));
   ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL));
 
   // The consumer_ returns success on session stop.
@@ -237,14 +238,14 @@
       test_provider_, TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
 
   EtwTraceProvider provider(test_provider_);
-  ASSERT_EQ(ERROR_SUCCESS, provider.Register());
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Register());
 
   // Start the consumer_.
   ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
-  ASSERT_EQ(0, TestConsumer::events_.size());
+  ASSERT_EQ(0u, TestConsumer::events_.size());
 
   EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR);
-  EXPECT_EQ(ERROR_SUCCESS, provider.Log(&event.header));
+  EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Log(&event.header));
   EXPECT_EQ(WAIT_OBJECT_0,
             ::WaitForSingleObject(TestConsumer::sank_event_.Get(), INFINITE));
   ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL));
@@ -294,9 +295,9 @@
 
     EtwTraceProvider provider(test_provider_);
     // Then register our provider, means we get a session handle immediately.
-    EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+    EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Register());
     // Trace the event, it goes to the temp file.
-    EXPECT_EQ(ERROR_SUCCESS, provider.Log(header));
+    EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Log(header));
     EXPECT_HRESULT_SUCCEEDED(controller.DisableProvider(test_provider_));
     EXPECT_HRESULT_SUCCEEDED(provider.Unregister());
     EXPECT_HRESULT_SUCCEEDED(controller.Flush(NULL));
diff --git a/base/win/event_trace_controller_unittest.cc b/base/win/event_trace_controller_unittest.cc
index c947ed7..c128253 100644
--- a/base/win/event_trace_controller_unittest.cc
+++ b/base/win/event_trace_controller_unittest.cc
@@ -62,25 +62,25 @@
   EXPECT_EQ(0u, p->Wnode.HistoricalContext);
 
   EXPECT_TRUE(kGuidNull == p->Wnode.Guid);
-  EXPECT_EQ(0, p->Wnode.ClientContext);
-  EXPECT_EQ(WNODE_FLAG_TRACED_GUID, p->Wnode.Flags);
+  EXPECT_EQ(0u, p->Wnode.ClientContext);
+  EXPECT_EQ(static_cast<ULONG>(WNODE_FLAG_TRACED_GUID), p->Wnode.Flags);
 
-  EXPECT_EQ(0, p->BufferSize);
-  EXPECT_EQ(0, p->MinimumBuffers);
-  EXPECT_EQ(0, p->MaximumBuffers);
-  EXPECT_EQ(0, p->MaximumFileSize);
-  EXPECT_EQ(0, p->LogFileMode);
-  EXPECT_EQ(0, p->FlushTimer);
-  EXPECT_EQ(0, p->EnableFlags);
+  EXPECT_EQ(0u, p->BufferSize);
+  EXPECT_EQ(0u, p->MinimumBuffers);
+  EXPECT_EQ(0u, p->MaximumBuffers);
+  EXPECT_EQ(0u, p->MaximumFileSize);
+  EXPECT_EQ(0u, p->LogFileMode);
+  EXPECT_EQ(0u, p->FlushTimer);
+  EXPECT_EQ(0u, p->EnableFlags);
   EXPECT_EQ(0, p->AgeLimit);
 
-  EXPECT_EQ(0, p->NumberOfBuffers);
-  EXPECT_EQ(0, p->FreeBuffers);
-  EXPECT_EQ(0, p->EventsLost);
-  EXPECT_EQ(0, p->BuffersWritten);
-  EXPECT_EQ(0, p->LogBuffersLost);
-  EXPECT_EQ(0, p->RealTimeBuffersLost);
-  EXPECT_EQ(0, p->LoggerThreadId);
+  EXPECT_EQ(0u, p->NumberOfBuffers);
+  EXPECT_EQ(0u, p->FreeBuffers);
+  EXPECT_EQ(0u, p->EventsLost);
+  EXPECT_EQ(0u, p->BuffersWritten);
+  EXPECT_EQ(0u, p->LogBuffersLost);
+  EXPECT_EQ(0u, p->RealTimeBuffersLost);
+  EXPECT_EQ(0u, p->LoggerThreadId);
   EXPECT_NE(0u, p->LogFileNameOffset);
   EXPECT_NE(0u, p->LoggerNameOffset);
 }
@@ -133,7 +133,7 @@
 TEST_F(EtwTraceControllerTest, Initialize) {
   EtwTraceController controller;
 
-  EXPECT_EQ(NULL, controller.session());
+  EXPECT_EQ(0u, controller.session());
   EXPECT_STREQ(L"", controller.session_name());
 }
 
@@ -148,11 +148,11 @@
     return;
   }
 
-  EXPECT_TRUE(NULL != controller.session());
+  EXPECT_NE(0u, controller.session());
   EXPECT_STREQ(session_name_.c_str(), controller.session_name());
 
   EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
-  EXPECT_EQ(NULL, controller.session());
+  EXPECT_EQ(0u, controller.session());
   EXPECT_STREQ(L"", controller.session_name());
 }
 
@@ -171,11 +171,11 @@
     return;
   }
 
-  EXPECT_TRUE(NULL != controller.session());
+  EXPECT_NE(0u, controller.session());
   EXPECT_STREQ(session_name_.c_str(), controller.session_name());
 
   EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
-  EXPECT_EQ(NULL, controller.session());
+  EXPECT_EQ(0u, controller.session());
   EXPECT_STREQ(L"", controller.session_name());
   base::DeleteFile(temp, false);
 }
@@ -184,8 +184,8 @@
 TEST_F(EtwTraceControllerTest, DISABLED_EnableDisable) {
   TestingProvider provider(test_provider_);
 
-  EXPECT_EQ(ERROR_SUCCESS, provider.Register());
-  EXPECT_EQ(NULL, provider.session_handle());
+  EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Register());
+  EXPECT_EQ(0u, provider.session_handle());
 
   EtwTraceController controller;
   HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(),
@@ -208,9 +208,9 @@
   provider.WaitForCallback();
 
   EXPECT_EQ(0, provider.enable_level());
-  EXPECT_EQ(0, provider.enable_flags());
+  EXPECT_EQ(0u, provider.enable_flags());
 
-  EXPECT_EQ(ERROR_SUCCESS, provider.Unregister());
+  EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Unregister());
 
   // Enable the provider again, before registering.
   EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_,
@@ -218,7 +218,7 @@
 
   // Register the provider again, the settings above
   // should take immediate effect.
-  EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+  EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Register());
 
   EXPECT_EQ(TRACE_LEVEL_VERBOSE, provider.enable_level());
   EXPECT_EQ(kTestProviderFlags, provider.enable_flags());
@@ -235,7 +235,7 @@
 
     // Session should have wound down.
     EXPECT_EQ(0, provider.enable_level());
-    EXPECT_EQ(0, provider.enable_flags());
+    EXPECT_EQ(0u, provider.enable_flags());
   }
 }
 
diff --git a/base/win/event_trace_provider.h b/base/win/event_trace_provider.h
index a87cb9c1..0775faf 100644
--- a/base/win/event_trace_provider.h
+++ b/base/win/event_trace_provider.h
@@ -67,7 +67,7 @@
     header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
   }
 
-  void SetField(int field, size_t size, const void *data) {
+  void SetField(size_t field, size_t size, const void* data) {
     // DCHECK(field < N);
     if ((field < N) && (size <= std::numeric_limits<uint32_t>::max())) {
       fields[field].DataPtr = reinterpret_cast<ULONG64>(data);
diff --git a/base/win/event_trace_provider_unittest.cc b/base/win/event_trace_provider_unittest.cc
index 55b5ae6a..7d57773 100644
--- a/base/win/event_trace_provider_unittest.cc
+++ b/base/win/event_trace_provider_unittest.cc
@@ -31,10 +31,10 @@
   char buf[sizeof(EtwTraceProvider)] = {0};
   EtwTraceProvider& provider = reinterpret_cast<EtwTraceProvider&>(buf);
 
-  EXPECT_EQ(NULL, provider.registration_handle());
-  EXPECT_EQ(NULL, provider.session_handle());
-  EXPECT_EQ(0, provider.enable_flags());
-  EXPECT_EQ(0, provider.enable_level());
+  EXPECT_EQ(0u, provider.registration_handle());
+  EXPECT_EQ(0u, provider.session_handle());
+  EXPECT_EQ(0u, provider.enable_flags());
+  EXPECT_EQ(0u, provider.enable_level());
 
   EXPECT_FALSE(provider.ShouldLog(TRACE_LEVEL_FATAL, 0xfffffff));
 
@@ -51,16 +51,16 @@
   new (buf) EtwTraceProvider(kTestProvider);
 
   // Registration is now safe.
-  EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+  EXPECT_EQ(static_cast<ULONG>(ERROR_SUCCESS), provider.Register());
 
   // Destruct the instance, this should unregister it.
   provider.EtwTraceProvider::~EtwTraceProvider();
 
   // And post-destruction, all of the above should still be safe.
-  EXPECT_EQ(NULL, provider.registration_handle());
-  EXPECT_EQ(NULL, provider.session_handle());
-  EXPECT_EQ(0, provider.enable_flags());
-  EXPECT_EQ(0, provider.enable_level());
+  EXPECT_EQ(0u, provider.registration_handle());
+  EXPECT_EQ(0u, provider.session_handle());
+  EXPECT_EQ(0u, provider.enable_flags());
+  EXPECT_EQ(0u, provider.enable_level());
 
   EXPECT_FALSE(provider.ShouldLog(TRACE_LEVEL_FATAL, 0xfffffff));
 
@@ -73,19 +73,19 @@
 TEST(EtwTraceProviderTest, Initialize) {
   EtwTraceProvider provider(kTestProvider);
 
-  EXPECT_EQ(NULL, provider.registration_handle());
-  EXPECT_EQ(NULL, provider.session_handle());
-  EXPECT_EQ(0, provider.enable_flags());
-  EXPECT_EQ(0, provider.enable_level());
+  EXPECT_EQ(0u, provider.registration_handle());
+  EXPECT_EQ(0u, provider.session_handle());
+  EXPECT_EQ(0u, provider.enable_flags());
+  EXPECT_EQ(0u, provider.enable_level());
 }
 
 TEST(EtwTraceProviderTest, Register) {
   EtwTraceProvider provider(kTestProvider);
 
-  ASSERT_EQ(ERROR_SUCCESS, provider.Register());
-  EXPECT_NE(NULL, provider.registration_handle());
-  ASSERT_EQ(ERROR_SUCCESS, provider.Unregister());
-  EXPECT_EQ(NULL, provider.registration_handle());
+  ASSERT_EQ(static_cast<ULONG>(ERROR_SUCCESS), provider.Register());
+  EXPECT_NE(0u, provider.registration_handle());
+  ASSERT_EQ(static_cast<ULONG>(ERROR_SUCCESS), provider.Unregister());
+  EXPECT_EQ(0u, provider.registration_handle());
 }
 
 TEST(EtwTraceProviderTest, RegisterWithNoNameFails) {
@@ -97,14 +97,14 @@
 TEST(EtwTraceProviderTest, Enable) {
   EtwTraceProvider provider(kTestProvider);
 
-  ASSERT_EQ(ERROR_SUCCESS, provider.Register());
-  EXPECT_NE(NULL, provider.registration_handle());
+  ASSERT_EQ(static_cast<ULONG>(ERROR_SUCCESS), provider.Register());
+  EXPECT_NE(0u, provider.registration_handle());
 
   // No session so far.
-  EXPECT_EQ(NULL, provider.session_handle());
-  EXPECT_EQ(0, provider.enable_flags());
-  EXPECT_EQ(0, provider.enable_level());
+  EXPECT_EQ(0u, provider.session_handle());
+  EXPECT_EQ(0u, provider.enable_flags());
+  EXPECT_EQ(0u, provider.enable_level());
 
-  ASSERT_EQ(ERROR_SUCCESS, provider.Unregister());
-  EXPECT_EQ(NULL, provider.registration_handle());
+  ASSERT_EQ(static_cast<ULONG>(ERROR_SUCCESS), provider.Unregister());
+  EXPECT_EQ(0u, provider.registration_handle());
 }
diff --git a/base/win/iunknown_impl_unittest.cc b/base/win/iunknown_impl_unittest.cc
index 874a43a..c6c35390 100644
--- a/base/win/iunknown_impl_unittest.cc
+++ b/base/win/iunknown_impl_unittest.cc
@@ -30,8 +30,8 @@
 
   EXPECT_EQ(1, TestIUnknownImplSubclass::instance_count);
 
-  EXPECT_EQ(1, u->AddRef());
-  EXPECT_EQ(1, u->AddRef());
+  EXPECT_EQ(1u, u->AddRef());
+  EXPECT_EQ(1u, u->AddRef());
 
   IUnknown* other = NULL;
   EXPECT_EQ(E_NOINTERFACE, u->QueryInterface(
@@ -40,8 +40,8 @@
       IID_IUnknown, reinterpret_cast<void**>(&other)));
   other->Release();
 
-  EXPECT_EQ(1, u->Release());
-  EXPECT_EQ(0, u->Release());
+  EXPECT_EQ(1u, u->Release());
+  EXPECT_EQ(0u, u->Release());
   EXPECT_EQ(0, TestIUnknownImplSubclass::instance_count);
 }
 
diff --git a/base/win/registry_unittest.cc b/base/win/registry_unittest.cc
index 2257663..0b87023c 100644
--- a/base/win/registry_unittest.cc
+++ b/base/win/registry_unittest.cc
@@ -167,7 +167,7 @@
   const wchar_t kName[] = L"name";
   // kData size is not a multiple of sizeof(wchar_t).
   const uint8 kData[] = { 1, 2, 3, 4, 5 };
-  EXPECT_EQ(5, arraysize(kData));
+  EXPECT_EQ(5u, arraysize(kData));
   ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kName, kData,
                                           arraysize(kData), REG_BINARY));
 
diff --git a/base/win/scoped_bstr_unittest.cc b/base/win/scoped_bstr_unittest.cc
index 5f6f7df..9a289ff 100644
--- a/base/win/scoped_bstr_unittest.cc
+++ b/base/win/scoped_bstr_unittest.cc
@@ -18,8 +18,8 @@
 void DumbBstrTests() {
   ScopedBstr b;
   EXPECT_TRUE(b == NULL);
-  EXPECT_EQ(0, b.Length());
-  EXPECT_EQ(0, b.ByteLength());
+  EXPECT_EQ(0u, b.Length());
+  EXPECT_EQ(0u, b.ByteLength());
   b.Reset(NULL);
   EXPECT_TRUE(b == NULL);
   EXPECT_TRUE(b.Release() == NULL);
@@ -40,7 +40,7 @@
   ScopedBstr b2;
   b1.Swap(b2);
   EXPECT_EQ(test1_len, b2.Length());
-  EXPECT_EQ(0, b1.Length());
+  EXPECT_EQ(0u, b1.Length());
   EXPECT_EQ(0, lstrcmp(b2, kTestString1));
   BSTR tmp = b2.Release();
   EXPECT_TRUE(tmp != NULL);
@@ -52,13 +52,13 @@
   EXPECT_TRUE(b2 != NULL);
   b2.Reset();
   EXPECT_TRUE(b2.AllocateBytes(100) != NULL);
-  EXPECT_EQ(100, b2.ByteLength());
+  EXPECT_EQ(100u, b2.ByteLength());
   EXPECT_EQ(100 / sizeof(kTestString1[0]), b2.Length());
   lstrcpy(static_cast<BSTR>(b2), kTestString1);
-  EXPECT_EQ(test1_len, lstrlen(b2));
+  EXPECT_EQ(test1_len, static_cast<size_t>(lstrlen(b2)));
   EXPECT_EQ(100 / sizeof(kTestString1[0]), b2.Length());
   b2.SetByteLen(lstrlen(b2) * sizeof(kTestString2[0]));
-  EXPECT_EQ(b2.Length(), lstrlen(b2));
+  EXPECT_EQ(b2.Length(), static_cast<size_t>(lstrlen(b2)));
 
   EXPECT_TRUE(b1.Allocate(kTestString2) != NULL);
   EXPECT_EQ(test2_len, b1.Length());
diff --git a/base/win/scoped_process_information_unittest.cc b/base/win/scoped_process_information_unittest.cc
index 614504d4..799b273 100644
--- a/base/win/scoped_process_information_unittest.cc
+++ b/base/win/scoped_process_information_unittest.cc
@@ -80,7 +80,7 @@
   HANDLE process = process_info.TakeProcessHandle();
   EXPECT_EQ(kProcessHandle, process);
   EXPECT_EQ(NULL, process_info.process_handle());
-  EXPECT_EQ(0, process_info.process_id());
+  EXPECT_EQ(0u, process_info.process_id());
   EXPECT_TRUE(process_info.IsValid());
   process_info.Take();
 }
@@ -92,7 +92,7 @@
   HANDLE thread = process_info.TakeThreadHandle();
   EXPECT_EQ(kThreadHandle, thread);
   EXPECT_EQ(NULL, process_info.thread_handle());
-  EXPECT_EQ(0, process_info.thread_id());
+  EXPECT_EQ(0u, process_info.thread_id());
   EXPECT_TRUE(process_info.IsValid());
   process_info.Take();
 }
diff --git a/base/win/scoped_variant_unittest.cc b/base/win/scoped_variant_unittest.cc
index d530d5b..48f08bb6 100644
--- a/base/win/scoped_variant_unittest.cc
+++ b/base/win/scoped_variant_unittest.cc
@@ -144,19 +144,19 @@
 
   var.Set(static_cast<uint8>(123));
   EXPECT_EQ(VT_UI1, var.type());
-  EXPECT_EQ(123, V_UI1(var.ptr()));
+  EXPECT_EQ(123u, V_UI1(var.ptr()));
 
   var.Set(static_cast<unsigned short>(123));
   EXPECT_EQ(VT_UI2, var.type());
-  EXPECT_EQ(123, V_UI2(var.ptr()));
+  EXPECT_EQ(123u, V_UI2(var.ptr()));
 
   var.Set(static_cast<uint32>(123));
   EXPECT_EQ(VT_UI4, var.type());
-  EXPECT_EQ(123, V_UI4(var.ptr()));
+  EXPECT_EQ(123u, V_UI4(var.ptr()));
 
   var.Set(static_cast<uint64>(123));
   EXPECT_EQ(VT_UI8, var.type());
-  EXPECT_EQ(123, V_UI8(var.ptr()));
+  EXPECT_EQ(123u, V_UI8(var.ptr()));
 
   var.Set(123.123f);
   EXPECT_EQ(VT_R4, var.type());
diff --git a/base/win/startup_information.h b/base/win/startup_information.h
index 3f18ee5..66c287f 100644
--- a/base/win/startup_information.h
+++ b/base/win/startup_information.h
@@ -31,7 +31,7 @@
                                  size_t size);
 
   LPSTARTUPINFOW startup_info() { return &startup_info_.StartupInfo; }
-  const LPSTARTUPINFOW startup_info() const {
+  LPSTARTUPINFOW startup_info() const {
     return const_cast<const LPSTARTUPINFOW>(&startup_info_.StartupInfo);
   }
 
diff --git a/base/win/win_util.h b/base/win/win_util.h
index 384db805..c1249d91 100644
--- a/base/win/win_util.h
+++ b/base/win/win_util.h
@@ -56,6 +56,14 @@
 namespace base {
 namespace win {
 
+inline uint32_t HandleToUint32(HANDLE h) {
+  // Cast through uintptr_t and then unsigned int to make the truncation to
+  // 32 bits explicit. Handles are size of-pointer but are always 32-bit values.
+  // https://msdn.microsoft.com/en-us/library/aa384203(VS.85).aspx says:
+  // 64-bit versions of Windows use 32-bit handles for interoperability.
+  return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(h));
+}
+
 BASE_EXPORT void GetNonClientMetrics(NONCLIENTMETRICS_XP* metrics);
 
 // Returns the string representing the current user sid.
diff --git a/blimp/client/BUILD.gn b/blimp/client/BUILD.gn
index 48f647b..3858bd3e 100644
--- a/blimp/client/BUILD.gn
+++ b/blimp/client/BUILD.gn
@@ -18,16 +18,28 @@
     "compositor/blimp_layer_tree_settings.h",
     "compositor/blimp_output_surface.cc",
     "compositor/blimp_output_surface.h",
-    "compositor/render_widget_message_processor.cc",
-    "compositor/render_widget_message_processor.h",
     "compositor/test/dummy_layer_driver.cc",
     "compositor/test/dummy_layer_driver.h",
-    "navigation_message_processor.cc",
-    "navigation_message_processor.h",
+    "input/blimp_input_handler_wrapper.cc",
+    "input/blimp_input_handler_wrapper.h",
+    "input/blimp_input_manager.cc",
+    "input/blimp_input_manager.h",
+    "session/blimp_client_session.cc",
+    "session/blimp_client_session.h",
+    "session/navigation_feature.cc",
+    "session/navigation_feature.h",
+    "session/render_widget_feature.cc",
+    "session/render_widget_feature.h",
+    "session/tab_control_feature.cc",
+    "session/tab_control_feature.h",
   ]
 
   defines = [ "BLIMP_CLIENT_IMPLEMENTATION=1" ]
 
+  public_deps = [
+    "//ui/events",
+  ]
+
   deps = [
     "//base",
     "//blimp/common:blimp_common",
@@ -38,6 +50,8 @@
     "//gpu/command_buffer/client:gl_in_process_context",
     "//gpu/command_buffer/common:gles2_utils",
     "//gpu/skia_bindings",
+    "//ui/events/blink",
+    "//ui/events/gestures/blink",
     "//ui/gfx/geometry",
     "//ui/gl",
     "//url:url",
@@ -48,8 +62,9 @@
   testonly = true
 
   sources = [
-    "compositor/render_widget_message_processor_unittest.cc",
-    "navigation_message_processor_unittest.cc",
+    "session/navigation_feature_unittest.cc",
+    "session/render_widget_feature_unittest.cc",
+    "session/tab_control_feature_unittest.cc",
   ]
 
   deps = [
@@ -92,6 +107,8 @@
     sources = [
       "android/java/src/org/chromium/blimp/BlimpLibraryLoader.java",
       "android/java/src/org/chromium/blimp/BlimpView.java",
+      "android/java/src/org/chromium/blimp/session/BlimpClientSession.java",
+      "android/java/src/org/chromium/blimp/session/TabControlFeature.java",
       "android/java/src/org/chromium/blimp/toolbar/Toolbar.java",
     ]
 
@@ -175,6 +192,8 @@
       "android/java/src/org/chromium/blimp/BlimpLibraryLoader.java",
       "android/java/src/org/chromium/blimp/BlimpRendererActivity.java",
       "android/java/src/org/chromium/blimp/BlimpView.java",
+      "android/java/src/org/chromium/blimp/session/BlimpClientSession.java",
+      "android/java/src/org/chromium/blimp/session/TabControlFeature.java",
       "android/java/src/org/chromium/blimp/toolbar/Toolbar.java",
       "android/java/src/org/chromium/blimp/toolbar/UrlBar.java",
     ]
@@ -220,6 +239,10 @@
       "android/toolbar.h",
       "compositor/blimp_compositor_android.cc",
       "compositor/blimp_compositor_android.h",
+      "session/blimp_client_session_android.cc",
+      "session/blimp_client_session_android.h",
+      "session/tab_control_feature_android.cc",
+      "session/tab_control_feature_android.h",
     ]
 
     libs = [ "android" ]
diff --git a/blimp/client/DEPS b/blimp/client/DEPS
index 1240c91a..19da9c3 100644
--- a/blimp/client/DEPS
+++ b/blimp/client/DEPS
@@ -9,6 +9,11 @@
   "+net/base",
   "+skia",
   "+third_party/skia",
+  "+third_party/WebKit/public/web/WebInputEvent.h",
+  "+ui/events/android",
+  "+ui/events/blink",
+  "+ui/events/gesture_detection",
+  "+ui/events/gestures/blink",
   "+ui/gfx",
   "+ui/gl",
   "+url",
diff --git a/blimp/client/android/blimp_jni_registrar.cc b/blimp/client/android/blimp_jni_registrar.cc
index 0bdd121..185a5f3 100644
--- a/blimp/client/android/blimp_jni_registrar.cc
+++ b/blimp/client/android/blimp_jni_registrar.cc
@@ -8,6 +8,8 @@
 #include "blimp/client/android/blimp_library_loader.h"
 #include "blimp/client/android/blimp_view.h"
 #include "blimp/client/android/toolbar.h"
+#include "blimp/client/session/blimp_client_session_android.h"
+#include "blimp/client/session/tab_control_feature_android.h"
 
 namespace {
 
@@ -15,6 +17,9 @@
     {"BlimpLibraryLoader", blimp::RegisterBlimpLibraryLoaderJni},
     {"Toolbar", blimp::Toolbar::RegisterJni},
     {"BlimpView", blimp::BlimpView::RegisterJni},
+    {"BlimpClientSessionAndroid",
+     blimp::BlimpClientSessionAndroid::RegisterJni},
+    {"TabControlFeatureAndroid", blimp::TabControlFeatureAndroid::RegisterJni},
 };
 
 }  // namespace
diff --git a/blimp/client/android/blimp_view.cc b/blimp/client/android/blimp_view.cc
index cec7e3a6..3fdbe260 100644
--- a/blimp/client/android/blimp_view.cc
+++ b/blimp/client/android/blimp_view.cc
@@ -7,22 +7,32 @@
 #include <android/native_window_jni.h>
 
 #include "blimp/client/compositor/blimp_compositor_android.h"
+#include "blimp/client/session/blimp_client_session_android.h"
 #include "jni/BlimpView_jni.h"
+#include "ui/events/android/motion_event_android.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace blimp {
 
-// static
 static jlong Init(JNIEnv* env,
                   const JavaParamRef<jobject>& jobj,
+                  const JavaParamRef<jobject>& blimp_client_session,
                   jint real_width,
                   jint real_height,
                   jint width,
                   jint height,
                   jfloat dp_to_px) {
-  return reinterpret_cast<intptr_t>(
-      new BlimpView(env, jobj, gfx::Size(real_width, real_height),
-                    gfx::Size(width, height), dp_to_px));
+  BlimpClientSession* client_session =
+      BlimpClientSessionAndroid::FromJavaObject(env,
+                                                blimp_client_session.obj());
+
+  // TODO(dtrainor): Pull the feature object from the BlimpClientSession and
+  // pass it through to the BlimpCompositor.
+  ALLOW_UNUSED_LOCAL(client_session);
+
+  return reinterpret_cast<intptr_t>(new BlimpView(
+      env, jobj, gfx::Size(real_width, real_height), gfx::Size(width, height),
+      dp_to_px, client_session->GetRenderWidgetFeature()));
 }
 
 // static
@@ -34,8 +44,13 @@
                      const JavaParamRef<jobject>& jobj,
                      const gfx::Size& real_size,
                      const gfx::Size& size,
-                     float dp_to_px)
-    : compositor_(BlimpCompositorAndroid::Create(real_size, size, dp_to_px)),
+                     float dp_to_px,
+                     RenderWidgetFeature* render_widget_feature)
+    : device_scale_factor_(dp_to_px),
+      compositor_(BlimpCompositorAndroid::Create(real_size,
+                                                 size,
+                                                 dp_to_px,
+                                                 render_widget_feature)),
       current_surface_format_(0),
       window_(gfx::kNullAcceleratedWidget) {
   java_obj_.Reset(env, jobj);
@@ -94,4 +109,66 @@
   window_ = gfx::kNullAcceleratedWidget;
 }
 
+jboolean BlimpView::OnTouchEvent(JNIEnv* env,
+                             jobject obj,
+                             jobject motion_event,
+                             jlong time_ms,
+                             jint android_action,
+                             jint pointer_count,
+                             jint history_size,
+                             jint action_index,
+                             jfloat pos_x_0,
+                             jfloat pos_y_0,
+                             jfloat pos_x_1,
+                             jfloat pos_y_1,
+                             jint pointer_id_0,
+                             jint pointer_id_1,
+                             jfloat touch_major_0,
+                             jfloat touch_major_1,
+                             jfloat touch_minor_0,
+                             jfloat touch_minor_1,
+                             jfloat orientation_0,
+                             jfloat orientation_1,
+                             jfloat tilt_0,
+                             jfloat tilt_1,
+                             jfloat raw_pos_x,
+                             jfloat raw_pos_y,
+                             jint android_tool_type_0,
+                             jint android_tool_type_1,
+                             jint android_button_state,
+                             jint android_meta_state) {
+  ui::MotionEventAndroid::Pointer pointer0(pointer_id_0,
+                                           pos_x_0,
+                                           pos_y_0,
+                                           touch_major_0,
+                                           touch_minor_0,
+                                           orientation_0,
+                                           tilt_0,
+                                           android_tool_type_0);
+  ui::MotionEventAndroid::Pointer pointer1(pointer_id_1,
+                                           pos_x_1,
+                                           pos_y_1,
+                                           touch_major_1,
+                                           touch_minor_1,
+                                           orientation_1,
+                                           tilt_1,
+                                           android_tool_type_1);
+  ui::MotionEventAndroid event(1.f / device_scale_factor_,
+                               env,
+                               motion_event,
+                               time_ms,
+                               android_action,
+                               pointer_count,
+                               history_size,
+                               action_index,
+                               android_button_state,
+                               android_meta_state,
+                               raw_pos_x - pos_x_0,
+                               raw_pos_y - pos_y_0,
+                               pointer0,
+                               pointer1);
+
+  return compositor_->OnTouchEvent(event);
+}
+
 }  // namespace blimp
diff --git a/blimp/client/android/blimp_view.h b/blimp/client/android/blimp_view.h
index 97dc3ed..748199d 100644
--- a/blimp/client/android/blimp_view.h
+++ b/blimp/client/android/blimp_view.h
@@ -17,6 +17,7 @@
 namespace blimp {
 
 class BlimpCompositorAndroid;
+class RenderWidgetFeature;
 
 // The native component of org.chromium.blimp.BlimpView.  This builds and
 // maintains a BlimpCompositorAndroid and handles notifying the compositor of
@@ -34,7 +35,8 @@
             const base::android::JavaParamRef<jobject>& jobj,
             const gfx::Size& real_size,
             const gfx::Size& size,
-            float dp_to_px);
+            float dp_to_px,
+            RenderWidgetFeature* render_widget_feature);
 
   // Methods called from Java via JNI.
   void Destroy(JNIEnv* env, jobject jobj);
@@ -48,6 +50,34 @@
   void OnSurfaceCreated(JNIEnv* env, jobject jobj);
   void OnSurfaceDestroyed(JNIEnv* env, jobject jobj);
   void SetVisibility(JNIEnv* env, jobject jobj, jboolean visible);
+  jboolean OnTouchEvent(JNIEnv* env,
+                        jobject obj,
+                        jobject motion_event,
+                        jlong time_ms,
+                        jint android_action,
+                        jint pointer_count,
+                        jint history_size,
+                        jint action_index,
+                        jfloat pos_x_0,
+                        jfloat pos_y_0,
+                        jfloat pos_x_1,
+                        jfloat pos_y_1,
+                        jint pointer_id_0,
+                        jint pointer_id_1,
+                        jfloat touch_major_0,
+                        jfloat touch_major_1,
+                        jfloat touch_minor_0,
+                        jfloat touch_minor_1,
+                        jfloat orientation_0,
+                        jfloat orientation_1,
+                        jfloat tilt_0,
+                        jfloat tilt_1,
+                        jfloat raw_pos_x,
+                        jfloat raw_pos_y,
+                        jint android_tool_type_0,
+                        jint android_tool_type_1,
+                        jint android_button_state,
+                        jint android_meta_state);
 
  private:
   virtual ~BlimpView();
@@ -57,6 +87,8 @@
   // Reference to the Java object which owns this class.
   base::android::ScopedJavaGlobalRef<jobject> java_obj_;
 
+  const float device_scale_factor_;
+
   scoped_ptr<BlimpCompositorAndroid> compositor_;
 
   // The format of the current surface owned by |compositor_|.  See
diff --git a/blimp/client/android/java/src/org/chromium/blimp/BlimpRendererActivity.java b/blimp/client/android/java/src/org/chromium/blimp/BlimpRendererActivity.java
index da2501104..6641c39 100644
--- a/blimp/client/android/java/src/org/chromium/blimp/BlimpRendererActivity.java
+++ b/blimp/client/android/java/src/org/chromium/blimp/BlimpRendererActivity.java
@@ -13,6 +13,8 @@
 import org.chromium.blimp.auth.RetryingTokenSource;
 import org.chromium.blimp.auth.TokenSource;
 import org.chromium.blimp.auth.TokenSourceImpl;
+import org.chromium.blimp.session.BlimpClientSession;
+import org.chromium.blimp.session.TabControlFeature;
 import org.chromium.blimp.toolbar.Toolbar;
 import org.chromium.ui.widget.Toast;
 
@@ -28,6 +30,8 @@
     private TokenSource mTokenSource;
     private BlimpView mBlimpView;
     private Toolbar mToolbar;
+    private BlimpClientSession mBlimpClientSession;
+    private TabControlFeature mTabControlFeature;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -48,6 +52,11 @@
 
     @Override
     protected void onDestroy() {
+        if (mTabControlFeature != null) {
+            mTabControlFeature.destroy();
+            mTabControlFeature = null;
+        }
+
         if (mBlimpView != null) {
             mBlimpView.destroyRenderer();
             mBlimpView = null;
@@ -63,6 +72,12 @@
             mTokenSource = null;
         }
 
+        // Destroy the BlimpClientSession last, as all other features may rely on it.
+        if (mBlimpClientSession != null) {
+            mBlimpClientSession.destroy();
+            mBlimpClientSession = null;
+        }
+
         super.onDestroy();
     }
 
@@ -100,11 +115,15 @@
 
         setContentView(R.layout.blimp_main);
 
+        mBlimpClientSession = new BlimpClientSession();
+
         mBlimpView = (BlimpView) findViewById(R.id.renderer);
-        mBlimpView.initializeRenderer();
+        mBlimpView.initializeRenderer(mBlimpClientSession);
 
         mToolbar = (Toolbar) findViewById(R.id.toolbar);
-        mToolbar.initialize();
+        mToolbar.initialize(mBlimpClientSession);
+
+        mTabControlFeature = new TabControlFeature(mBlimpClientSession, mBlimpView);
     }
 
     // TokenSource.Callback implementation.
diff --git a/blimp/client/android/java/src/org/chromium/blimp/BlimpView.java b/blimp/client/android/java/src/org/chromium/blimp/BlimpView.java
index a902680..c8b586b 100644
--- a/blimp/client/android/java/src/org/chromium/blimp/BlimpView.java
+++ b/blimp/client/android/java/src/org/chromium/blimp/BlimpView.java
@@ -8,12 +8,14 @@
 import android.graphics.Point;
 import android.os.Build;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.WindowManager;
 
 import org.chromium.base.annotations.JNINamespace;
+import org.chromium.blimp.session.BlimpClientSession;
 
 /**
  * A {@link View} that will visually represent the Blimp rendered content.  This {@link View} starts
@@ -37,8 +39,10 @@
     /**
      * Starts up rendering for this {@link View}.  This will start up the native compositor and will
      * display it's contents.
+     * @param blimpClientSession The {@link BlimpClientSession} that contains the content-lite
+     *                           features required by the native components of the compositor.
      */
-    public void initializeRenderer() {
+    public void initializeRenderer(BlimpClientSession blimpClientSession) {
         assert mNativeBlimpViewPtr == 0;
 
         WindowManager windowManager =
@@ -51,8 +55,8 @@
         }
         // TODO(dtrainor): Change 1.f to dpToPx once native fully supports dp.
         float compositorDensity = 1.f;
-        mNativeBlimpViewPtr = nativeInit(
-                physicalSize.x, physicalSize.y, displaySize.x, displaySize.y, compositorDensity);
+        mNativeBlimpViewPtr = nativeInit(blimpClientSession, physicalSize.x, physicalSize.y,
+                displaySize.x, displaySize.y, compositorDensity);
         getHolder().addCallback(this);
         setVisibility(VISIBLE);
     }
@@ -86,6 +90,37 @@
         nativeSetVisibility(mNativeBlimpViewPtr, visible);
     }
 
+    // View overrides.
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (mNativeBlimpViewPtr == 0) return false;
+
+        int eventAction = event.getActionMasked();
+
+        if (!isValidTouchEventActionForNative(eventAction)) return false;
+
+        int pointerCount = event.getPointerCount();
+        boolean consumed = nativeOnTouchEvent(mNativeBlimpViewPtr, event,
+                event.getEventTime(), eventAction,
+                pointerCount, event.getHistorySize(), event.getActionIndex(),
+                event.getX(), event.getY(),
+                pointerCount > 1 ? event.getX(1) : 0,
+                pointerCount > 1 ? event.getY(1) : 0,
+                event.getPointerId(0), pointerCount > 1 ? event.getPointerId(1) : -1,
+                event.getTouchMajor(), pointerCount > 1 ? event.getTouchMajor(1) : 0,
+                event.getTouchMinor(), pointerCount > 1 ? event.getTouchMinor(1) : 0,
+                event.getOrientation(), pointerCount > 1 ? event.getOrientation(1) : 0,
+                event.getAxisValue(MotionEvent.AXIS_TILT),
+                pointerCount > 1 ? event.getAxisValue(MotionEvent.AXIS_TILT, 1) : 0,
+                event.getRawX(), event.getRawY(),
+                event.getToolType(0),
+                pointerCount > 1 ? event.getToolType(1) : MotionEvent.TOOL_TYPE_UNKNOWN,
+                event.getButtonState(),
+                event.getMetaState());
+
+        return consumed;
+    }
+
     // SurfaceView overrides.
     @Override
     protected void onFinishInflate() {
@@ -117,9 +152,21 @@
     @Override
     public void surfaceRedrawNeeded(SurfaceHolder holder) {}
 
+    private static boolean isValidTouchEventActionForNative(int eventAction) {
+        // Only these actions have any effect on gesture detection.  Other
+        // actions have no corresponding WebTouchEvent type and may confuse the
+        // touch pipline, so we ignore them entirely.
+        return eventAction == MotionEvent.ACTION_DOWN
+                || eventAction == MotionEvent.ACTION_UP
+                || eventAction == MotionEvent.ACTION_CANCEL
+                || eventAction == MotionEvent.ACTION_MOVE
+                || eventAction == MotionEvent.ACTION_POINTER_DOWN
+                || eventAction == MotionEvent.ACTION_POINTER_UP;
+    }
+
     // Native Methods
-    private native long nativeInit(int physicalWidth, int physicalHeight, int displayWidth,
-            int displayHeight, float dpToPixel);
+    private native long nativeInit(BlimpClientSession blimpClientSession, int physicalWidth,
+            int physicalHeight, int displayWidth, int displayHeight, float dpToPixel);
     private native void nativeDestroy(long nativeBlimpView);
     private native void nativeSetNeedsComposite(long nativeBlimpView);
     private native void nativeOnSurfaceChanged(
@@ -127,4 +174,16 @@
     private native void nativeOnSurfaceCreated(long nativeBlimpView);
     private native void nativeOnSurfaceDestroyed(long nativeBlimpView);
     private native void nativeSetVisibility(long nativeBlimpView, boolean visible);
+    private native boolean nativeOnTouchEvent(
+            long nativeBlimpView, MotionEvent event,
+            long timeMs, int action, int pointerCount, int historySize, int actionIndex,
+            float x0, float y0, float x1, float y1,
+            int pointerId0, int pointerId1,
+            float touchMajor0, float touchMajor1,
+            float touchMinor0, float touchMinor1,
+            float orientation0, float orientation1,
+            float tilt0, float tilt1,
+            float rawX, float rawY,
+            int androidToolType0, int androidToolType1,
+            int androidButtonState, int androidMetaState);
 }
diff --git a/blimp/client/android/java/src/org/chromium/blimp/session/BlimpClientSession.java b/blimp/client/android/java/src/org/chromium/blimp/session/BlimpClientSession.java
new file mode 100644
index 0000000..cc9368014
--- /dev/null
+++ b/blimp/client/android/java/src/org/chromium/blimp/session/BlimpClientSession.java
@@ -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.
+
+package org.chromium.blimp.session;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+
+/**
+ * The Java representation of a native BlimpClientSession.  This is primarily used to provide access
+ * to the native session methods and to facilitate passing a BlimpClientSession object between Java
+ * classes with native counterparts.
+ */
+@JNINamespace("blimp")
+public class BlimpClientSession {
+    private long mNativeBlimpClientSessionAndroidPtr;
+
+    public BlimpClientSession() {
+        mNativeBlimpClientSessionAndroidPtr = nativeInit();
+    }
+
+    /**
+     * Destroys the native BlimpClientSession.  This class should not be used after this is called.
+     */
+    public void destroy() {
+        if (mNativeBlimpClientSessionAndroidPtr == 0) return;
+
+        nativeDestroy(mNativeBlimpClientSessionAndroidPtr);
+        mNativeBlimpClientSessionAndroidPtr = 0;
+    }
+
+    // Methods that are called by native via JNI.
+    @CalledByNative
+    private long getNativePtr() {
+        assert mNativeBlimpClientSessionAndroidPtr != 0;
+        return mNativeBlimpClientSessionAndroidPtr;
+    }
+
+    private native long nativeInit();
+    private native void nativeDestroy(long nativeBlimpClientSessionAndroid);
+}
\ No newline at end of file
diff --git a/blimp/client/android/java/src/org/chromium/blimp/session/TabControlFeature.java b/blimp/client/android/java/src/org/chromium/blimp/session/TabControlFeature.java
new file mode 100644
index 0000000..d9847af
--- /dev/null
+++ b/blimp/client/android/java/src/org/chromium/blimp/session/TabControlFeature.java
@@ -0,0 +1,72 @@
+// 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.blimp.session;
+
+import android.view.View;
+
+import org.chromium.base.annotations.JNINamespace;
+
+/**
+ * A Java representation of the native ControlFeature class.  Provides easy access for Java control
+ * UI to interact with the native content-lite feature proxy and talk to the engine.
+ */
+@JNINamespace("blimp")
+public class TabControlFeature implements View.OnLayoutChangeListener {
+    private final float mDpToPx;
+
+    private View mContentAreaView;
+    private long mNativeTabControlFeatureAndroidPtr;
+
+    /**
+     * Creates an instance of a {@link TabControlFeature}.  This will register with
+     * {@code contentAreaView} as a {@link android.view.View.OnLayoutChangeListener} and will
+     * unregister when {@link #destroy()} is called.
+     * @param blimpClientSession The {@link BlimpClientSession} that contains the content-lite
+     *                           features required by the native components of the
+     *                           {@link TabControlFeature}.
+     * @param contentAreaView    A {@link View} that represents the content area of the screen.
+     *                           This is used to notify the engine of the correct size of the web
+     *                           content area.
+     */
+    public TabControlFeature(BlimpClientSession blimpClientSession, View contentAreaView) {
+        mContentAreaView = contentAreaView;
+        mDpToPx = mContentAreaView.getContext().getResources().getDisplayMetrics().density;
+        mNativeTabControlFeatureAndroidPtr = nativeInit(blimpClientSession);
+
+        // Push down the current size of the content area view.
+        nativeOnContentAreaSizeChanged(mNativeTabControlFeatureAndroidPtr,
+                mContentAreaView.getWidth(), mContentAreaView.getHeight(), mDpToPx);
+    }
+
+    /**
+     * Tears down the native counterpart to this class and unregisters any {@link View} listeners.
+     * This class should not be used after this.
+     */
+    public void destroy() {
+        if (mContentAreaView != null) {
+            mContentAreaView.removeOnLayoutChangeListener(this);
+            mContentAreaView = null;
+        }
+
+        if (mNativeTabControlFeatureAndroidPtr != 0) {
+            nativeDestroy(mNativeTabControlFeatureAndroidPtr);
+            mNativeTabControlFeatureAndroidPtr = 0;
+        }
+    }
+
+    // View.OnLayoutChangeListener implementation.
+    @Override
+    public void onLayoutChange(View v, int left, int top, int right, int bottom,
+            int oldLeft, int oldTop, int oldRight, int oldBottom) {
+        if (mNativeTabControlFeatureAndroidPtr == 0) return;
+        nativeOnContentAreaSizeChanged(mNativeTabControlFeatureAndroidPtr, right - left,
+                bottom - top, mDpToPx);
+    }
+
+    private native long nativeInit(BlimpClientSession blimpClientSession);
+    private native void nativeDestroy(long nativeTabControlFeatureAndroid);
+    private native void nativeOnContentAreaSizeChanged(
+            long nativeTabControlFeatureAndroid, int width, int height, float dpToPx);
+}
\ No newline at end of file
diff --git a/blimp/client/android/java/src/org/chromium/blimp/toolbar/Toolbar.java b/blimp/client/android/java/src/org/chromium/blimp/toolbar/Toolbar.java
index 9de79ea6..fc00435c 100644
--- a/blimp/client/android/java/src/org/chromium/blimp/toolbar/Toolbar.java
+++ b/blimp/client/android/java/src/org/chromium/blimp/toolbar/Toolbar.java
@@ -16,6 +16,7 @@
 import org.chromium.base.annotations.JNINamespace;
 
 import org.chromium.blimp.R;
+import org.chromium.blimp.session.BlimpClientSession;
 
 /**
  * A {@link View} that visually represents the Blimp toolbar, which lets users issue navigation
@@ -47,11 +48,13 @@
     /**
      * To be called when the native library is loaded so that this class can initialize its native
      * components.
+     * @param blimpClientSession The {@link BlimpClientSession} that contains the content-lite
+     *                           features required by the native components of the Toolbar.
      */
-    public void initialize() {
+    public void initialize(BlimpClientSession blimpClientSession) {
         assert mNativeToolbarPtr == 0;
 
-        mNativeToolbarPtr = nativeInit();
+        mNativeToolbarPtr = nativeInit(blimpClientSession);
         sendUrlTextInternal(mUrlToLoad);
     }
 
@@ -151,7 +154,7 @@
         // TODO(dtrainor): Add a UI for the loading state.
     }
 
-    private native long nativeInit();
+    private native long nativeInit(BlimpClientSession blimpClientSession);
     private native void nativeDestroy(long nativeToolbar);
     private native void nativeOnUrlTextEntered(long nativeToolbar, String text);
     private native void nativeOnReloadPressed(long nativeToolbar);
diff --git a/blimp/client/android/toolbar.cc b/blimp/client/android/toolbar.cc
index 27468e9b..abb69624 100644
--- a/blimp/client/android/toolbar.cc
+++ b/blimp/client/android/toolbar.cc
@@ -5,8 +5,7 @@
 #include "blimp/client/android/toolbar.h"
 
 #include "base/android/jni_string.h"
-#include "base/lazy_instance.h"
-#include "blimp/net/null_blimp_message_processor.h"
+#include "blimp/client/session/blimp_client_session_android.h"
 #include "jni/Toolbar_jni.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/android/java_bitmap.h"
@@ -18,14 +17,17 @@
 
 const int kDummyTabId = 0;
 
-base::LazyInstance<blimp::NullBlimpMessageProcessor>
-    g_null_message_processor = LAZY_INSTANCE_INITIALIZER;
-
 }  // namespace
 
-// static
-static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& jobj) {
-  return reinterpret_cast<intptr_t>(new Toolbar(env, jobj));
+static jlong Init(JNIEnv* env,
+                  const JavaParamRef<jobject>& jobj,
+                  const JavaParamRef<jobject>& blimp_client_session) {
+  BlimpClientSession* client_session =
+      BlimpClientSessionAndroid::FromJavaObject(env,
+                                                blimp_client_session.obj());
+
+  return reinterpret_cast<intptr_t>(
+      new Toolbar(env, jobj, client_session->GetNavigationFeature()));
 }
 
 // static
@@ -34,15 +36,16 @@
 }
 
 Toolbar::Toolbar(JNIEnv* env,
-                 const base::android::JavaParamRef<jobject>& jobj)
-    : navigation_message_processor_(g_null_message_processor.Pointer()) {
+                 const base::android::JavaParamRef<jobject>& jobj,
+                 NavigationFeature* navigation_feature)
+    : navigation_feature_(navigation_feature) {
   java_obj_.Reset(env, jobj);
 
-  navigation_message_processor_.SetDelegate(kDummyTabId, this);
+  navigation_feature_->SetDelegate(kDummyTabId, this);
 }
 
 Toolbar::~Toolbar() {
-  navigation_message_processor_.RemoveDelegate(kDummyTabId);
+  navigation_feature_->RemoveDelegate(kDummyTabId);
 }
 
 void Toolbar::Destroy(JNIEnv* env, jobject jobj) {
@@ -50,21 +53,20 @@
 }
 
 void Toolbar::OnUrlTextEntered(JNIEnv* env, jobject jobj, jstring text) {
-  navigation_message_processor_.NavigateToUrlText(
-      kDummyTabId,
-      base::android::ConvertJavaStringToUTF8(env, text));
+  navigation_feature_->NavigateToUrlText(
+      kDummyTabId, base::android::ConvertJavaStringToUTF8(env, text));
 }
 
 void Toolbar::OnReloadPressed(JNIEnv* env, jobject jobj) {
-  navigation_message_processor_.Reload(kDummyTabId);
+  navigation_feature_->Reload(kDummyTabId);
 }
 
 void Toolbar::OnForwardPressed(JNIEnv* env, jobject jobj) {
-  navigation_message_processor_.GoForward(kDummyTabId);
+  navigation_feature_->GoForward(kDummyTabId);
 }
 
 jboolean Toolbar::OnBackPressed(JNIEnv* env, jobject jobj) {
-  navigation_message_processor_.GoBack(kDummyTabId);
+  navigation_feature_->GoBack(kDummyTabId);
 
   // TODO(dtrainor): Find a way to determine whether or not we're at the end of
   // our history stack.
diff --git a/blimp/client/android/toolbar.h b/blimp/client/android/toolbar.h
index f9d210d..b72ce1b 100644
--- a/blimp/client/android/toolbar.h
+++ b/blimp/client/android/toolbar.h
@@ -7,7 +7,7 @@
 
 #include "base/android/jni_android.h"
 #include "base/macros.h"
-#include "blimp/client/navigation_message_processor.h"
+#include "blimp/client/session/navigation_feature.h"
 
 class GURL;
 class SkBitmap;
@@ -16,12 +16,14 @@
 
 // The native component of org.chromium.blimp.toolbar.Toolbar.  This handles
 // marshalling calls between Java and native.  Specifically, this passes calls
-// between Toolbar.java <=> content_lite's NavigationController layer.
-class Toolbar : public NavigationMessageProcessor::NavigationMessageDelegate {
+// between Toolbar.java <=> NavigationFeature.
+class Toolbar : public NavigationFeature::NavigationFeatureDelegate {
  public:
   static bool RegisterJni(JNIEnv* env);
 
-  Toolbar(JNIEnv* env, const base::android::JavaParamRef<jobject>& jobj);
+  Toolbar(JNIEnv* env,
+          const base::android::JavaParamRef<jobject>& jobj,
+          NavigationFeature* navigation_feature);
 
   // Methods called from Java via JNI.
   void Destroy(JNIEnv* env, jobject jobj);
@@ -30,7 +32,7 @@
   void OnForwardPressed(JNIEnv* env, jobject jobj);
   jboolean OnBackPressed(JNIEnv* env, jobject jobj);
 
-  // NavigationMessageDelegate implementation.
+  // NavigationFeatureDelegate implementation.
   void OnUrlChanged(int tab_id, const GURL& url) override;
   void OnFaviconChanged(int tab_id, const SkBitmap& favicon) override;
   void OnTitleChanged(int tab_id, const std::string& title) override;
@@ -39,7 +41,7 @@
  private:
   virtual ~Toolbar();
 
-  NavigationMessageProcessor navigation_message_processor_;
+  NavigationFeature* navigation_feature_;
 
   // Reference to the Java object which owns this class.
   base::android::ScopedJavaGlobalRef<jobject> java_obj_;
diff --git a/blimp/client/compositor/blimp_compositor.cc b/blimp/client/compositor/blimp_compositor.cc
index 9c783dcc..cc3b5570 100644
--- a/blimp/client/compositor/blimp_compositor.cc
+++ b/blimp/client/compositor/blimp_compositor.cc
@@ -17,13 +17,8 @@
 #include "blimp/client/compositor/blimp_layer_tree_settings.h"
 #include "blimp/client/compositor/blimp_output_surface.h"
 #include "blimp/client/compositor/test/dummy_layer_driver.h"
+#include "blimp/client/session/render_widget_feature.h"
 #include "blimp/common/compositor/blimp_task_graph_runner.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 "blimp/net/blimp_message_multiplexer.h"
-#include "blimp/net/null_blimp_message_processor.h"
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_settings.h"
 #include "cc/output/output_surface.h"
@@ -39,9 +34,6 @@
 
 const int kDummyTabId = 0;
 
-base::LazyInstance<blimp::NullBlimpMessageProcessor> g_blimp_message_processor =
-    LAZY_INSTANCE_INITIALIZER;
-
 // TODO(dtrainor): Replace this when Layer content comes from the server (see
 // crbug.com/527200 for details).
 base::LazyInstance<blimp::DummyLayerDriver> g_dummy_layer_driver =
@@ -51,26 +43,29 @@
 
 namespace blimp {
 
-BlimpCompositor::BlimpCompositor(float dp_to_px)
+BlimpCompositor::BlimpCompositor(float dp_to_px,
+                                 RenderWidgetFeature* render_widget_feature)
     : device_scale_factor_(dp_to_px),
       window_(gfx::kNullAcceleratedWidget),
       host_should_be_visible_(false),
       output_surface_request_pending_(false),
       remote_proto_channel_receiver_(nullptr),
-      // TODO(dtrainor): Properly pull these from BlimpMessageMultiplexer.
-      render_widget_processor_(g_blimp_message_processor.Pointer(),
-                               g_blimp_message_processor.Pointer()) {
-  render_widget_processor_.SetDelegate(kDummyTabId, this);
+      render_widget_feature_(render_widget_feature) {
+  render_widget_feature_->SetDelegate(kDummyTabId, this);
 }
 
 BlimpCompositor::~BlimpCompositor() {
-  render_widget_processor_.RemoveDelegate(kDummyTabId);
+  render_widget_feature_->RemoveDelegate(kDummyTabId);
   SetVisible(false);
 
   // Destroy |host_| first, as it has a reference to the |settings_| and runs
   // tasks on |compositor_thread_|.
   host_.reset();
   settings_.reset();
+
+  // We must destroy |host_| before the |input_manager_|.
+  input_manager_.reset();
+
   if (compositor_thread_)
     compositor_thread_->Stop();
 }
@@ -131,6 +126,12 @@
   window_ = gfx::kNullAcceleratedWidget;
 }
 
+bool BlimpCompositor::OnTouchEvent(const ui::MotionEvent& motion_event) {
+  if (input_manager_)
+    return input_manager_->OnTouchEvent(motion_event);
+  return false;
+}
+
 void BlimpCompositor::WillBeginMainFrame() {}
 
 void BlimpCompositor::DidBeginMainFrame() {}
@@ -178,7 +179,7 @@
 
 void BlimpCompositor::SendCompositorProto(
     const cc::proto::CompositorMessage& proto) {
-  render_widget_processor_.SendCompositorMessage(kDummyTabId, proto);
+  render_widget_feature_->SendCompositorMessage(kDummyTabId, proto);
 }
 
 void BlimpCompositor::OnRenderWidgetInitialized() {
@@ -189,6 +190,12 @@
   // Destroy the old LayerTreeHost state.
   host_.reset();
 
+  // Destroy the old input manager state.
+  // It is important to destroy the LayerTreeHost before destroying the input
+  // manager as it has a reference to the cc::InputHandlerClient owned by the
+  // BlimpInputManager.
+  input_manager_.reset();
+
   // Reset other state.
   output_surface_request_pending_ = false;
 
@@ -212,6 +219,11 @@
   PopulateCommonLayerTreeSettings(settings);
 }
 
+void BlimpCompositor::SendWebInputEvent(
+    const blink::WebInputEvent& input_event) {
+  render_widget_feature_->SendInputEvent(kDummyTabId, input_event);
+}
+
 void BlimpCompositor::CreateLayerTreeHost(
     scoped_ptr<cc::proto::CompositorMessage> message) {
   if (!settings_) {
@@ -244,6 +256,15 @@
       cc::Layer::Create(BlimpCompositor::LayerSettings()));
   host_->SetRootLayer(root);
   g_dummy_layer_driver.Pointer()->SetParentLayer(root);
+
+  // TODO(khushalsagar): Create this after successful initialization of the
+  // remote client compositor when implemented.
+  DCHECK(!input_manager_);
+  input_manager_ =
+      BlimpInputManager::Create(this,
+                                base::ThreadTaskRunnerHandle::Get(),
+                                GetCompositorTaskRunner(),
+                                host_->GetInputHandler());
 }
 
 scoped_refptr<base::SingleThreadTaskRunner>
diff --git a/blimp/client/compositor/blimp_compositor.h b/blimp/client/compositor/blimp_compositor.h
index e382a3e..18280e04 100644
--- a/blimp/client/compositor/blimp_compositor.h
+++ b/blimp/client/compositor/blimp_compositor.h
@@ -11,7 +11,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "blimp/client/blimp_client_export.h"
-#include "blimp/client/compositor/render_widget_message_processor.h"
+#include "blimp/client/input/blimp_input_manager.h"
+#include "blimp/client/session/render_widget_feature.h"
 #include "cc/layers/layer_settings.h"
 #include "cc/trees/layer_tree_host_client.h"
 #include "cc/trees/layer_tree_settings.h"
@@ -42,8 +43,8 @@
 class BLIMP_CLIENT_EXPORT BlimpCompositor
     : public cc::LayerTreeHostClient,
       public cc::RemoteProtoChannel,
-      public RenderWidgetMessageProcessor::RenderWidgetMessageDelegate {
-
+      public RenderWidgetFeature::RenderWidgetFeatureDelegate,
+      public BlimpInputManagerClient {
  public:
   ~BlimpCompositor() override;
 
@@ -73,11 +74,15 @@
   // compositor.
   void ReleaseAcceleratedWidget();
 
+  // Forwards the touch event to the |input_manager_|.
+  bool OnTouchEvent(const ui::MotionEvent& motion_event);
+
  protected:
   // |dp_to_px| is the scale factor required to move from dp (device pixels) to
   // px.  See https://developer.android.com/guide/practices/screens_support.html
   // for more details.
-  explicit BlimpCompositor(float dp_to_px);
+  explicit BlimpCompositor(float dp_to_px,
+                           RenderWidgetFeature* render_widget_feature);
 
   // Populates the cc::LayerTreeSettings used by the cc::LayerTreeHost.  Can be
   // overridden to provide custom settings parameters.
@@ -112,11 +117,14 @@
   void SetProtoReceiver(ProtoReceiver* receiver) override;
   void SendCompositorProto(const cc::proto::CompositorMessage& proto) override;
 
-  // RenderWidgetMessageDelegate implementation.
+  // RenderWidgetFeatureDelegate implementation.
   void OnRenderWidgetInitialized() override;
   void OnCompositorMessageReceived(
       scoped_ptr<cc::proto::CompositorMessage> message) override;
 
+  // BlimpInputManagerClient implementation.
+  void SendWebInputEvent(const blink::WebInputEvent& input_event) override;
+
   // Helper method to build the internal CC compositor instance from |message|.
   void CreateLayerTreeHost(scoped_ptr<cc::proto::CompositorMessage> message);
 
@@ -156,7 +164,14 @@
   // The bridge to the network layer that does the proto/RenderWidget id work.
   // TODO(dtrainor): Move this to a higher level once we start dealing with
   // multiple tabs.
-  RenderWidgetMessageProcessor render_widget_processor_;
+  RenderWidgetFeature* render_widget_feature_;
+
+  // Handles input events for the current render widget. The lifetime of the
+  // input manager is tied to the lifetime of the |host_| which owns the
+  // cc::InputHandler. The input events are forwarded to this input handler by
+  // the manager to be handled by the client compositor for the current render
+  // widget.
+  scoped_ptr<BlimpInputManager> input_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(BlimpCompositor);
 };
diff --git a/blimp/client/compositor/blimp_compositor_android.cc b/blimp/client/compositor/blimp_compositor_android.cc
index 9cc2524..a78729a 100644
--- a/blimp/client/compositor/blimp_compositor_android.cc
+++ b/blimp/client/compositor/blimp_compositor_android.cc
@@ -20,21 +20,24 @@
 scoped_ptr<BlimpCompositorAndroid> BlimpCompositorAndroid::Create(
     const gfx::Size& real_size,
     const gfx::Size& size,
-    float dp_to_px) {
+    float dp_to_px,
+    RenderWidgetFeature* render_widget_feature) {
   gfx::Size device_size(real_size);
   bool real_size_supported = true;
   if (device_size.IsEmpty()) {
     real_size_supported = false;
     device_size = size;
   }
-  return make_scoped_ptr(
-      new BlimpCompositorAndroid(device_size, real_size_supported, dp_to_px));
+  return make_scoped_ptr(new BlimpCompositorAndroid(
+      device_size, real_size_supported, dp_to_px, render_widget_feature));
 }
 
-BlimpCompositorAndroid::BlimpCompositorAndroid(const gfx::Size& size,
-                                               bool real_size_supported,
-                                               float dp_to_px)
-    : BlimpCompositor(dp_to_px),
+BlimpCompositorAndroid::BlimpCompositorAndroid(
+    const gfx::Size& size,
+    bool real_size_supported,
+    float dp_to_px,
+    RenderWidgetFeature* render_widget_feature)
+    : BlimpCompositor(dp_to_px, render_widget_feature),
       portrait_width_(std::min(size.width(), size.height())),
       landscape_width_(std::max(size.width(), size.height())),
       real_size_supported_(real_size_supported) {}
diff --git a/blimp/client/compositor/blimp_compositor_android.h b/blimp/client/compositor/blimp_compositor_android.h
index f3255d9e..f2c1f197 100644
--- a/blimp/client/compositor/blimp_compositor_android.h
+++ b/blimp/client/compositor/blimp_compositor_android.h
@@ -22,6 +22,8 @@
 
 namespace blimp {
 
+class RenderWidgetFeature;
+
 // An Android specific version of the BlimpCompositor.  This class builds a
 // gfx::AcceleratedWidget out of an Android SurfaceView's surface.
 class BlimpCompositorAndroid : public BlimpCompositor {
@@ -31,9 +33,11 @@
   // area not including system decorations (see android.view.Display.getSize()).
   // |dp_to_px| is the scale factor that is required to convert from dp device
   // pixels) to px.
-  static scoped_ptr<BlimpCompositorAndroid> Create(const gfx::Size& real_size,
-                                                   const gfx::Size& size,
-                                                   float dp_to_px);
+  static scoped_ptr<BlimpCompositorAndroid> Create(
+      const gfx::Size& real_size,
+      const gfx::Size& size,
+      float dp_to_px,
+      RenderWidgetFeature* render_widget_feature);
 
   ~BlimpCompositorAndroid() override;
 
@@ -44,7 +48,8 @@
   // is required to convert from dp (device pixels) to px.
   BlimpCompositorAndroid(const gfx::Size& size,
                          bool real_size_supported,
-                         float dp_to_px);
+                         float dp_to_px,
+                         RenderWidgetFeature* render_widget_feature);
 
   // BlimpCompositor implementation.
   void GenerateLayerTreeSettings(cc::LayerTreeSettings* settings);
diff --git a/blimp/client/compositor/render_widget_message_processor.cc b/blimp/client/compositor/render_widget_message_processor.cc
deleted file mode 100644
index 73699fc0..0000000
--- a/blimp/client/compositor/render_widget_message_processor.cc
+++ /dev/null
@@ -1,135 +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 "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"
-#include "blimp/common/proto/render_widget.pb.h"
-#include "cc/proto/compositor_message.pb.h"
-#include "net/base/net_errors.h"
-
-namespace blimp {
-
-RenderWidgetMessageProcessor::RenderWidgetMessageProcessor(
-    BlimpMessageProcessor* input_message_processor,
-    BlimpMessageProcessor* compositor_message_processor)
-    : input_message_processor_(input_message_processor),
-      compositor_message_processor_(compositor_message_processor) {
-  // TODO(dtrainor): Register as a BlimpMessageProcessor for
-  // BlimpMessage::RENDER_WIDGET and BlimpMessage::COMPOSITOR messages.
-}
-
-RenderWidgetMessageProcessor::~RenderWidgetMessageProcessor() {
-  // TODO(dtrainor): Unregister as a BlimpMessageProcessor for
-  // BlimpMessage::RENDER_WIDGET and BlimpMessage::COMPOSITOR messages.
-}
-
-void RenderWidgetMessageProcessor::SendInputEvent(
-    const int tab_id, const blink::WebInputEvent& event) {
-  scoped_ptr<BlimpMessage> blimp_message =
-      input_message_generator_.GenerateMessage(event);
-
-  // Don't send unsupported WebInputEvents.
-  if (!blimp_message)
-    return;
-
-  blimp_message->set_target_tab_id(tab_id);
-  blimp_message->mutable_input()->set_render_widget_id(
-      GetRenderWidgetId(tab_id));
-
-  input_message_processor_->ProcessMessage(std::move(blimp_message),
-                                           net::CompletionCallback());
-}
-
-void RenderWidgetMessageProcessor::SendCompositorMessage(
-    const int tab_id,
-    const cc::proto::CompositorMessage& message) {
-  CompositorMessage* compositor_message;
-  scoped_ptr<BlimpMessage> blimp_message =
-      CreateBlimpMessage(&compositor_message, tab_id);
-
-  uint32_t render_widget_id = GetRenderWidgetId(tab_id);
-  DCHECK_LT(0U, render_widget_id);
-  compositor_message->set_render_widget_id(render_widget_id);
-  compositor_message->mutable_payload()->resize(
-      base::checked_cast<size_t>(message.ByteSize()));
-  if (message.SerializeToString(compositor_message->mutable_payload())) {
-    compositor_message_processor_->ProcessMessage(std::move(blimp_message),
-                                                  net::CompletionCallback());
-  } else {
-    LOG(ERROR) << "Unable to serialize compositor proto.";
-  }
-}
-
-void RenderWidgetMessageProcessor::SetDelegate(
-    const int tab_id, RenderWidgetMessageDelegate* delegate) {
-  DCHECK(!FindDelegate(tab_id));
-  delegates_[tab_id] = delegate;
-}
-
-void RenderWidgetMessageProcessor::RemoveDelegate(const int tab_id) {
-  DelegateMap::iterator it = delegates_.find(tab_id);
-  if (it != delegates_.end())
-    delegates_.erase(it);
-}
-
-void RenderWidgetMessageProcessor::ProcessMessage(
-    scoped_ptr<BlimpMessage> message,
-    const net::CompletionCallback& callback) {
-  DCHECK(message->type() == BlimpMessage::RENDER_WIDGET ||
-         message->type() == BlimpMessage::COMPOSITOR);
-
-  int target_tab_id = message->target_tab_id();
-  RenderWidgetMessageDelegate* delegate = FindDelegate(target_tab_id);
-  DCHECK(delegate);
-
-  switch (message->type()) {
-    case BlimpMessage::RENDER_WIDGET:
-      if (message->render_widget().type() == RenderWidgetMessage::INITIALIZE) {
-        render_widget_ids_[target_tab_id] =
-            message->render_widget().render_widget_id();
-        delegate->OnRenderWidgetInitialized();
-      }
-      break;
-    case BlimpMessage::COMPOSITOR:
-      {
-        DCHECK_EQ(message->compositor().render_widget_id(),
-                  GetRenderWidgetId(target_tab_id));
-        scoped_ptr<cc::proto::CompositorMessage> payload(
-            new cc::proto::CompositorMessage);
-        if (payload->ParseFromString(message->compositor().payload())) {
-          delegate->OnCompositorMessageReceived(std::move(payload));
-        }
-      }
-      break;
-    default:
-      NOTIMPLEMENTED();
-  }
-
-  if (!callback.is_null()) {
-    callback.Run(net::OK);
-  }
-}
-
-RenderWidgetMessageProcessor::RenderWidgetMessageDelegate*
-RenderWidgetMessageProcessor::FindDelegate(
-    const int tab_id) {
-  DelegateMap::const_iterator it = delegates_.find(tab_id);
-  if (it != delegates_.end())
-    return it->second;
-  return nullptr;
-}
-
-uint32_t RenderWidgetMessageProcessor::GetRenderWidgetId(const int tab_id) {
-  RenderWidgetIdMap::const_iterator it = render_widget_ids_.find(tab_id);
-  if (it != render_widget_ids_.end())
-    return it->second;
-  return 0U;
-}
-
-}  // namespace blimp
diff --git a/blimp/client/compositor/render_widget_message_processor_unittest.cc b/blimp/client/compositor/render_widget_message_processor_unittest.cc
deleted file mode 100644
index 384c7314..0000000
--- a/blimp/client/compositor/render_widget_message_processor_unittest.cc
+++ /dev/null
@@ -1,125 +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 "blimp/client/compositor/render_widget_message_processor.h"
-
-#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"
-#include "blimp/net/test_common.h"
-#include "cc/proto/compositor_message.pb.h"
-#include "net/base/net_errors.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::_;
-using testing::InvokeArgument;
-using testing::Ref;
-using testing::Return;
-using testing::SaveArg;
-
-namespace blimp {
-
-namespace {
-
-class MockRenderWidgetMessageDelegate
-    : public RenderWidgetMessageProcessor::RenderWidgetMessageDelegate {
- public:
-  // RenderWidgetMessageDelegate implementation.
-  void OnRenderWidgetInitialized() override {
-    MockableOnRenderWidgetInitialized();
-  }
-  void OnCompositorMessageReceived(
-      scoped_ptr<cc::proto::CompositorMessage> message) override {
-    MockableOnCompositorMessageReceived(*message);
-  }
-
-  MOCK_METHOD0(MockableOnRenderWidgetInitialized, void());
-  MOCK_METHOD1(MockableOnCompositorMessageReceived,
-               void(const cc::proto::CompositorMessage& message));
-};
-
-MATCHER_P2(CompMsgEquals, tab_id, rw_id, "") {
-  return arg.compositor().render_widget_id() == rw_id &&
-      arg.target_tab_id() == tab_id;
-}
-
-void SendRenderWidgetMessage(BlimpMessageProcessor* processor,
-                             int tab_id,
-                             uint32_t rw_id) {
-  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),
-                            net::CompletionCallback());
-}
-
-void SendCompositorMessage(BlimpMessageProcessor* processor,
-                             int tab_id,
-                             uint32_t rw_id) {
-  CompositorMessage* details;
-  scoped_ptr<BlimpMessage> message = CreateBlimpMessage(&details, tab_id);
-  details->set_render_widget_id(rw_id);
-  processor->ProcessMessage(std::move(message),
-                            net::CompletionCallback());
-}
-
-}  // namespace
-
-class RenderWidgetMessageProcessorTest : public testing::Test {
- public:
-  RenderWidgetMessageProcessorTest()
-      : processor_(&out_processor_, &out_processor_) {}
-
-  void SetUp() override {
-    processor_.SetDelegate(1, &delegate1_);
-    processor_.SetDelegate(2, &delegate2_);
-  }
-
- protected:
-  MockBlimpMessageProcessor out_processor_;
-  MockRenderWidgetMessageDelegate delegate1_;
-  MockRenderWidgetMessageDelegate delegate2_;
-
-  RenderWidgetMessageProcessor processor_;
-};
-
-TEST_F(RenderWidgetMessageProcessorTest, DelegateCallsOK) {
-  EXPECT_CALL(delegate1_, MockableOnRenderWidgetInitialized()).Times(1);
-  SendRenderWidgetMessage(&processor_, 1, 1U);
-
-  EXPECT_CALL(delegate1_, MockableOnCompositorMessageReceived(_)).Times(1);
-  SendCompositorMessage(&processor_, 1, 1U);
-
-  EXPECT_CALL(delegate2_, MockableOnRenderWidgetInitialized()).Times(1);
-  SendRenderWidgetMessage(&processor_, 2, 2U);
-
-  EXPECT_CALL(delegate2_, MockableOnCompositorMessageReceived(_)).Times(1);
-  SendCompositorMessage(&processor_, 2, 2U);
-}
-
-TEST_F(RenderWidgetMessageProcessorTest, RepliesHaveCorrectRenderWidgetId) {
-  SendRenderWidgetMessage(&processor_, 1, 2U);
-  SendRenderWidgetMessage(&processor_, 2, 1U);
-
-  EXPECT_CALL(out_processor_,
-              MockableProcessMessage(CompMsgEquals(1, 2U), _)).Times(1);
-  processor_.SendCompositorMessage(1, cc::proto::CompositorMessage());
-
-  SendRenderWidgetMessage(&processor_, 1, 3U);
-
-  EXPECT_CALL(out_processor_,
-              MockableProcessMessage(CompMsgEquals(1, 3U), _)).Times(1);
-  processor_.SendCompositorMessage(1, cc::proto::CompositorMessage());
-
-  EXPECT_CALL(out_processor_,
-              MockableProcessMessage(CompMsgEquals(2, 1U), _)).Times(1);
-  processor_.SendCompositorMessage(2, cc::proto::CompositorMessage());
-}
-
-}  // namespace blimp
diff --git a/blimp/client/input/blimp_input_handler_wrapper.cc b/blimp/client/input/blimp_input_handler_wrapper.cc
new file mode 100644
index 0000000..dbd6fe75
--- /dev/null
+++ b/blimp/client/input/blimp_input_handler_wrapper.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 "blimp/client/input/blimp_input_handler_wrapper.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "blimp/client/input/blimp_input_manager.h"
+#include "ui/events/gestures/blink/web_gesture_curve_impl.h"
+
+namespace blimp {
+
+BlimpInputHandlerWrapper::BlimpInputHandlerWrapper(
+    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+    const base::WeakPtr<BlimpInputManager> input_manager_weak_ptr,
+    cc::InputHandler* input_handler)
+    : main_task_runner_(main_task_runner),
+      input_manager_weak_ptr_(input_manager_weak_ptr) {
+  DCHECK(compositor_thread_checker_.CalledOnValidThread());
+  DCHECK(input_handler);
+  input_handler_proxy_.reset(
+      new ui::InputHandlerProxy(input_handler, this));
+}
+
+BlimpInputHandlerWrapper::~BlimpInputHandlerWrapper() {
+  DCHECK(compositor_thread_checker_.CalledOnValidThread());
+
+  // The input handler proxy must have been shutdown by the cc::InputHandler
+  // before the InputHandlerWrapper is destroyed.
+  DCHECK(!input_handler_proxy_);
+}
+
+void BlimpInputHandlerWrapper::HandleWebInputEvent(
+      const blink::WebInputEvent& input_event) {
+  DCHECK(compositor_thread_checker_.CalledOnValidThread());
+
+  // We might not have the input handler proxy anymore.
+  if (!input_handler_proxy_)
+    return;
+
+  ui::InputHandlerProxy::EventDisposition disposition =
+      input_handler_proxy_->HandleInputEvent(input_event);
+
+  bool consumed = disposition == ui::InputHandlerProxy::DID_NOT_HANDLE;
+
+  main_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&BlimpInputManager::DidHandleWebInputEvent,
+                 input_manager_weak_ptr_, input_event, consumed));
+}
+
+void BlimpInputHandlerWrapper::WillShutdown() {
+  DCHECK(compositor_thread_checker_.CalledOnValidThread());
+
+  input_handler_proxy_.reset();
+}
+
+void BlimpInputHandlerWrapper::TransferActiveWheelFlingAnimation(
+    const blink::WebActiveWheelFlingParameters& params) {
+  DCHECK(compositor_thread_checker_.CalledOnValidThread());
+
+  NOTIMPLEMENTED() <<
+      "Transferring Fling Animations to the engine is not supported";
+}
+
+blink::WebGestureCurve* BlimpInputHandlerWrapper::CreateFlingAnimationCurve(
+      blink::WebGestureDevice device_source,
+      const blink::WebFloatPoint& velocity,
+      const blink::WebSize& cumulative_scroll) {
+  DCHECK(compositor_thread_checker_.CalledOnValidThread());
+
+  return ui::WebGestureCurveImpl::CreateFromDefaultPlatformCurve(
+               gfx::Vector2dF(velocity.x, velocity.y),
+               gfx::Vector2dF(cumulative_scroll.width,
+                              cumulative_scroll.height),
+               false /* on_main_thread */).release();
+}
+
+void BlimpInputHandlerWrapper::DidOverscroll(
+    const gfx::Vector2dF& accumulated_overscroll,
+    const gfx::Vector2dF& latest_overscroll_delta,
+    const gfx::Vector2dF& current_fling_velocity,
+    const gfx::PointF& causal_event_viewport_point) {
+  DCHECK(compositor_thread_checker_.CalledOnValidThread());
+}
+
+void BlimpInputHandlerWrapper::DidStopFlinging() {
+  DCHECK(compositor_thread_checker_.CalledOnValidThread());
+}
+
+void BlimpInputHandlerWrapper::DidAnimateForInput() {
+  DCHECK(compositor_thread_checker_.CalledOnValidThread());
+}
+
+}  // namespace blimp
diff --git a/blimp/client/input/blimp_input_handler_wrapper.h b/blimp/client/input/blimp_input_handler_wrapper.h
new file mode 100644
index 0000000..7bb55d87
--- /dev/null
+++ b/blimp/client/input/blimp_input_handler_wrapper.h
@@ -0,0 +1,67 @@
+// Copyright 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BLIMP_CLIENT_INPUT_BLIMP_INPUT_HANDLER_WRAPPER_H_
+#define BLIMP_CLIENT_INPUT_BLIMP_INPUT_HANDLER_WRAPPER_H_
+
+#include "base/macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_checker.h"
+#include "ui/events/blink/input_handler_proxy.h"
+#include "ui/events/blink/input_handler_proxy_client.h"
+
+namespace blimp {
+class BlimpInputManager;
+
+// The BlimpInputHandlerWrapper isolates all input handling processing done on
+// the compositor thread from the BlimpInputManager. It takes web input events
+// from the BlimpInputManager and sends them to the ui::InputHandlerProxy.
+// The class is created and lives on the compositor thread.
+class BlimpInputHandlerWrapper : public ui::InputHandlerProxyClient {
+ public:
+  BlimpInputHandlerWrapper(
+      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+      const base::WeakPtr<BlimpInputManager> input_manager_weak_ptr,
+      cc::InputHandler* input_handler);
+
+  ~BlimpInputHandlerWrapper() override;
+
+  // Called by the BlimpInputManager to process a web input event. This will
+  // call BlimpInputManager::HandleWebInputEvent with the result on the main
+  // thread.
+  void HandleWebInputEvent(const blink::WebInputEvent& input_event);
+
+ private:
+  // InputHandlerProxyClient implementation.
+  void WillShutdown() override;
+  void TransferActiveWheelFlingAnimation(
+      const blink::WebActiveWheelFlingParameters& params) override;
+  blink::WebGestureCurve* CreateFlingAnimationCurve(
+      blink::WebGestureDevice device_source,
+      const blink::WebFloatPoint& velocity,
+      const blink::WebSize& cumulative_scroll) override;
+  void DidOverscroll(const gfx::Vector2dF& accumulated_overscroll,
+                     const gfx::Vector2dF& latest_overscroll_delta,
+                     const gfx::Vector2dF& current_fling_velocity,
+                     const gfx::PointF& causal_event_viewport_point) override;
+  void DidStopFlinging() override;
+  void DidAnimateForInput() override;
+
+  base::ThreadChecker compositor_thread_checker_;
+
+  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+
+  // Used to queue calls to the BlimpInputManager to be run on the main
+  // thread. This ensures that any tasks queued are abandoned after the
+  // BlimpInputManager is destroyed.
+  base::WeakPtr<BlimpInputManager> input_manager_weak_ptr_;
+
+  scoped_ptr<ui::InputHandlerProxy> input_handler_proxy_;
+
+  DISALLOW_COPY_AND_ASSIGN(BlimpInputHandlerWrapper);
+};
+
+}  // namespace blimp
+
+#endif  // BLIMP_CLIENT_INPUT_BLIMP_INPUT_HANDLER_WRAPPER_H_
diff --git a/blimp/client/input/blimp_input_manager.cc b/blimp/client/input/blimp_input_manager.cc
new file mode 100644
index 0000000..dedfac69
--- /dev/null
+++ b/blimp/client/input/blimp_input_manager.cc
@@ -0,0 +1,155 @@
+// 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/client/input/blimp_input_manager.h"
+
+#include "base/auto_reset.h"
+#include "base/bind.h"
+#include "base/location.h"
+#include "ui/events/blink/blink_event_util.h"
+#include "ui/events/gesture_detection/gesture_provider_config_helper.h"
+
+namespace blimp {
+
+scoped_ptr<BlimpInputManager> BlimpInputManager::Create(
+      BlimpInputManagerClient* client,
+      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+      scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
+      const base::WeakPtr<cc::InputHandler>& input_handler) {
+  return make_scoped_ptr(new BlimpInputManager(client,
+                                               main_task_runner,
+                                               compositor_task_runner,
+                                               input_handler));
+}
+
+BlimpInputManager::BlimpInputManager(
+    BlimpInputManagerClient* client,
+    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+    scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
+    const base::WeakPtr<cc::InputHandler>& input_handler)
+    : client_(client),
+      gesture_provider_(ui::GetGestureProviderConfig(
+                ui::GestureProviderConfigType::CURRENT_PLATFORM), this),
+      main_task_runner_(main_task_runner),
+      compositor_task_runner_(compositor_task_runner),
+      main_thread_blocked_(false),
+      weak_factory_(this) {
+  DCHECK(IsMainThread());
+  compositor_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(
+          &BlimpInputManager::CreateInputHandlerWrapperOnCompositorThread,
+          base::Unretained(this), weak_factory_.GetWeakPtr(),
+          input_handler));
+}
+
+BlimpInputManager::~BlimpInputManager() {
+  DCHECK(IsMainThread());
+
+  base::WaitableEvent shutdown_event(false /* manual_reset */,
+                                     false /* initially_signaled */);
+  {
+    base::AutoReset<bool> auto_reset_main_thread_blocked(
+        &main_thread_blocked_, true);
+    compositor_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(
+            &BlimpInputManager::ShutdownOnCompositorThread,
+            base::Unretained(this), &shutdown_event));
+    shutdown_event.Wait();
+  }
+}
+
+bool BlimpInputManager::OnTouchEvent(const ui::MotionEvent& motion_event) {
+  DCHECK(IsMainThread());
+
+  ui::FilteredGestureProvider::TouchHandlingResult result =
+      gesture_provider_.OnTouchEvent(motion_event);
+  if (!result.succeeded)
+    return false;
+
+  blink::WebTouchEvent touch =
+      ui::CreateWebTouchEventFromMotionEvent(motion_event,
+                                             result.did_generate_scroll);
+
+  // Touch events are queued in the Gesture Provider until acknowledged to
+  // allow them to be consumed by the touch event handlers in blink which can
+  // prevent-default on the event. Since we currently do not support touch
+  // handlers the event is always acknowledged as not consumed.
+  gesture_provider_.OnTouchEventAck(touch.uniqueTouchEventId, false);
+
+  return true;
+}
+
+void BlimpInputManager::OnGestureEvent(const ui::GestureEventData& gesture) {
+  DCHECK(IsMainThread());
+
+  blink::WebGestureEvent web_gesture =
+      ui::CreateWebGestureEventFromGestureEventData(gesture);
+  // TODO(khushalsagar): Remove this workaround after Android fixes UiAutomator
+  // to stop providing shift meta values to synthetic MotionEvents. This
+  // prevents unintended shift+click interpretation of all accessibility clicks.
+  // See crbug.com/443247.
+  if (web_gesture.type == blink::WebInputEvent::GestureTap &&
+      web_gesture.modifiers == blink::WebInputEvent::ShiftKey) {
+    web_gesture.modifiers = 0;
+  }
+
+  compositor_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(
+          &BlimpInputManager::HandleWebInputEventOnCompositorThread,
+          base::Unretained(this), web_gesture));
+}
+
+void BlimpInputManager::CreateInputHandlerWrapperOnCompositorThread(
+    base::WeakPtr<BlimpInputManager> input_manager_weak_ptr,
+    const base::WeakPtr<cc::InputHandler>& input_handler) {
+  DCHECK(IsCompositorThread());
+
+  // The input_handler might have been destroyed at this point.
+  if (!input_handler)
+    return;
+
+  DCHECK(!input_handler_wrapper_);
+  input_handler_wrapper_ = make_scoped_ptr(
+      new BlimpInputHandlerWrapper(main_task_runner_,
+                                   input_manager_weak_ptr,
+                                   input_handler.get()));
+}
+
+void BlimpInputManager::HandleWebInputEventOnCompositorThread(
+    const blink::WebInputEvent& input_event) {
+  DCHECK(IsCompositorThread());
+
+  if (input_handler_wrapper_)
+    input_handler_wrapper_->HandleWebInputEvent(input_event);
+}
+
+void BlimpInputManager::ShutdownOnCompositorThread(
+    base::WaitableEvent* shutdown_event) {
+  DCHECK(IsCompositorThread());
+  DCHECK(main_thread_blocked_);
+
+  input_handler_wrapper_.reset();
+  shutdown_event->Signal();
+}
+
+void BlimpInputManager::DidHandleWebInputEvent(
+    const blink::WebInputEvent& input_event, bool consumed) {
+  DCHECK(IsMainThread());
+
+  if (!consumed)
+    client_->SendWebInputEvent(input_event);
+}
+
+bool BlimpInputManager::IsMainThread() const {
+  return main_task_runner_->BelongsToCurrentThread();
+}
+
+bool BlimpInputManager::IsCompositorThread() const {
+  return compositor_task_runner_->BelongsToCurrentThread();
+}
+
+}  // namespace blimp
diff --git a/blimp/client/input/blimp_input_manager.h b/blimp/client/input/blimp_input_manager.h
new file mode 100644
index 0000000..7acddd4
--- /dev/null
+++ b/blimp/client/input/blimp_input_manager.h
@@ -0,0 +1,106 @@
+// 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_CLIENT_INPUT_BLIMP_INPUT_MANAGER_H_
+#define BLIMP_CLIENT_INPUT_BLIMP_INPUT_MANAGER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "blimp/client/input/blimp_input_handler_wrapper.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "ui/events/gesture_detection/filtered_gesture_provider.h"
+#include "ui/events/gesture_detection/motion_event.h"
+
+namespace blimp {
+
+class BlimpInputManagerClient {
+ public:
+  virtual void SendWebInputEvent(
+      const blink::WebInputEvent& input_event) = 0;
+};
+
+// The BlimpInputManager handles input events for a specific web widget. The
+// class processes ui::events to generate web input events which are forwarded
+// to the compositor to be handled on the compositor thread. If the event can
+// not be handled locally by the compositor, it is given to the
+// BlimpInputManagerClient to be sent to the engine.
+//
+// The BlimpInputManager is created and destroyed on the main thread but can be
+// called from the main or compositor thread. It is safe for the
+// BlimpInputManager to be called on the compositor thread because:
+// 1) The only compositor threaded callers of the BlimpInputManager are the
+// BlimpInputManager itself.
+// 2) BlimpInputManager blocks the main thread in its dtor to ensure that all
+// tasks queued to call it on the compositor thread have been run before it is
+// destroyed on the main thread.
+//
+// It is *important* to destroy the cc::InputHandler on the compositor thread
+// before destroying the BlimpInputManager.
+
+class BlimpInputManager : public ui::GestureProviderClient {
+ public:
+  static scoped_ptr<BlimpInputManager> Create(
+      BlimpInputManagerClient* client,
+      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+      scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
+      const base::WeakPtr<cc::InputHandler>& input_handler);
+
+  ~BlimpInputManager() override;
+
+  // Called to process a ui::MotionEvent. Returns true if the event was
+  // successfully processed.
+  bool OnTouchEvent(const ui::MotionEvent& motion_event);
+
+  // Called by the BlimpInputHandlerWrapper after an input event was handled on
+  // the compositor thread.
+  // |consumed| is false if the event was not handled by the compositor and
+  // should be sent to the engine.
+  void DidHandleWebInputEvent(const blink::WebInputEvent& input_event,
+                              bool consumed);
+
+ private:
+  BlimpInputManager(
+      BlimpInputManagerClient* client,
+      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+      scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
+      const base::WeakPtr<cc::InputHandler>& input_handler);
+
+  // ui::GestureProviderClient implementation.
+  void OnGestureEvent(const ui::GestureEventData& gesture) override;
+
+  // Called on the compositor thread.
+  void CreateInputHandlerWrapperOnCompositorThread(
+      base::WeakPtr<BlimpInputManager> input_manager_weak_ptr,
+      const base::WeakPtr<cc::InputHandler>& input_handler);
+  void HandleWebInputEventOnCompositorThread(
+      const blink::WebInputEvent& input_event);
+  void ShutdownOnCompositorThread(base::WaitableEvent* shutdown_event);
+
+  bool IsMainThread() const;
+  bool IsCompositorThread() const;
+
+  BlimpInputManagerClient* client_;
+
+  ui::FilteredGestureProvider gesture_provider_;
+
+  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
+
+  // Used for debug assertions to ensure that the main thread is blocked during
+  // shutdown. Set in the destructor before the main thread is blocked and
+  // read in ShutdownOnCompositorThread.
+  bool main_thread_blocked_;
+
+  scoped_ptr<BlimpInputHandlerWrapper> input_handler_wrapper_;
+
+  base::WeakPtrFactory<BlimpInputManager> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(BlimpInputManager);
+};
+
+}  // namespace blimp
+
+#endif  // BLIMP_CLIENT_INPUT_BLIMP_INPUT_MANAGER_H_
diff --git a/blimp/client/navigation_message_processor.cc b/blimp/client/navigation_message_processor.cc
deleted file mode 100644
index 8181060..0000000
--- a/blimp/client/navigation_message_processor.cc
+++ /dev/null
@@ -1,138 +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 "blimp/client/navigation_message_processor.h"
-
-#include "blimp/common/proto/blimp_message.pb.h"
-#include "blimp/common/proto/navigation.pb.h"
-#include "net/base/net_errors.h"
-#include "url/gurl.h"
-
-namespace blimp {
-
-NavigationMessageProcessor::NavigationMessageProcessor(
-    BlimpMessageProcessor* outgoing_message_processor)
-    : outgoing_message_processor_(outgoing_message_processor) {
-}
-
-NavigationMessageProcessor::~NavigationMessageProcessor() {
-}
-
-void NavigationMessageProcessor::SetDelegate(
-    int tab_id,
-    NavigationMessageDelegate* delegate) {
-  DCHECK(!FindDelegate(tab_id));
-  delegates_[tab_id] = delegate;
-}
-
-void NavigationMessageProcessor::RemoveDelegate(int tab_id) {
-  DelegateMap::iterator it = delegates_.find(tab_id);
-  if (it != delegates_.end())
-    delegates_.erase(it);
-}
-
-void NavigationMessageProcessor::NavigateToUrlText(
-    int tab_id,
-    const std::string& url_text) {
-  scoped_ptr<BlimpMessage> blimp_message(new BlimpMessage);
-  blimp_message->set_target_tab_id(tab_id);
-
-  NavigationMessage* navigation_message = blimp_message->mutable_navigation();
-  navigation_message->set_type(NavigationMessage::LOAD_URL);
-  navigation_message->mutable_load_url()->set_url(url_text);
-
-  outgoing_message_processor_->ProcessMessage(std::move(blimp_message),
-                                              net::CompletionCallback());
-}
-
-void NavigationMessageProcessor::Reload(int tab_id) {
-  scoped_ptr<BlimpMessage> blimp_message(new BlimpMessage);
-  blimp_message->set_target_tab_id(tab_id);
-
-  NavigationMessage* navigation_message = blimp_message->mutable_navigation();
-  navigation_message->set_type(NavigationMessage::RELOAD);
-
-  outgoing_message_processor_->ProcessMessage(std::move(blimp_message),
-                                              net::CompletionCallback());
-}
-
-void NavigationMessageProcessor::GoForward(int tab_id) {
-  scoped_ptr<BlimpMessage> blimp_message(new BlimpMessage);
-  blimp_message->set_target_tab_id(tab_id);
-
-  NavigationMessage* navigation_message = blimp_message->mutable_navigation();
-  navigation_message->set_type(NavigationMessage::GO_FORWARD);
-
-  outgoing_message_processor_->ProcessMessage(std::move(blimp_message),
-                                              net::CompletionCallback());
-}
-
-void NavigationMessageProcessor::GoBack(int tab_id) {
-  scoped_ptr<BlimpMessage> blimp_message(new BlimpMessage);
-  blimp_message->set_target_tab_id(tab_id);
-
-  NavigationMessage* navigation_message = blimp_message->mutable_navigation();
-  navigation_message->set_type(NavigationMessage::GO_BACK);
-
-  outgoing_message_processor_->ProcessMessage(std::move(blimp_message),
-                                              net::CompletionCallback());
-}
-
-void NavigationMessageProcessor::ProcessMessage(
-    scoped_ptr<BlimpMessage> message,
-    const net::CompletionCallback& callback) {
-  DCHECK(message->type() == BlimpMessage::NAVIGATION);
-
-  int tab_id = message->target_tab_id();
-  DCHECK(message->has_navigation());
-  const NavigationMessage& navigation_message = message->navigation();
-
-  NavigationMessageDelegate* delegate = FindDelegate(tab_id);
-  DCHECK(delegate);
-  if (!delegate)
-    return;
-
-  switch (navigation_message.type()) {
-    case NavigationMessage::NAVIGATION_STATE_CHANGED:
-      {
-        const NavigationStateChangeMessage& details =
-            navigation_message.navigation_state_change();
-        if (details.has_url())
-          delegate->OnUrlChanged(tab_id, GURL(details.url()));
-
-        if (details.has_title())
-          delegate->OnTitleChanged(tab_id, details.title());
-
-        if (details.has_loading())
-          delegate->OnLoadingChanged(tab_id, details.loading());
-
-        if (details.has_favicon()) {
-          NOTIMPLEMENTED();
-        }
-      }
-      break;
-    case NavigationMessage::LOAD_URL:
-    case NavigationMessage::GO_BACK:
-    case NavigationMessage::GO_FORWARD:
-    case NavigationMessage::RELOAD:
-      NOTREACHED() << "Client received unexpected navigation type.";
-      break;
-    case NavigationMessage::UNKNOWN:
-      NOTREACHED();
-  }
-
-  if (!callback.is_null())
-    callback.Run(net::OK);
-}
-
-NavigationMessageProcessor::NavigationMessageDelegate*
-NavigationMessageProcessor::FindDelegate(
-    const int tab_id) {
-  DelegateMap::const_iterator it = delegates_.find(tab_id);
-  if (it != delegates_.end())
-    return it->second;
-  return nullptr;
-}
-
-}  // namespace blimp
diff --git a/blimp/client/navigation_message_processor_unittest.cc b/blimp/client/navigation_message_processor_unittest.cc
deleted file mode 100644
index 926ee5f..0000000
--- a/blimp/client/navigation_message_processor_unittest.cc
+++ /dev/null
@@ -1,157 +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 "blimp/client/navigation_message_processor.h"
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "blimp/common/proto/blimp_message.pb.h"
-#include "blimp/net/test_common.h"
-#include "net/base/net_errors.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "url/gurl.h"
-
-using testing::_;
-
-namespace blimp {
-
-class MockNavigationMessageDelegate
-    : public NavigationMessageProcessor::NavigationMessageDelegate {
- public:
-  // NavigationMessageDelegate implementation.
-  MOCK_METHOD2(OnUrlChanged, void(int tab_id, const GURL& url));
-  MOCK_METHOD2(OnFaviconChanged, void(int tab_id, const SkBitmap& favicon));
-  MOCK_METHOD2(OnTitleChanged, void(int tab_id, const std::string& title));
-  MOCK_METHOD2(OnLoadingChanged, void(int tab_id, bool loading));
-};
-
-void SendMockNavigationStateChangedMessage(BlimpMessageProcessor* processor,
-                                           int tab_id,
-                                           const GURL* url,
-                                           const std::string* title,
-                                           const bool* loading) {
-  scoped_ptr<BlimpMessage> message(new BlimpMessage);
-  message->set_type(BlimpMessage::NAVIGATION);
-  message->set_target_tab_id(tab_id);
-
-  NavigationMessage* details = message->mutable_navigation();
-  details->set_type(NavigationMessage::NAVIGATION_STATE_CHANGED);
-
-  NavigationStateChangeMessage* state =
-      details->mutable_navigation_state_change();
-  if (url)
-    state->set_url(url->spec());
-
-  if (title)
-    state->set_title(*title);
-
-  if (loading)
-    state->set_loading(*loading);
-
-  processor->ProcessMessage(std::move(message), net::CompletionCallback());
-}
-
-MATCHER_P2(EqualsNavigateToUrlText, tab_id, text, "") {
-  return arg.target_tab_id() == tab_id &&
-      arg.navigation().type() == NavigationMessage::LOAD_URL &&
-      arg.navigation().load_url().url() == text;
-}
-
-MATCHER_P(EqualsNavigateForward, tab_id, "") {
-  return arg.target_tab_id() == tab_id &&
-      arg.navigation().type() == NavigationMessage::GO_FORWARD;
-}
-
-MATCHER_P(EqualsNavigateBack, tab_id, "") {
-  return arg.target_tab_id() == tab_id &&
-      arg.navigation().type() == NavigationMessage::GO_BACK;
-}
-
-MATCHER_P(EqualsNavigateReload, tab_id, "") {
-  return arg.target_tab_id() == tab_id &&
-      arg.navigation().type() == NavigationMessage::RELOAD;
-}
-
-
-class NavigationMessageProcessorTest : public testing::Test {
- public:
-  NavigationMessageProcessorTest()
-      : processor_(&out_processor_) {}
-
-  void SetUp() override {
-    processor_.SetDelegate(1, &delegate1_);
-    processor_.SetDelegate(2, &delegate2_);
-  }
-
- protected:
-  MockBlimpMessageProcessor out_processor_;
-  MockNavigationMessageDelegate delegate1_;
-  MockNavigationMessageDelegate delegate2_;
-
-  NavigationMessageProcessor processor_;
-};
-
-TEST_F(NavigationMessageProcessorTest, DispatchesToCorrectDelegate) {
-  GURL url("https://www.google.com");
-  EXPECT_CALL(delegate1_, OnUrlChanged(1, url)).Times(1);
-  SendMockNavigationStateChangedMessage(
-      &processor_, 1, &url, nullptr, nullptr);
-
-  EXPECT_CALL(delegate2_, OnUrlChanged(2, url)).Times(1);
-  SendMockNavigationStateChangedMessage(
-      &processor_, 2, &url, nullptr, nullptr);
-}
-
-TEST_F(NavigationMessageProcessorTest, AllDelegateFieldsCalled) {
-  GURL url("https://www.google.com");
-  std::string title = "Google";
-  bool loading = true;
-
-  EXPECT_CALL(delegate1_, OnUrlChanged(1, url)).Times(1);
-  EXPECT_CALL(delegate1_, OnTitleChanged(1, title)).Times(1);
-  EXPECT_CALL(delegate1_, OnLoadingChanged(1, loading)).Times(1);
-  SendMockNavigationStateChangedMessage(&processor_, 1, &url, &title, &loading);
-}
-
-TEST_F(NavigationMessageProcessorTest, PartialDelegateFieldsCalled) {
-  std::string title = "Google";
-  bool loading = true;
-
-  EXPECT_CALL(delegate1_, OnUrlChanged(_, _)).Times(0);
-  EXPECT_CALL(delegate1_, OnTitleChanged(1, title)).Times(1);
-  EXPECT_CALL(delegate1_, OnLoadingChanged(1, loading)).Times(1);
-  SendMockNavigationStateChangedMessage(
-      &processor_, 1, nullptr, &title, &loading);
-}
-
-TEST_F(NavigationMessageProcessorTest, TestNavigateToUrlMessage) {
-  std::string text = "text";
-
-  EXPECT_CALL(out_processor_,
-              MockableProcessMessage(
-                  EqualsNavigateToUrlText(1, text), _)).Times(1);
-  processor_.NavigateToUrlText(1, text);
-}
-
-TEST_F(NavigationMessageProcessorTest, TestNavigateForwardMessage) {
-  EXPECT_CALL(out_processor_,
-              MockableProcessMessage(EqualsNavigateForward(1), _)).Times(1);
-  processor_.GoForward(1);
-}
-
-TEST_F(NavigationMessageProcessorTest, TestNavigateBackMessage) {
-  EXPECT_CALL(out_processor_,
-              MockableProcessMessage(EqualsNavigateBack(1), _)).Times(1);
-  processor_.GoBack(1);
-}
-
-TEST_F(NavigationMessageProcessorTest, TestNavigateReloadMessage) {
-  EXPECT_CALL(out_processor_,
-              MockableProcessMessage(EqualsNavigateReload(1), _)).Times(1);
-  processor_.Reload(1);
-}
-
-}  // namespace blimp
diff --git a/blimp/client/session/blimp_client_session.cc b/blimp/client/session/blimp_client_session.cc
new file mode 100644
index 0000000..f0fcd39
--- /dev/null
+++ b/blimp/client/session/blimp_client_session.cc
@@ -0,0 +1,52 @@
+// 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/client/session/blimp_client_session.h"
+
+#include "blimp/client/session/navigation_feature.h"
+#include "blimp/client/session/render_widget_feature.h"
+#include "blimp/client/session/tab_control_feature.h"
+#include "blimp/net/browser_connection_handler.h"
+
+namespace blimp {
+
+BlimpClientSession::BlimpClientSession()
+    : connection_handler_(new BrowserConnectionHandler),
+      tab_control_feature_(new TabControlFeature),
+      navigation_feature_(new NavigationFeature),
+      render_widget_feature_(new RenderWidgetFeature) {
+  // Connect the features with the network layer.
+  tab_control_feature_->set_outgoing_message_processor(
+        connection_handler_->RegisterFeature(BlimpMessage::CONTROL,
+                                             tab_control_feature_.get()));
+  navigation_feature_->set_outgoing_message_processor(
+      connection_handler_->RegisterFeature(BlimpMessage::NAVIGATION,
+                                           navigation_feature_.get()));
+  render_widget_feature_->set_outgoing_input_message_processor(
+      connection_handler_->RegisterFeature(BlimpMessage::INPUT,
+                                           render_widget_feature_.get()));
+  render_widget_feature_->set_outgoing_compositor_message_processor(
+      connection_handler_->RegisterFeature(BlimpMessage::COMPOSITOR,
+                                           render_widget_feature_.get()));
+  // We don't expect to send any RenderWidget messages, so don't save the
+  // outgoing BlimpMessageProcessor in the RenderWidgetFeature.
+  connection_handler_->RegisterFeature(BlimpMessage::RENDER_WIDGET,
+                                       render_widget_feature_.get());
+}
+
+BlimpClientSession::~BlimpClientSession() {}
+
+TabControlFeature* BlimpClientSession::GetTabControlFeature() const {
+  return tab_control_feature_.get();
+}
+
+NavigationFeature* BlimpClientSession::GetNavigationFeature() const {
+  return navigation_feature_.get();
+}
+
+RenderWidgetFeature* BlimpClientSession::GetRenderWidgetFeature() const {
+  return render_widget_feature_.get();
+}
+
+}  // namespace blimp
diff --git a/blimp/client/session/blimp_client_session.h b/blimp/client/session/blimp_client_session.h
new file mode 100644
index 0000000..da8e74a
--- /dev/null
+++ b/blimp/client/session/blimp_client_session.h
@@ -0,0 +1,52 @@
+// 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_CLIENT_SESSION_BLIMP_CLIENT_SESSION_H_
+#define BLIMP_CLIENT_SESSION_BLIMP_CLIENT_SESSION_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "blimp/client/blimp_client_export.h"
+
+namespace blimp {
+
+class BrowserConnectionHandler;
+class NavigationFeature;
+class RenderWidgetFeature;
+class TabControlFeature;
+
+// BlimpClientSession represents a single active session of Blimp on the client
+// regardless of whether or not the client application is in the background or
+// foreground.  The only time this session is invalid is during initialization
+// and shutdown of this particular client process (or Activity on Android).
+//
+// This session glues together the feature proxy components and the network
+// layer.  The network components must be interacted with on the IO thread.  The
+// feature proxies must be interacted with on the UI thread.
+class BLIMP_CLIENT_EXPORT BlimpClientSession {
+ public:
+  BlimpClientSession();
+
+  TabControlFeature* GetTabControlFeature() const;
+  NavigationFeature* GetNavigationFeature() const;
+  RenderWidgetFeature* GetRenderWidgetFeature() const;
+
+ protected:
+  virtual ~BlimpClientSession();
+
+ private:
+  // The BrowserConnectionHandler is here so that the BlimpClientSession can
+  // glue the feature-specific handlers to the actual network connection.
+  scoped_ptr<BrowserConnectionHandler> connection_handler_;
+
+  scoped_ptr<TabControlFeature> tab_control_feature_;
+  scoped_ptr<NavigationFeature> navigation_feature_;
+  scoped_ptr<RenderWidgetFeature> render_widget_feature_;
+
+  DISALLOW_COPY_AND_ASSIGN(BlimpClientSession);
+};
+
+}  // namespace blimp
+
+#endif  // BLIMP_CLIENT_SESSION_BLIMP_CLIENT_SESSION_H_
diff --git a/blimp/client/session/blimp_client_session_android.cc b/blimp/client/session/blimp_client_session_android.cc
new file mode 100644
index 0000000..a877877
--- /dev/null
+++ b/blimp/client/session/blimp_client_session_android.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 "blimp/client/session/blimp_client_session_android.h"
+
+#include "jni/BlimpClientSession_jni.h"
+
+namespace blimp {
+
+static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& jobj) {
+  return reinterpret_cast<intptr_t>(new BlimpClientSessionAndroid(env, jobj));
+}
+
+// static
+bool BlimpClientSessionAndroid::RegisterJni(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+// static
+BlimpClientSessionAndroid* BlimpClientSessionAndroid::FromJavaObject(
+    JNIEnv* env,
+    jobject jobj) {
+  return reinterpret_cast<BlimpClientSessionAndroid*>(
+      Java_BlimpClientSession_getNativePtr(env, jobj));
+}
+
+BlimpClientSessionAndroid::BlimpClientSessionAndroid(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& jobj)
+    : BlimpClientSession() {
+  java_obj_.Reset(env, jobj);
+}
+
+BlimpClientSessionAndroid::~BlimpClientSessionAndroid() {}
+
+void BlimpClientSessionAndroid::Destroy(JNIEnv* env, jobject jobj) {
+  delete this;
+}
+
+}  // namespace blimp
diff --git a/blimp/client/session/blimp_client_session_android.h b/blimp/client/session/blimp_client_session_android.h
new file mode 100644
index 0000000..fe552bf
--- /dev/null
+++ b/blimp/client/session/blimp_client_session_android.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 BLIMP_CLIENT_SESSION_BLIMP_CLIENT_SESSION_ANDROID_H_
+#define BLIMP_CLIENT_SESSION_BLIMP_CLIENT_SESSION_ANDROID_H_
+
+#include "base/android/jni_android.h"
+#include "base/macros.h"
+#include "blimp/client/session/blimp_client_session.h"
+
+namespace blimp {
+
+class BlimpClientSessionAndroid : public BlimpClientSession {
+ public:
+  static bool RegisterJni(JNIEnv* env);
+  static BlimpClientSessionAndroid* FromJavaObject(JNIEnv* env, jobject jobj);
+
+  BlimpClientSessionAndroid(JNIEnv* env,
+                            const base::android::JavaParamRef<jobject>& jobj);
+
+  // Methods called from Java via JNI.
+  void Destroy(JNIEnv* env, jobject jobj);
+
+ private:
+  ~BlimpClientSessionAndroid() override;
+
+  // Reference to the Java object which owns this class.
+  base::android::ScopedJavaGlobalRef<jobject> java_obj_;
+
+  DISALLOW_COPY_AND_ASSIGN(BlimpClientSessionAndroid);
+};
+
+}  // namespace blimp
+
+#endif  // BLIMP_CLIENT_SESSION_BLIMP_CLIENT_SESSION_ANDROID_H_
diff --git a/blimp/client/session/navigation_feature.cc b/blimp/client/session/navigation_feature.cc
new file mode 100644
index 0000000..65318f7
--- /dev/null
+++ b/blimp/client/session/navigation_feature.cc
@@ -0,0 +1,130 @@
+// 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/client/session/navigation_feature.h"
+
+#include "blimp/common/create_blimp_message.h"
+#include "blimp/common/proto/blimp_message.pb.h"
+#include "blimp/common/proto/navigation.pb.h"
+#include "net/base/net_errors.h"
+#include "url/gurl.h"
+
+namespace blimp {
+
+NavigationFeature::NavigationFeature() {}
+
+NavigationFeature::~NavigationFeature() {}
+
+void NavigationFeature::set_outgoing_message_processor(
+    scoped_ptr<BlimpMessageProcessor> processor) {
+  outgoing_message_processor_ = std::move(processor);
+}
+
+void NavigationFeature::SetDelegate(int tab_id,
+                                    NavigationFeatureDelegate* delegate) {
+  DCHECK(!FindDelegate(tab_id));
+  delegates_[tab_id] = delegate;
+}
+
+void NavigationFeature::RemoveDelegate(int tab_id) {
+  DelegateMap::iterator it = delegates_.find(tab_id);
+  if (it != delegates_.end())
+    delegates_.erase(it);
+}
+
+void NavigationFeature::NavigateToUrlText(int tab_id,
+                                          const std::string& url_text) {
+  NavigationMessage* navigation_message;
+  scoped_ptr<BlimpMessage> blimp_message =
+      CreateBlimpMessage(&navigation_message, tab_id);
+  navigation_message->set_type(NavigationMessage::LOAD_URL);
+  navigation_message->mutable_load_url()->set_url(url_text);
+  outgoing_message_processor_->ProcessMessage(std::move(blimp_message),
+                                              net::CompletionCallback());
+}
+
+void NavigationFeature::Reload(int tab_id) {
+  NavigationMessage* navigation_message;
+  scoped_ptr<BlimpMessage> blimp_message =
+      CreateBlimpMessage(&navigation_message, tab_id);
+  navigation_message->set_type(NavigationMessage::RELOAD);
+
+  outgoing_message_processor_->ProcessMessage(std::move(blimp_message),
+                                              net::CompletionCallback());
+}
+
+void NavigationFeature::GoForward(int tab_id) {
+  NavigationMessage* navigation_message;
+  scoped_ptr<BlimpMessage> blimp_message =
+      CreateBlimpMessage(&navigation_message, tab_id);
+  navigation_message->set_type(NavigationMessage::GO_FORWARD);
+
+  outgoing_message_processor_->ProcessMessage(std::move(blimp_message),
+                                              net::CompletionCallback());
+}
+
+void NavigationFeature::GoBack(int tab_id) {
+  NavigationMessage* navigation_message;
+  scoped_ptr<BlimpMessage> blimp_message =
+      CreateBlimpMessage(&navigation_message, tab_id);
+  navigation_message->set_type(NavigationMessage::GO_BACK);
+
+  outgoing_message_processor_->ProcessMessage(std::move(blimp_message),
+                                              net::CompletionCallback());
+}
+
+void NavigationFeature::ProcessMessage(
+    scoped_ptr<BlimpMessage> message,
+    const net::CompletionCallback& callback) {
+  DCHECK(message->type() == BlimpMessage::NAVIGATION);
+
+  int tab_id = message->target_tab_id();
+  DCHECK(message->has_navigation());
+  const NavigationMessage& navigation_message = message->navigation();
+
+  NavigationFeatureDelegate* delegate = FindDelegate(tab_id);
+  DCHECK(delegate);
+  if (!delegate)
+    return;
+
+  switch (navigation_message.type()) {
+    case NavigationMessage::NAVIGATION_STATE_CHANGED: {
+      const NavigationStateChangeMessage& details =
+          navigation_message.navigation_state_change();
+      if (details.has_url())
+        delegate->OnUrlChanged(tab_id, GURL(details.url()));
+
+      if (details.has_title())
+        delegate->OnTitleChanged(tab_id, details.title());
+
+      if (details.has_loading())
+        delegate->OnLoadingChanged(tab_id, details.loading());
+
+      if (details.has_favicon()) {
+        NOTIMPLEMENTED();
+      }
+    } break;
+    case NavigationMessage::LOAD_URL:
+    case NavigationMessage::GO_BACK:
+    case NavigationMessage::GO_FORWARD:
+    case NavigationMessage::RELOAD:
+      NOTREACHED() << "Client received unexpected navigation type.";
+      break;
+    case NavigationMessage::UNKNOWN:
+      NOTREACHED();
+  }
+
+  if (!callback.is_null())
+    callback.Run(net::OK);
+}
+
+NavigationFeature::NavigationFeatureDelegate* NavigationFeature::FindDelegate(
+    const int tab_id) {
+  DelegateMap::const_iterator it = delegates_.find(tab_id);
+  if (it != delegates_.end())
+    return it->second;
+  return nullptr;
+}
+
+}  // namespace blimp
diff --git a/blimp/client/navigation_message_processor.h b/blimp/client/session/navigation_feature.h
similarity index 61%
rename from blimp/client/navigation_message_processor.h
rename to blimp/client/session/navigation_feature.h
index 0e85bdc..91b4ecb 100644
--- a/blimp/client/navigation_message_processor.h
+++ b/blimp/client/session/navigation_feature.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef BLIMP_CLIENT_NAVIGATION_MESSAGE_PROCESSOR_H_
-#define BLIMP_CLIENT_NAVIGATION_MESSAGE_PROCESSOR_H_
+#ifndef BLIMP_CLIENT_SESSION_NAVIGATION_FEATURE_H_
+#define BLIMP_CLIENT_SESSION_NAVIGATION_FEATURE_H_
 
 #include "base/containers/small_map.h"
 #include "base/macros.h"
@@ -18,12 +18,11 @@
 // Handles all incoming and outgoing protobuf messages of type
 // RenderWidget::NAVIGATION.  Delegates can be added to be notified of incoming
 // messages.
-class BLIMP_CLIENT_EXPORT NavigationMessageProcessor
-    : public BlimpMessageProcessor {
+class BLIMP_CLIENT_EXPORT NavigationFeature : public BlimpMessageProcessor {
  public:
   // A delegate to be notified of specific navigation events related to a
   // a particular tab.
-  class NavigationMessageDelegate {
+  class NavigationFeatureDelegate {
    public:
     virtual void OnUrlChanged(int tab_id, const GURL& url) = 0;
     virtual void OnFaviconChanged(int tab_id, const SkBitmap& favicon) = 0;
@@ -31,13 +30,17 @@
     virtual void OnLoadingChanged(int tab_id, bool loading) = 0;
   };
 
-  explicit NavigationMessageProcessor(
-      BlimpMessageProcessor* outgoing_message_processor);
-  ~NavigationMessageProcessor() override;
+  NavigationFeature();
+  ~NavigationFeature() override;
+
+  // Set the BlimpMessageProcessor that will be used to send
+  // BlimpMessage::NAVIGATION messages to the engine.
+  void set_outgoing_message_processor(
+      scoped_ptr<BlimpMessageProcessor> processor);
 
   // Sets a NavigationMessageDelegate to be notified of all navigation messages
   // for |tab_id| from the engine.
-  void SetDelegate(int tab_id, NavigationMessageDelegate* delegate);
+  void SetDelegate(int tab_id, NavigationFeatureDelegate* delegate);
   void RemoveDelegate(int tab_id);
 
   void NavigateToUrlText(int tab_id, const std::string& url_text);
@@ -45,22 +48,23 @@
   void GoForward(int tab_id);
   void GoBack(int tab_id);
 
+ private:
   // BlimpMessageProcessor implementation.
   void ProcessMessage(scoped_ptr<BlimpMessage> message,
                       const net::CompletionCallback& callback) override;
- private:
-  NavigationMessageDelegate* FindDelegate(const int tab_id);
 
-  typedef base::SmallMap<std::map<int, NavigationMessageDelegate*> >
-      DelegateMap;
+  NavigationFeatureDelegate* FindDelegate(const int tab_id);
+
+  typedef base::SmallMap<std::map<int, NavigationFeatureDelegate*>> DelegateMap;
 
   DelegateMap delegates_;
 
-  BlimpMessageProcessor* outgoing_message_processor_;
+  // Used to send BlimpMessage::NAVIGATION messages to the engine.
+  scoped_ptr<BlimpMessageProcessor> outgoing_message_processor_;
 
-  DISALLOW_COPY_AND_ASSIGN(NavigationMessageProcessor);
+  DISALLOW_COPY_AND_ASSIGN(NavigationFeature);
 };
 
 }  // namespace blimp
 
-#endif  // BLIMP_CLIENT_NAVIGATION_MESSAGE_PROCESSOR_H_
+#endif  // BLIMP_CLIENT_SESSION_NAVIGATION_FEATURE_H_
diff --git a/blimp/client/session/navigation_feature_unittest.cc b/blimp/client/session/navigation_feature_unittest.cc
new file mode 100644
index 0000000..e739652
--- /dev/null
+++ b/blimp/client/session/navigation_feature_unittest.cc
@@ -0,0 +1,158 @@
+// 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/client/session/navigation_feature.h"
+
+#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/net/test_common.h"
+#include "net/base/net_errors.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "url/gurl.h"
+
+using testing::_;
+
+namespace blimp {
+
+class MockNavigationFeatureDelegate
+    : public NavigationFeature::NavigationFeatureDelegate {
+ public:
+  // NavigationFeatureDelegate implementation.
+  MOCK_METHOD2(OnUrlChanged, void(int tab_id, const GURL& url));
+  MOCK_METHOD2(OnFaviconChanged, void(int tab_id, const SkBitmap& favicon));
+  MOCK_METHOD2(OnTitleChanged, void(int tab_id, const std::string& title));
+  MOCK_METHOD2(OnLoadingChanged, void(int tab_id, bool loading));
+};
+
+void SendMockNavigationStateChangedMessage(BlimpMessageProcessor* processor,
+                                           int tab_id,
+                                           const GURL* url,
+                                           const std::string* title,
+                                           const bool* loading) {
+  NavigationMessage* navigation_message;
+  scoped_ptr<BlimpMessage> message =
+      CreateBlimpMessage(&navigation_message, tab_id);
+  navigation_message->set_type(NavigationMessage::NAVIGATION_STATE_CHANGED);
+  NavigationStateChangeMessage* state =
+      navigation_message->mutable_navigation_state_change();
+  if (url)
+    state->set_url(url->spec());
+
+  if (title)
+    state->set_title(*title);
+
+  if (loading)
+    state->set_loading(*loading);
+
+  processor->ProcessMessage(std::move(message), net::CompletionCallback());
+}
+
+MATCHER_P2(EqualsNavigateToUrlText, tab_id, text, "") {
+  return arg.target_tab_id() == tab_id &&
+         arg.navigation().type() == NavigationMessage::LOAD_URL &&
+         arg.navigation().load_url().url() == text;
+}
+
+MATCHER_P(EqualsNavigateForward, tab_id, "") {
+  return arg.target_tab_id() == tab_id &&
+         arg.navigation().type() == NavigationMessage::GO_FORWARD;
+}
+
+MATCHER_P(EqualsNavigateBack, tab_id, "") {
+  return arg.target_tab_id() == tab_id &&
+         arg.navigation().type() == NavigationMessage::GO_BACK;
+}
+
+MATCHER_P(EqualsNavigateReload, tab_id, "") {
+  return arg.target_tab_id() == tab_id &&
+         arg.navigation().type() == NavigationMessage::RELOAD;
+}
+
+class NavigationFeatureTest : public testing::Test {
+ public:
+  NavigationFeatureTest() : out_processor_(nullptr) {}
+
+  void SetUp() override {
+    out_processor_ = new MockBlimpMessageProcessor();
+    feature_.set_outgoing_message_processor(make_scoped_ptr(out_processor_));
+
+    feature_.SetDelegate(1, &delegate1_);
+    feature_.SetDelegate(2, &delegate2_);
+  }
+
+ protected:
+  // This is a raw pointer to a class that is owned by the NavigationFeature.
+  MockBlimpMessageProcessor* out_processor_;
+
+  MockNavigationFeatureDelegate delegate1_;
+  MockNavigationFeatureDelegate delegate2_;
+
+  NavigationFeature feature_;
+};
+
+TEST_F(NavigationFeatureTest, DispatchesToCorrectDelegate) {
+  GURL url("https://www.google.com");
+  EXPECT_CALL(delegate1_, OnUrlChanged(1, url)).Times(1);
+  SendMockNavigationStateChangedMessage(&feature_, 1, &url, nullptr, nullptr);
+
+  EXPECT_CALL(delegate2_, OnUrlChanged(2, url)).Times(1);
+  SendMockNavigationStateChangedMessage(&feature_, 2, &url, nullptr, nullptr);
+}
+
+TEST_F(NavigationFeatureTest, AllDelegateFieldsCalled) {
+  GURL url("https://www.google.com");
+  std::string title = "Google";
+  bool loading = true;
+
+  EXPECT_CALL(delegate1_, OnUrlChanged(1, url)).Times(1);
+  EXPECT_CALL(delegate1_, OnTitleChanged(1, title)).Times(1);
+  EXPECT_CALL(delegate1_, OnLoadingChanged(1, loading)).Times(1);
+  SendMockNavigationStateChangedMessage(&feature_, 1, &url, &title, &loading);
+}
+
+TEST_F(NavigationFeatureTest, PartialDelegateFieldsCalled) {
+  std::string title = "Google";
+  bool loading = true;
+
+  EXPECT_CALL(delegate1_, OnUrlChanged(_, _)).Times(0);
+  EXPECT_CALL(delegate1_, OnTitleChanged(1, title)).Times(1);
+  EXPECT_CALL(delegate1_, OnLoadingChanged(1, loading)).Times(1);
+  SendMockNavigationStateChangedMessage(&feature_, 1, nullptr, &title,
+                                        &loading);
+}
+
+TEST_F(NavigationFeatureTest, TestNavigateToUrlMessage) {
+  std::string text = "text";
+
+  EXPECT_CALL(*out_processor_,
+              MockableProcessMessage(EqualsNavigateToUrlText(1, text), _))
+      .Times(1);
+  feature_.NavigateToUrlText(1, text);
+}
+
+TEST_F(NavigationFeatureTest, TestNavigateForwardMessage) {
+  EXPECT_CALL(*out_processor_,
+              MockableProcessMessage(EqualsNavigateForward(1), _))
+      .Times(1);
+  feature_.GoForward(1);
+}
+
+TEST_F(NavigationFeatureTest, TestNavigateBackMessage) {
+  EXPECT_CALL(*out_processor_, MockableProcessMessage(EqualsNavigateBack(1), _))
+      .Times(1);
+  feature_.GoBack(1);
+}
+
+TEST_F(NavigationFeatureTest, TestNavigateReloadMessage) {
+  EXPECT_CALL(*out_processor_,
+              MockableProcessMessage(EqualsNavigateReload(1), _))
+      .Times(1);
+  feature_.Reload(1);
+}
+
+}  // namespace blimp
diff --git a/blimp/client/session/render_widget_feature.cc b/blimp/client/session/render_widget_feature.cc
new file mode 100644
index 0000000..8a5d294
--- /dev/null
+++ b/blimp/client/session/render_widget_feature.cc
@@ -0,0 +1,134 @@
+// 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/client/session/render_widget_feature.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"
+#include "blimp/common/proto/render_widget.pb.h"
+#include "cc/proto/compositor_message.pb.h"
+#include "net/base/net_errors.h"
+
+namespace blimp {
+
+RenderWidgetFeature::RenderWidgetFeature() {}
+
+RenderWidgetFeature::~RenderWidgetFeature() {}
+
+void RenderWidgetFeature::set_outgoing_input_message_processor(
+    scoped_ptr<BlimpMessageProcessor> processor) {
+  outgoing_input_message_processor_ = std::move(processor);
+}
+
+void RenderWidgetFeature::set_outgoing_compositor_message_processor(
+    scoped_ptr<BlimpMessageProcessor> processor) {
+  outgoing_compositor_message_processor_ = std::move(processor);
+}
+
+void RenderWidgetFeature::SendInputEvent(const int tab_id,
+                                         const blink::WebInputEvent& event) {
+  scoped_ptr<BlimpMessage> blimp_message =
+      input_message_generator_.GenerateMessage(event);
+
+  // Don't send unsupported WebInputEvents.
+  if (!blimp_message)
+    return;
+
+  blimp_message->set_target_tab_id(tab_id);
+  blimp_message->mutable_input()->set_render_widget_id(
+      GetRenderWidgetId(tab_id));
+
+  outgoing_input_message_processor_->ProcessMessage(std::move(blimp_message),
+                                                    net::CompletionCallback());
+}
+
+void RenderWidgetFeature::SendCompositorMessage(
+    const int tab_id,
+    const cc::proto::CompositorMessage& message) {
+  CompositorMessage* compositor_message;
+  scoped_ptr<BlimpMessage> blimp_message =
+      CreateBlimpMessage(&compositor_message, tab_id);
+
+  uint32_t render_widget_id = GetRenderWidgetId(tab_id);
+  DCHECK_LT(0U, render_widget_id);
+  compositor_message->set_render_widget_id(render_widget_id);
+  compositor_message->mutable_payload()->resize(
+      base::checked_cast<size_t>(message.ByteSize()));
+  if (message.SerializeToString(compositor_message->mutable_payload())) {
+    outgoing_compositor_message_processor_->ProcessMessage(
+        std::move(blimp_message), net::CompletionCallback());
+  } else {
+    LOG(ERROR) << "Unable to serialize compositor proto.";
+  }
+}
+
+void RenderWidgetFeature::SetDelegate(const int tab_id,
+                                      RenderWidgetFeatureDelegate* delegate) {
+  DCHECK(!FindDelegate(tab_id));
+  delegates_[tab_id] = delegate;
+}
+
+void RenderWidgetFeature::RemoveDelegate(const int tab_id) {
+  DelegateMap::iterator it = delegates_.find(tab_id);
+  if (it != delegates_.end())
+    delegates_.erase(it);
+}
+
+void RenderWidgetFeature::ProcessMessage(
+    scoped_ptr<BlimpMessage> message,
+    const net::CompletionCallback& callback) {
+  DCHECK(message->type() == BlimpMessage::RENDER_WIDGET ||
+         message->type() == BlimpMessage::COMPOSITOR);
+
+  int target_tab_id = message->target_tab_id();
+  RenderWidgetFeatureDelegate* delegate = FindDelegate(target_tab_id);
+  DCHECK(delegate);
+  if (!delegate)
+    return;
+
+  switch (message->type()) {
+    case BlimpMessage::RENDER_WIDGET:
+      if (message->render_widget().type() == RenderWidgetMessage::INITIALIZE) {
+        render_widget_ids_[target_tab_id] =
+            message->render_widget().render_widget_id();
+        delegate->OnRenderWidgetInitialized();
+      }
+      break;
+    case BlimpMessage::COMPOSITOR: {
+      DCHECK_EQ(message->compositor().render_widget_id(),
+                GetRenderWidgetId(target_tab_id));
+      scoped_ptr<cc::proto::CompositorMessage> payload(
+          new cc::proto::CompositorMessage);
+      if (payload->ParseFromString(message->compositor().payload())) {
+        delegate->OnCompositorMessageReceived(std::move(payload));
+      }
+    } break;
+    default:
+      NOTIMPLEMENTED();
+  }
+
+  if (!callback.is_null()) {
+    callback.Run(net::OK);
+  }
+}
+
+RenderWidgetFeature::RenderWidgetFeatureDelegate*
+RenderWidgetFeature::FindDelegate(const int tab_id) {
+  DelegateMap::const_iterator it = delegates_.find(tab_id);
+  if (it != delegates_.end())
+    return it->second;
+  return nullptr;
+}
+
+uint32_t RenderWidgetFeature::GetRenderWidgetId(const int tab_id) {
+  RenderWidgetIdMap::const_iterator it = render_widget_ids_.find(tab_id);
+  if (it != render_widget_ids_.end())
+    return it->second;
+  return 0U;
+}
+
+}  // namespace blimp
diff --git a/blimp/client/compositor/render_widget_message_processor.h b/blimp/client/session/render_widget_feature.h
similarity index 65%
rename from blimp/client/compositor/render_widget_message_processor.h
rename to blimp/client/session/render_widget_feature.h
index 4b4a4ce5..25d7371 100644
--- a/blimp/client/compositor/render_widget_message_processor.h
+++ b/blimp/client/session/render_widget_feature.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef BLIMP_CLIENT_COMPOSITOR_RENDER_WIDGET_MESSAGE_PROCESSOR_H_
-#define BLIMP_CLIENT_COMPOSITOR_RENDER_WIDGET_MESSAGE_PROCESSOR_H_
+#ifndef BLIMP_CLIENT_SESSION_RENDER_WIDGET_FEATURE_H_
+#define BLIMP_CLIENT_SESSION_RENDER_WIDGET_FEATURE_H_
 
 #include "base/containers/small_map.h"
 #include "base/macros.h"
@@ -30,11 +30,10 @@
 // notified of incoming messages. This class automatically attaches a specific
 // id so that the engine can drop stale RenderWidget related messages after it
 // sends a RenderWidgetMessage::INITIALIZE message.
-class BLIMP_CLIENT_EXPORT RenderWidgetMessageProcessor
-    : public BlimpMessageProcessor {
+class BLIMP_CLIENT_EXPORT RenderWidgetFeature : public BlimpMessageProcessor {
  public:
   // A delegate to be notified of specific RenderWidget related incoming events.
-  class RenderWidgetMessageDelegate {
+  class RenderWidgetFeatureDelegate {
    public:
     // Called when the engine's RenderWidget has changed for a particular
     // WebContents.  When this is received all state related to the existing
@@ -47,10 +46,18 @@
         scoped_ptr<cc::proto::CompositorMessage> message) = 0;
   };
 
-  RenderWidgetMessageProcessor(
-      BlimpMessageProcessor* input_message_processor,
-      BlimpMessageProcessor* compositor_message_processor);
-  ~RenderWidgetMessageProcessor() override;
+  RenderWidgetFeature();
+  ~RenderWidgetFeature() override;
+
+  // Set the BlimpMessageProcessor that will be used to send BlimpMessage::INPUT
+  // messages to the engine.
+  void set_outgoing_input_message_processor(
+      scoped_ptr<BlimpMessageProcessor> processor);
+
+  // Set the BlimpMessageProcessor that will be used to send
+  // BlimpMessage::COMPOSITOR messages to the engine.
+  void set_outgoing_compositor_message_processor(
+      scoped_ptr<BlimpMessageProcessor> processor);
 
   // Sends a WebInputEvent for |tab_id| to the engine.
   void SendInputEvent(const int tab_id, const blink::WebInputEvent& event);
@@ -62,35 +69,38 @@
   // Sets a RenderWidgetMessageDelegate to be notified of all incoming
   // RenderWidget related messages for |tab_id| from the engine.  There can only
   // be one RenderWidgetMessageDelegate per tab.
-  void SetDelegate(const int tab_id, RenderWidgetMessageDelegate* delegate);
+  void SetDelegate(const int tab_id, RenderWidgetFeatureDelegate* delegate);
   void RemoveDelegate(const int tab_id);
 
+ private:
   // BlimpMessageProcessor implementation.
   void ProcessMessage(scoped_ptr<BlimpMessage> message,
                       const net::CompletionCallback& callback) override;
 
- private:
   // Returns nullptr if no delegate is found.
-  RenderWidgetMessageDelegate* FindDelegate(const int tab_id);
+  RenderWidgetFeatureDelegate* FindDelegate(const int tab_id);
 
   // Returns 0 if no id is found.
   uint32_t GetRenderWidgetId(const int tab_id);
 
-  typedef base::SmallMap<std::map<int, RenderWidgetMessageDelegate*> >
+  typedef base::SmallMap<std::map<int, RenderWidgetFeatureDelegate*>>
       DelegateMap;
-  typedef base::SmallMap<std::map<int, uint32_t> > RenderWidgetIdMap;
+  typedef base::SmallMap<std::map<int, uint32_t>> RenderWidgetIdMap;
 
   DelegateMap delegates_;
   RenderWidgetIdMap render_widget_ids_;
 
   InputMessageGenerator input_message_generator_;
 
-  BlimpMessageProcessor* input_message_processor_;
-  BlimpMessageProcessor* compositor_message_processor_;
+  // Used to send BlimpMessage::INPUT type messages to the engine.
+  scoped_ptr<BlimpMessageProcessor> outgoing_input_message_processor_;
 
-  DISALLOW_COPY_AND_ASSIGN(RenderWidgetMessageProcessor);
+  // Used to send BlimpMessage::COMPOSITOR messages to the engine.
+  scoped_ptr<BlimpMessageProcessor> outgoing_compositor_message_processor_;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderWidgetFeature);
 };
 
 }  // namespace blimp
 
-#endif  // BLIMP_CLIENT_COMPOSITOR_RENDER_WIDGET_MESSAGE_PROCESSOR_H_
+#endif  // BLIMP_CLIENT_SESSION_RENDER_WIDGET_FEATURE_H_
diff --git a/blimp/client/session/render_widget_feature_unittest.cc b/blimp/client/session/render_widget_feature_unittest.cc
new file mode 100644
index 0000000..3e7752d
--- /dev/null
+++ b/blimp/client/session/render_widget_feature_unittest.cc
@@ -0,0 +1,133 @@
+// 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/client/session/render_widget_feature.h"
+
+#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"
+#include "blimp/net/test_common.h"
+#include "cc/proto/compositor_message.pb.h"
+#include "net/base/net_errors.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+
+namespace blimp {
+
+namespace {
+
+class MockRenderWidgetFeatureDelegate
+    : public RenderWidgetFeature::RenderWidgetFeatureDelegate {
+ public:
+  // RenderWidgetFeatureDelegate implementation.
+  void OnRenderWidgetInitialized() override {
+    MockableOnRenderWidgetInitialized();
+  }
+  void OnCompositorMessageReceived(
+      scoped_ptr<cc::proto::CompositorMessage> message) override {
+    MockableOnCompositorMessageReceived(*message);
+  }
+
+  MOCK_METHOD0(MockableOnRenderWidgetInitialized, void());
+  MOCK_METHOD1(MockableOnCompositorMessageReceived,
+               void(const cc::proto::CompositorMessage& message));
+};
+
+MATCHER_P2(CompMsgEquals, tab_id, rw_id, "") {
+  return arg.compositor().render_widget_id() == rw_id &&
+         arg.target_tab_id() == tab_id;
+}
+
+void SendRenderWidgetMessage(BlimpMessageProcessor* processor,
+                             int tab_id,
+                             uint32_t rw_id) {
+  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), net::CompletionCallback());
+}
+
+void SendCompositorMessage(BlimpMessageProcessor* processor,
+                           int tab_id,
+                           uint32_t rw_id) {
+  CompositorMessage* details;
+  scoped_ptr<BlimpMessage> message = CreateBlimpMessage(&details, tab_id);
+  details->set_render_widget_id(rw_id);
+  processor->ProcessMessage(std::move(message), net::CompletionCallback());
+}
+
+}  // namespace
+
+class RenderWidgetFeatureTest : public testing::Test {
+ public:
+  RenderWidgetFeatureTest()
+      : out_input_processor_(nullptr), out_compositor_processor_(nullptr) {}
+
+  void SetUp() override {
+    out_input_processor_ = new MockBlimpMessageProcessor();
+    out_compositor_processor_ = new MockBlimpMessageProcessor();
+    feature_.set_outgoing_input_message_processor(
+        make_scoped_ptr(out_input_processor_));
+    feature_.set_outgoing_compositor_message_processor(
+        make_scoped_ptr(out_compositor_processor_));
+
+    feature_.SetDelegate(1, &delegate1_);
+    feature_.SetDelegate(2, &delegate2_);
+  }
+
+ protected:
+  // These are raw pointers to classes that are owned by the
+  // RenderWidgetFeature.
+  MockBlimpMessageProcessor* out_input_processor_;
+  MockBlimpMessageProcessor* out_compositor_processor_;
+
+  MockRenderWidgetFeatureDelegate delegate1_;
+  MockRenderWidgetFeatureDelegate delegate2_;
+
+  RenderWidgetFeature feature_;
+};
+
+TEST_F(RenderWidgetFeatureTest, DelegateCallsOK) {
+  EXPECT_CALL(delegate1_, MockableOnRenderWidgetInitialized()).Times(1);
+  SendRenderWidgetMessage(&feature_, 1, 1U);
+
+  EXPECT_CALL(delegate1_, MockableOnCompositorMessageReceived(_)).Times(1);
+  SendCompositorMessage(&feature_, 1, 1U);
+
+  EXPECT_CALL(delegate2_, MockableOnRenderWidgetInitialized()).Times(1);
+  SendRenderWidgetMessage(&feature_, 2, 2U);
+
+  EXPECT_CALL(delegate2_, MockableOnCompositorMessageReceived(_)).Times(1);
+  SendCompositorMessage(&feature_, 2, 2U);
+}
+
+TEST_F(RenderWidgetFeatureTest, RepliesHaveCorrectRenderWidgetId) {
+  SendRenderWidgetMessage(&feature_, 1, 2U);
+  SendRenderWidgetMessage(&feature_, 2, 1U);
+
+  EXPECT_CALL(*out_compositor_processor_,
+              MockableProcessMessage(CompMsgEquals(1, 2U), _))
+      .Times(1);
+  feature_.SendCompositorMessage(1, cc::proto::CompositorMessage());
+
+  SendRenderWidgetMessage(&feature_, 1, 3U);
+
+  EXPECT_CALL(*out_compositor_processor_,
+              MockableProcessMessage(CompMsgEquals(1, 3U), _))
+      .Times(1);
+  feature_.SendCompositorMessage(1, cc::proto::CompositorMessage());
+
+  EXPECT_CALL(*out_compositor_processor_,
+              MockableProcessMessage(CompMsgEquals(2, 1U), _))
+      .Times(1);
+  feature_.SendCompositorMessage(2, cc::proto::CompositorMessage());
+}
+
+}  // namespace blimp
diff --git a/blimp/client/session/tab_control_feature.cc b/blimp/client/session/tab_control_feature.cc
new file mode 100644
index 0000000..15cbdd1
--- /dev/null
+++ b/blimp/client/session/tab_control_feature.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 "blimp/client/session/tab_control_feature.h"
+
+#include "blimp/common/create_blimp_message.h"
+#include "blimp/common/proto/blimp_message.pb.h"
+#include "blimp/common/proto/control.pb.h"
+#include "blimp/common/proto/size.pb.h"
+#include "blimp/net/blimp_message_processor.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace blimp {
+
+TabControlFeature::TabControlFeature() {}
+
+TabControlFeature::~TabControlFeature() {}
+
+void TabControlFeature::set_outgoing_message_processor(
+    scoped_ptr<BlimpMessageProcessor> processor) {
+  outgoing_message_processor_ = std::move(processor);
+}
+
+void TabControlFeature::SetSizeAndScale(const gfx::Size& size,
+                                        float device_pixel_ratio) {
+  SizeMessage* size_details;
+  scoped_ptr<BlimpMessage> message = CreateBlimpMessage(&size_details);
+  size_details->set_width(size.width());
+  size_details->set_height(size.height());
+  size_details->set_device_pixel_ratio(device_pixel_ratio);
+
+  // TODO(dtrainor): Don't keep sending size events to the server.  Wait for a
+  // CompletionCallback to return before sending future size updates.
+  outgoing_message_processor_->ProcessMessage(std::move(message),
+                                              net::CompletionCallback());
+}
+
+void TabControlFeature::ProcessMessage(
+    scoped_ptr<BlimpMessage> message,
+    const net::CompletionCallback& callback) {
+  NOTIMPLEMENTED();
+}
+
+}  // namespace blimp
diff --git a/blimp/client/session/tab_control_feature.h b/blimp/client/session/tab_control_feature.h
new file mode 100644
index 0000000..166dec7
--- /dev/null
+++ b/blimp/client/session/tab_control_feature.h
@@ -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.
+
+#ifndef BLIMP_CLIENT_SESSION_TAB_CONTROL_FEATURE_H_
+#define BLIMP_CLIENT_SESSION_TAB_CONTROL_FEATURE_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "blimp/client/blimp_client_export.h"
+#include "blimp/net/blimp_message_processor.h"
+
+namespace gfx {
+class Size;
+}
+
+namespace blimp {
+
+class BLIMP_CLIENT_EXPORT TabControlFeature : public BlimpMessageProcessor {
+ public:
+  TabControlFeature();
+  ~TabControlFeature() override;
+
+  // Set the BlimpMessageProcessor that will be used to send
+  // BlimpMessage::CONTROL messages to the engine.
+  void set_outgoing_message_processor(
+      scoped_ptr<BlimpMessageProcessor> processor);
+
+  // Pushes the current size and scale information to the engine, which will
+  // affect the web content display area for all tabs.
+  void SetSizeAndScale(const gfx::Size& size, float device_pixel_ratio);
+
+ private:
+  // BlimpMessageProcessor implementation.
+  void ProcessMessage(scoped_ptr<BlimpMessage> message,
+                      const net::CompletionCallback& callback) override;
+
+  // Used to send BlimpMessage::CONTROL messages to the engine.
+  scoped_ptr<BlimpMessageProcessor> outgoing_message_processor_;
+
+  DISALLOW_COPY_AND_ASSIGN(TabControlFeature);
+};
+
+}  // namespace blimp
+
+#endif  // BLIMP_CLIENT_SESSION_TAB_CONTROL_FEATURE_H_
diff --git a/blimp/client/session/tab_control_feature_android.cc b/blimp/client/session/tab_control_feature_android.cc
new file mode 100644
index 0000000..20da386
--- /dev/null
+++ b/blimp/client/session/tab_control_feature_android.cc
@@ -0,0 +1,54 @@
+// 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/client/session/tab_control_feature_android.h"
+
+#include "blimp/client/session/blimp_client_session_android.h"
+#include "blimp/client/session/tab_control_feature.h"
+#include "jni/TabControlFeature_jni.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace blimp {
+
+static jlong Init(JNIEnv* env,
+                  const JavaParamRef<jobject>& jobj,
+                  const JavaParamRef<jobject>& blimp_client_session) {
+  BlimpClientSession* client_session =
+      BlimpClientSessionAndroid::FromJavaObject(env,
+                                                blimp_client_session.obj());
+
+  return reinterpret_cast<intptr_t>(
+      new TabControlFeatureAndroid(env,
+                                   jobj,
+                                   client_session->GetTabControlFeature()));
+}
+
+// static
+bool TabControlFeatureAndroid::RegisterJni(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+TabControlFeatureAndroid::TabControlFeatureAndroid(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& jobj,
+    TabControlFeature* tab_control_feature)
+    : tab_control_feature_(tab_control_feature) {
+  java_obj_.Reset(env, jobj);
+}
+
+TabControlFeatureAndroid::~TabControlFeatureAndroid() {}
+
+void TabControlFeatureAndroid::Destroy(JNIEnv* env, jobject jobj) {
+  delete this;
+}
+
+void TabControlFeatureAndroid::OnContentAreaSizeChanged(JNIEnv* env,
+                                                        jobject jobj,
+                                                        jint width,
+                                                        jint height,
+                                                        jfloat dp_to_px) {
+  tab_control_feature_->SetSizeAndScale(gfx::Size(width, height), dp_to_px);
+}
+
+}  // namespace blimp
diff --git a/blimp/client/session/tab_control_feature_android.h b/blimp/client/session/tab_control_feature_android.h
new file mode 100644
index 0000000..81aa6c5
--- /dev/null
+++ b/blimp/client/session/tab_control_feature_android.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 BLIMP_CLIENT_SESSION_TAB_CONTROL_FEATURE_ANDROID_H_
+#define BLIMP_CLIENT_SESSION_TAB_CONTROL_FEATURE_ANDROID_H_
+
+#include "base/android/jni_android.h"
+#include "base/macros.h"
+
+namespace blimp {
+
+class TabControlFeature;
+
+class TabControlFeatureAndroid {
+ public:
+  static bool RegisterJni(JNIEnv* env);
+
+  TabControlFeatureAndroid(JNIEnv* env,
+                           const base::android::JavaParamRef<jobject>& jobj,
+                           TabControlFeature* tab_control_feature);
+
+  // Methods called from Java via JNI.
+  void Destroy(JNIEnv* env, jobject jobj);
+  void OnContentAreaSizeChanged(JNIEnv* env,
+                                jobject jobj,
+                                jint width,
+                                jint height,
+                                jfloat dp_to_px);
+
+ private:
+  virtual ~TabControlFeatureAndroid();
+
+  TabControlFeature* tab_control_feature_;
+
+  // Reference to the Java object which owns this class.
+  base::android::ScopedJavaGlobalRef<jobject> java_obj_;
+
+  DISALLOW_COPY_AND_ASSIGN(TabControlFeatureAndroid);
+};
+
+}  // namespace blimp
+
+#endif  // BLIMP_CLIENT_SESSION_TAB_CONTROL_FEATURE_ANDROID_H_
diff --git a/blimp/client/session/tab_control_feature_unittest.cc b/blimp/client/session/tab_control_feature_unittest.cc
new file mode 100644
index 0000000..d53bd97
--- /dev/null
+++ b/blimp/client/session/tab_control_feature_unittest.cc
@@ -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.
+
+#include "blimp/client/session/tab_control_feature.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "blimp/common/proto/blimp_message.pb.h"
+#include "blimp/common/proto/control.pb.h"
+#include "blimp/common/proto/size.pb.h"
+#include "blimp/net/test_common.h"
+#include "net/base/net_errors.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/size.h"
+
+using testing::_;
+
+namespace blimp {
+
+MATCHER_P3(EqualsSizeMessage, width, height, dp_to_px, "") {
+  return arg.control().type() == ControlMessage::SIZE &&
+         arg.control().size().width() == width &&
+         arg.control().size().height() == height &&
+         arg.control().size().device_pixel_ratio() == dp_to_px;
+}
+
+class TabControlFeatureTest : public testing::Test {
+ public:
+  TabControlFeatureTest() : out_processor_(nullptr) {}
+
+  void SetUp() override {
+    out_processor_ = new MockBlimpMessageProcessor();
+    feature_.set_outgoing_message_processor(make_scoped_ptr(out_processor_));
+  }
+
+ protected:
+  // This is a raw pointer to a class that is owned by the ControlFeature.
+  MockBlimpMessageProcessor* out_processor_;
+
+  TabControlFeature feature_;
+};
+
+TEST_F(TabControlFeatureTest, CreatesCorrectSizeMessage) {
+  uint64_t width = 10;
+  uint64_t height = 15;
+  float dp_to_px = 1.23f;
+
+  EXPECT_CALL(
+      *out_processor_,
+      MockableProcessMessage(EqualsSizeMessage(width, height, dp_to_px), _))
+      .Times(1);
+  feature_.SetSizeAndScale(gfx::Size(width, height), 1.23f);
+}
+
+}  // namespace blimp
diff --git a/blimp/common/BUILD.gn b/blimp/common/BUILD.gn
index 72d23e1..5b7ba5ab 100644
--- a/blimp/common/BUILD.gn
+++ b/blimp/common/BUILD.gn
@@ -11,6 +11,7 @@
     "compositor/blimp_task_graph_runner.h",
     "create_blimp_message.cc",
     "create_blimp_message.h",
+    "protocol_version.h",
   ]
 
   defines = [ "BLIMP_COMMON_IMPLEMENTATION=1" ]
diff --git a/blimp/common/create_blimp_message.cc b/blimp/common/create_blimp_message.cc
index 4d331ac..e4f953a 100644
--- a/blimp/common/create_blimp_message.cc
+++ b/blimp/common/create_blimp_message.cc
@@ -8,8 +8,10 @@
 #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/control.pb.h"
 #include "blimp/common/proto/input.pb.h"
 #include "blimp/common/proto/render_widget.pb.h"
+#include "blimp/common/proto/size.pb.h"
 
 namespace blimp {
 
@@ -24,6 +26,14 @@
   return output;
 }
 
+scoped_ptr<BlimpMessage> CreateBlimpMessage(ControlMessage** control_message) {
+  DCHECK(control_message);
+  scoped_ptr<BlimpMessage> output(new BlimpMessage);
+  output->set_type(BlimpMessage::CONTROL);
+  *control_message = output->mutable_control();
+  return output;
+}
+
 scoped_ptr<BlimpMessage> CreateBlimpMessage(InputMessage** input_message) {
   DCHECK(input_message);
   scoped_ptr<BlimpMessage> output(new BlimpMessage);
@@ -33,6 +43,17 @@
 }
 
 scoped_ptr<BlimpMessage> CreateBlimpMessage(
+    NavigationMessage** navigation_message,
+    int target_tab_id) {
+  DCHECK(navigation_message);
+  scoped_ptr<BlimpMessage> output(new BlimpMessage);
+  output->set_type(BlimpMessage::NAVIGATION);
+  output->set_target_tab_id(target_tab_id);
+  *navigation_message = output->mutable_navigation();
+  return output;
+}
+
+scoped_ptr<BlimpMessage> CreateBlimpMessage(
     RenderWidgetMessage** render_widget_message,
     int target_tab_id) {
   DCHECK(render_widget_message);
@@ -43,4 +64,30 @@
   return output;
 }
 
+scoped_ptr<BlimpMessage> CreateBlimpMessage(SizeMessage** size_message) {
+  DCHECK(size_message);
+  ControlMessage* control_message;
+  scoped_ptr<BlimpMessage> output = CreateBlimpMessage(&control_message);
+  control_message->set_type(ControlMessage::SIZE);
+  *size_message = control_message->mutable_size();
+  return output;
+}
+
+scoped_ptr<BlimpMessage> CreateStartConnectionMessage(
+    const std::string& client_token,
+    int protocol_version) {
+  scoped_ptr<BlimpMessage> output(new BlimpMessage);
+  output->set_type(BlimpMessage::PROTOCOL_CONTROL);
+
+  ProtocolControlMessage* control_message = output->mutable_protocol_control();
+  control_message->set_type(ProtocolControlMessage::START_CONNECTION);
+
+  StartConnectionMessage* start_connection_message =
+      control_message->mutable_start_connection();
+  start_connection_message->set_client_token(client_token);
+  start_connection_message->set_protocol_version(protocol_version);
+
+  return output;
+}
+
 }  // namespace blimp
diff --git a/blimp/common/create_blimp_message.h b/blimp/common/create_blimp_message.h
index 1e638d5..c6ac4db 100644
--- a/blimp/common/create_blimp_message.h
+++ b/blimp/common/create_blimp_message.h
@@ -5,6 +5,8 @@
 #ifndef BLIMP_COMMON_CREATE_BLIMP_MESSAGE_H_
 #define BLIMP_COMMON_CREATE_BLIMP_MESSAGE_H_
 
+#include <string>
+
 #include "base/memory/scoped_ptr.h"
 #include "blimp/common/blimp_common_export.h"
 
@@ -12,8 +14,12 @@
 
 class BlimpMessage;
 class CompositorMessage;
+class ControlMessage;
 class InputMessage;
+class NavigationMessage;
 class RenderWidgetMessage;
+class SizeMessage;
+class StartConnectionMessage;
 
 // Suite of helper methods to simplify the repetitive task of creating
 // new BlimpMessages, initializing them, and extracting type-specific
@@ -32,12 +38,26 @@
     int target_tab_id);
 
 BLIMP_COMMON_EXPORT scoped_ptr<BlimpMessage> CreateBlimpMessage(
+    ControlMessage** control_message);
+
+BLIMP_COMMON_EXPORT scoped_ptr<BlimpMessage> CreateBlimpMessage(
     InputMessage** input_message);
 
 BLIMP_COMMON_EXPORT scoped_ptr<BlimpMessage> CreateBlimpMessage(
+    NavigationMessage** navigation_message,
+    int target_tab_id);
+
+BLIMP_COMMON_EXPORT scoped_ptr<BlimpMessage> CreateBlimpMessage(
     RenderWidgetMessage** render_widget_message,
     int target_tab_id);
 
+BLIMP_COMMON_EXPORT scoped_ptr<BlimpMessage> CreateBlimpMessage(
+    SizeMessage** size_message);
+
+BLIMP_COMMON_EXPORT scoped_ptr<BlimpMessage> CreateStartConnectionMessage(
+    const std::string& client_token,
+    int protocol_version);
+
 }  // 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
index 1db89566..0c1760d 100644
--- a/blimp/common/create_blimp_message_unittest.cc
+++ b/blimp/common/create_blimp_message_unittest.cc
@@ -5,8 +5,11 @@
 #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/control.pb.h"
 #include "blimp/common/proto/input.pb.h"
+#include "blimp/common/proto/navigation.pb.h"
 #include "blimp/common/proto/render_widget.pb.h"
+#include "blimp/common/proto/size.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blimp {
@@ -23,6 +26,14 @@
   EXPECT_EQ(kTabId, message->target_tab_id());
 }
 
+TEST(CreateBlimpMessageTest, ControlMessage) {
+  ControlMessage* details = nullptr;
+  scoped_ptr<BlimpMessage> message = CreateBlimpMessage(&details);
+  EXPECT_NE(nullptr, details);
+  EXPECT_NE(nullptr, message);
+  EXPECT_EQ(details, message->mutable_control());
+}
+
 TEST(CreateBlimpMessageTest, InputMessage) {
   InputMessage* details = nullptr;
   scoped_ptr<BlimpMessage> message = CreateBlimpMessage(&details);
@@ -31,6 +42,15 @@
   EXPECT_EQ(details, message->mutable_input());
 }
 
+TEST(CreateBlimpMessageTest, NavigationMessage) {
+  NavigationMessage* details = nullptr;
+  scoped_ptr<BlimpMessage> message = CreateBlimpMessage(&details, kTabId);
+  EXPECT_NE(nullptr, details);
+  EXPECT_NE(nullptr, message);
+  EXPECT_EQ(details, message->mutable_navigation());
+  EXPECT_EQ(kTabId, message->target_tab_id());
+}
+
 TEST(CreateBlimpMessageTest, RenderWidgetMessage) {
   RenderWidgetMessage* details = nullptr;
   scoped_ptr<BlimpMessage> message = CreateBlimpMessage(&details, kTabId);
@@ -40,5 +60,29 @@
   EXPECT_EQ(kTabId, message->target_tab_id());
 }
 
+TEST(CreateBlimpMessageTest, SizeMessage) {
+  SizeMessage* details = nullptr;
+  scoped_ptr<BlimpMessage> message = CreateBlimpMessage(&details);
+  EXPECT_NE(nullptr, details);
+  EXPECT_NE(nullptr, message);
+  EXPECT_EQ(ControlMessage::SIZE, message->mutable_control()->type());
+  EXPECT_EQ(details, message->mutable_control()->mutable_size());
+}
+
+TEST(CreateBlimpMessageTest, StartConnectionMessage) {
+  const char* client_token = "token";
+  const int protocol_version = 1;
+  scoped_ptr<BlimpMessage> message =
+      CreateStartConnectionMessage(client_token, protocol_version);
+  EXPECT_NE(nullptr, message);
+  EXPECT_EQ(BlimpMessage::PROTOCOL_CONTROL, message->type());
+  EXPECT_EQ(ProtocolControlMessage::START_CONNECTION,
+            message->protocol_control().type());
+  EXPECT_EQ(client_token,
+            message->protocol_control().start_connection().client_token());
+  EXPECT_EQ(protocol_version,
+            message->protocol_control().start_connection().protocol_version());
+}
+
 }  // namespace
 }  // namespace blimp
diff --git a/blimp/common/proto/BUILD.gn b/blimp/common/proto/BUILD.gn
index fa564ebb..80d3d2a 100644
--- a/blimp/common/proto/BUILD.gn
+++ b/blimp/common/proto/BUILD.gn
@@ -30,6 +30,7 @@
     "control.proto",
     "input.proto",
     "navigation.proto",
+    "protocol_control.proto",
     "render_widget.proto",
     "size.proto",
   ]
diff --git a/blimp/common/proto/blimp_message.proto b/blimp/common/proto/blimp_message.proto
index 5841cd80..3bf22f84 100644
--- a/blimp/common/proto/blimp_message.proto
+++ b/blimp/common/proto/blimp_message.proto
@@ -28,6 +28,7 @@
 import "input.proto";
 import "navigation.proto";
 import "render_widget.proto";
+import "protocol_control.proto";
 
 package blimp;
 
@@ -39,6 +40,7 @@
     RENDER_WIDGET = 3;
     INPUT = 4;
     COMPOSITOR = 5;
+    PROTOCOL_CONTROL = 6;
   }
 
   // Sequence number of this message, used for message acknowledgement.
@@ -70,5 +72,6 @@
   optional RenderWidgetMessage render_widget = 1002;
   optional InputMessage input = 1003;
   optional CompositorMessage compositor = 1004;
+  optional ProtocolControlMessage protocol_control = 1005;
 }
 
diff --git a/blimp/common/proto/control.proto b/blimp/common/proto/control.proto
index 1a909b6..8d29789 100644
--- a/blimp/common/proto/control.proto
+++ b/blimp/common/proto/control.proto
@@ -28,5 +28,6 @@
 
   // Feature-specific messages follow.
   // Only one of these fields may be set per ControlMessage.
-  optional SizeMessage resize = 1000;
+  // TODO(kmarshall): use a 'oneof' union when it's supported in Chromium.
+  optional SizeMessage size = 1000;
 }
diff --git a/blimp/common/proto/protocol_control.proto b/blimp/common/proto/protocol_control.proto
new file mode 100644
index 0000000..9589d52
--- /dev/null
+++ b/blimp/common/proto/protocol_control.proto
@@ -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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package blimp;
+
+// Contains Client->Engine information to establish an authenticated connection.
+message StartConnectionMessage {
+  optional string client_token = 1;
+  optional int32 protocol_version = 2;
+}
+
+message ProtocolControlMessage {
+  enum Type {
+    UNKNOWN = 0;
+
+    // Client => Server types.
+    START_CONNECTION = 1;
+  }
+
+  optional Type type = 1;
+
+  optional StartConnectionMessage start_connection = 1000;
+}
diff --git a/blimp/common/proto/size.proto b/blimp/common/proto/size.proto
index f6ba801..fc59b2d 100644
--- a/blimp/common/proto/size.proto
+++ b/blimp/common/proto/size.proto
@@ -13,5 +13,6 @@
 message SizeMessage {
   optional uint64 width = 1;
   optional uint64 height = 2;
+  optional float device_pixel_ratio = 3;
 }
 
diff --git a/blimp/common/protocol_version.h b/blimp/common/protocol_version.h
new file mode 100644
index 0000000..98a7e63
--- /dev/null
+++ b/blimp/common/protocol_version.h
@@ -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.
+
+#ifndef BLIMP_COMMON_PROTOCOL_VERSION_H_
+#define BLIMP_COMMON_PROTOCOL_VERSION_H_
+
+#include "blimp/common/blimp_common_export.h"
+
+namespace blimp {
+
+const int BLIMP_COMMON_EXPORT kProtocolVersion = 0;
+
+}  // namespace blimp
+
+#endif  // BLIMP_COMMON_PROTOCOL_VERSION_H_
diff --git a/blimp/engine/browser/blimp_engine_session.cc b/blimp/engine/browser/blimp_engine_session.cc
index abea9af..aa17d29a 100644
--- a/blimp/engine/browser/blimp_engine_session.cc
+++ b/blimp/engine/browser/blimp_engine_session.cc
@@ -6,6 +6,7 @@
 
 #include "base/lazy_instance.h"
 #include "base/strings/utf_string_conversions.h"
+#include "blimp/common/create_blimp_message.h"
 #include "blimp/common/proto/blimp_message.pb.h"
 #include "blimp/common/proto/control.pb.h"
 #include "blimp/engine/browser/blimp_browser_context.h"
@@ -40,6 +41,9 @@
 namespace {
 
 const int kDummyTabId = 0;
+const float kDefaultScaleFactor = 1.f;
+const int kDefaultDisplayWidth = 800;
+const int kDefaultDisplayHeight = 600;
 
 base::LazyInstance<blimp::NullBlimpMessageProcessor> g_blimp_message_processor =
     LAZY_INSTANCE_INITIALIZER;
@@ -67,6 +71,9 @@
       // TODO(dtrainor, haibinlu): Properly pull these from the BlimpMessageMux.
       render_widget_processor_(g_blimp_message_processor.Pointer(),
                                g_blimp_message_processor.Pointer()) {
+  screen_->UpdateDisplayScaleAndSize(kDefaultScaleFactor,
+                                     gfx::Size(kDefaultDisplayWidth,
+                                               kDefaultDisplayHeight));
   render_widget_processor_.SetDelegate(kDummyTabId, this);
 }
 
@@ -120,9 +127,13 @@
   web_contents_->Close();
 }
 
-void BlimpEngineSession::HandleResize(const gfx::Size& size) {
-  // TODO(dtrainor, haibinlu): Set the proper size on the WebContents/save for
-  // future WebContents objects.
+void BlimpEngineSession::HandleResize(float device_pixel_ratio,
+                                      const gfx::Size& size) {
+  screen_->UpdateDisplayScaleAndSize(device_pixel_ratio, size);
+  if (web_contents_ && web_contents_->GetRenderViewHost() &&
+      web_contents_->GetRenderViewHost()->GetWidget()) {
+    web_contents_->GetRenderViewHost()->GetWidget()->WasResized();
+  }
 }
 
 void BlimpEngineSession::LoadUrl(const int target_tab_id, const GURL& url) {
@@ -197,8 +208,9 @@
       case ControlMessage::CLOSE_TAB:
         CloseWebContents(message->target_tab_id());
       case ControlMessage::SIZE:
-        HandleResize(gfx::Size(message->control().resize().width(),
-                               message->control().resize().height()));
+        HandleResize(message->control().size().device_pixel_ratio(),
+                     gfx::Size(message->control().size().width(),
+                               message->control().size().height()));
         break;
       default:
         NOTIMPLEMENTED();
@@ -299,11 +311,9 @@
   if (source != web_contents_.get() || !changed_flags)
     return;
 
-  scoped_ptr<BlimpMessage> message(new BlimpMessage);
-  message->set_type(BlimpMessage::NAVIGATION);
-  message->set_target_tab_id(kDummyTabId);
-
-  NavigationMessage* navigation_message = message->mutable_navigation();
+  NavigationMessage* navigation_message;
+  scoped_ptr<BlimpMessage> message =
+      CreateBlimpMessage(&navigation_message, kDummyTabId);
   navigation_message->set_type(NavigationMessage::NAVIGATION_STATE_CHANGED);
   NavigationStateChangeMessage* details =
       navigation_message->mutable_navigation_state_change();
diff --git a/blimp/engine/browser/blimp_engine_session.h b/blimp/engine/browser/blimp_engine_session.h
index e834fe3..61f772b 100644
--- a/blimp/engine/browser/blimp_engine_session.h
+++ b/blimp/engine/browser/blimp_engine_session.h
@@ -74,7 +74,7 @@
   // Creates a new WebContents, which will be indexed by |target_tab_id|.
   void CreateWebContents(const int target_tab_id);
   void CloseWebContents(const int target_tab_id);
-  void HandleResize(const gfx::Size& size);
+  void HandleResize(float device_pixel_ratio, const gfx::Size& size);
 
   // NavigationMessage handler methods.
   // Navigates the target tab to the |url|.
diff --git a/blimp/engine/ui/blimp_screen.cc b/blimp/engine/ui/blimp_screen.cc
index 02829679..0e38138 100644
--- a/blimp/engine/ui/blimp_screen.cc
+++ b/blimp/engine/ui/blimp_screen.cc
@@ -10,23 +10,17 @@
 namespace {
 
 const int64 kDisplayId = 1;
-const float kDefaultScale = 1.0f;
 const int kNumDisplays = 1;
 
 }  // namespace
 
-const int BlimpScreen::kDefaultDisplayWidth = 800;
-const int BlimpScreen::kDefaultDisplayHeight = 600;
-
-BlimpScreen::BlimpScreen() : display_(kDisplayId) {
-  display_.SetScaleAndBounds(
-      kDefaultScale, gfx::Rect(kDefaultDisplayWidth, kDefaultDisplayHeight));
-}
+BlimpScreen::BlimpScreen() : display_(kDisplayId) {}
 
 BlimpScreen::~BlimpScreen() {}
 
-void BlimpScreen::UpdateDisplaySize(const gfx::Size& size) {
-  display_.SetScaleAndBounds(kDefaultScale, gfx::Rect(size));
+void BlimpScreen::UpdateDisplayScaleAndSize(float scale,
+                                            const gfx::Size& size) {
+  display_.SetScaleAndBounds(scale, gfx::Rect(size));
 }
 
 gfx::Point BlimpScreen::GetCursorScreenPoint() {
diff --git a/blimp/engine/ui/blimp_screen.h b/blimp/engine/ui/blimp_screen.h
index 7901780..0e2e550 100644
--- a/blimp/engine/ui/blimp_screen.h
+++ b/blimp/engine/ui/blimp_screen.h
@@ -21,7 +21,7 @@
   ~BlimpScreen() override;
 
   // Updates the size reported by the primary display.
-  void UpdateDisplaySize(const gfx::Size& size);
+  void UpdateDisplayScaleAndSize(float scale, const gfx::Size& size);
 
   // gfx::Screen implementation.
   gfx::Point GetCursorScreenPoint() override;
@@ -36,9 +36,6 @@
   void AddObserver(gfx::DisplayObserver* observer) override;
   void RemoveObserver(gfx::DisplayObserver* observer) override;
 
-  static const int kDefaultDisplayWidth;
-  static const int kDefaultDisplayHeight;
-
  private:
   gfx::Display display_;
 
diff --git a/blimp/net/BUILD.gn b/blimp/net/BUILD.gn
index bd73b7a..c58fa77 100644
--- a/blimp/net/BUILD.gn
+++ b/blimp/net/BUILD.gn
@@ -27,6 +27,8 @@
     "common.h",
     "connection_error_observer.h",
     "connection_handler.h",
+    "engine_authentication_handler.cc",
+    "engine_authentication_handler.h",
     "engine_connection_manager.cc",
     "engine_connection_manager.h",
     "input_message_generator.cc",
@@ -84,6 +86,7 @@
     "blimp_message_output_buffer_unittest.cc",
     "blimp_message_pump_unittest.cc",
     "client_connection_manager_unittest.cc",
+    "engine_authentication_handler_unittest.cc",
     "engine_connection_manager_unittest.cc",
     "input_message_unittest.cc",
     "stream_packet_reader_unittest.cc",
diff --git a/blimp/net/blimp_connection.cc b/blimp/net/blimp_connection.cc
index c5b0700..db2f63d5 100644
--- a/blimp/net/blimp_connection.cc
+++ b/blimp/net/blimp_connection.cc
@@ -96,6 +96,8 @@
   DCHECK(writer_);
 }
 
+BlimpConnection::BlimpConnection() {}
+
 BlimpConnection::~BlimpConnection() {}
 
 void BlimpConnection::SetConnectionErrorObserver(
diff --git a/blimp/net/blimp_connection.h b/blimp/net/blimp_connection.h
index 9f48f50..f95a91c 100644
--- a/blimp/net/blimp_connection.h
+++ b/blimp/net/blimp_connection.h
@@ -27,15 +27,18 @@
   virtual ~BlimpConnection();
 
   // Lets |observer| know when the network connection encounters an error.
-  void SetConnectionErrorObserver(ConnectionErrorObserver* observer);
+  virtual void SetConnectionErrorObserver(ConnectionErrorObserver* observer);
 
   // Sets the processor which will take incoming messages for this connection.
   // Can be set multiple times, but previously set processors are discarded.
   // Caller retains the ownership of |processor|.
-  void SetIncomingMessageProcessor(BlimpMessageProcessor* processor);
+  virtual void SetIncomingMessageProcessor(BlimpMessageProcessor* processor);
 
   // Gets a processor for BrowserSession->BlimpConnection message routing.
-  BlimpMessageProcessor* GetOutgoingMessageProcessor() const;
+  virtual BlimpMessageProcessor* GetOutgoingMessageProcessor() const;
+
+ protected:
+  BlimpConnection();
 
  private:
   scoped_ptr<PacketReader> reader_;
diff --git a/blimp/net/browser_connection_handler.h b/blimp/net/browser_connection_handler.h
index 03b2cd04..5a4b239 100644
--- a/blimp/net/browser_connection_handler.h
+++ b/blimp/net/browser_connection_handler.h
@@ -27,6 +27,7 @@
 class BLIMP_NET_EXPORT BrowserConnectionHandler
     : public ConnectionHandler,
       public ConnectionErrorObserver {
+ public:
   BrowserConnectionHandler();
   ~BrowserConnectionHandler() override;
 
diff --git a/blimp/net/client_connection_manager.cc b/blimp/net/client_connection_manager.cc
index c8238e4..0626696 100644
--- a/blimp/net/client_connection_manager.cc
+++ b/blimp/net/client_connection_manager.cc
@@ -5,7 +5,11 @@
 #include "blimp/net/client_connection_manager.h"
 
 #include "base/logging.h"
+#include "blimp/common/create_blimp_message.h"
+#include "blimp/common/proto/blimp_message.pb.h"
+#include "blimp/common/protocol_version.h"
 #include "blimp/net/blimp_connection.h"
+#include "blimp/net/blimp_message_processor.h"
 #include "blimp/net/blimp_transport.h"
 #include "blimp/net/connection_handler.h"
 #include "net/base/net_errors.h"
@@ -48,7 +52,9 @@
   DCHECK_NE(result, net::ERR_IO_PENDING);
   const auto& transport = transports_[transport_index];
   if (result == net::OK) {
-    connection_handler_->HandleConnection(transport->TakeConnection());
+    scoped_ptr<BlimpConnection> connection = transport->TakeConnection();
+    SendAuthenticationMessage(connection.get());
+    connection_handler_->HandleConnection(std::move(connection));
   } else {
     DVLOG(1) << "Transport " << transport->GetName()
              << " failed to connect:" << net::ErrorToString(result);
@@ -56,4 +62,13 @@
   }
 }
 
+void ClientConnectionManager::SendAuthenticationMessage(
+    BlimpConnection* connection) {
+  // TODO(haibinlu): get client token.
+  const char* client_token = "";
+  connection->GetOutgoingMessageProcessor()->ProcessMessage(
+      CreateStartConnectionMessage(client_token, kProtocolVersion),
+      net::CompletionCallback());
+}
+
 }  // namespace blimp
diff --git a/blimp/net/client_connection_manager.h b/blimp/net/client_connection_manager.h
index f259b62..8c52313 100644
--- a/blimp/net/client_connection_manager.h
+++ b/blimp/net/client_connection_manager.h
@@ -13,6 +13,7 @@
 
 namespace blimp {
 
+class BlimpConnection;
 class BlimpTransport;
 class ConnectionHandler;
 
@@ -49,6 +50,9 @@
   // connection ready to be authenticated or there is an error.
   void OnConnectResult(int transport_index, int result);
 
+  // Sends authentication message to the engine via |connection|.
+  void SendAuthenticationMessage(BlimpConnection* connection);
+
   ConnectionHandler* connection_handler_;
   std::vector<scoped_ptr<BlimpTransport>> transports_;
 
diff --git a/blimp/net/client_connection_manager_unittest.cc b/blimp/net/client_connection_manager_unittest.cc
index 31d6a2bff..3aba2c84 100644
--- a/blimp/net/client_connection_manager_unittest.cc
+++ b/blimp/net/client_connection_manager_unittest.cc
@@ -7,6 +7,9 @@
 
 #include "base/callback_helpers.h"
 #include "base/message_loop/message_loop.h"
+#include "blimp/common/create_blimp_message.h"
+#include "blimp/common/proto/blimp_message.pb.h"
+#include "blimp/common/protocol_version.h"
 #include "blimp/net/blimp_connection.h"
 #include "blimp/net/blimp_transport.h"
 #include "blimp/net/client_connection_manager.h"
@@ -30,9 +33,12 @@
       : 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))) {}
+        reader_(new MockPacketReader),
+        writer_(new MockPacketWriter),
+        connection_(new BlimpConnection(make_scoped_ptr(reader_),
+                                        make_scoped_ptr(writer_))),
+        start_connection_message_(
+            CreateStartConnectionMessage("", kProtocolVersion)) {}
 
   ~ClientConnectionManagerTest() override {}
 
@@ -42,7 +48,10 @@
   scoped_ptr<ClientConnectionManager> manager_;
   scoped_ptr<testing::StrictMock<MockTransport>> transport1_;
   scoped_ptr<testing::StrictMock<MockTransport>> transport2_;
+  MockPacketReader* reader_;
+  MockPacketWriter* writer_;
   scoped_ptr<BlimpConnection> connection_;
+  scoped_ptr<BlimpMessage> start_connection_message_;
 };
 
 // The 1st transport connects, and the 2nd transport is not used.
@@ -50,6 +59,8 @@
   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(*writer_,
+              WritePacket(BufferEqualsProto(*start_connection_message_), _));
   EXPECT_CALL(*transport1_, TakeConnectionPtr())
       .WillOnce(Return(connection_.release()));
 
@@ -67,6 +78,8 @@
   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(*writer_,
+              WritePacket(BufferEqualsProto(*start_connection_message_), _));
   EXPECT_CALL(connection_handler_, HandleConnectionPtr(Eq(connection_.get())));
   EXPECT_CALL(*transport2_, TakeConnectionPtr())
       .WillOnce(Return(connection_.release()));
diff --git a/blimp/net/engine_authentication_handler.cc b/blimp/net/engine_authentication_handler.cc
new file mode 100644
index 0000000..e49f5ea9c
--- /dev/null
+++ b/blimp/net/engine_authentication_handler.cc
@@ -0,0 +1,126 @@
+// 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/net/engine_authentication_handler.h"
+
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "base/timer/timer.h"
+#include "blimp/common/proto/blimp_message.pb.h"
+#include "blimp/net/blimp_connection.h"
+#include "blimp/net/blimp_message_processor.h"
+#include "blimp/net/blimp_transport.h"
+#include "blimp/net/connection_error_observer.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_errors.h"
+
+namespace blimp {
+
+namespace {
+// Expect Client to send the StartConnection within ten seconds of becoming
+// connected.
+const int kAuthTimeoutDurationInSeconds = 10;
+
+// Authenticates one connection. It deletes itself when
+//   * the connection is authenticated and passed to |connection_handler|.
+//   * the connection gets into an error state.
+//   * the auth message does not arrive within a reasonable time.
+class Authenticator : public ConnectionErrorObserver,
+                      public BlimpMessageProcessor {
+ public:
+  explicit Authenticator(scoped_ptr<BlimpConnection> connection,
+                         base::WeakPtr<ConnectionHandler> connection_handler);
+  ~Authenticator() override;
+
+ private:
+  // Processes authentication result and deletes |this|.
+  void OnConnectionAuthenticated(bool authenticated);
+
+  // Handles timeout waiting for auth message, and deletes |this|.
+  void OnAuthenticationTimeout();
+
+  // ConnectionErrorObserver implementation.
+  void OnConnectionError(int error) override;
+
+  // BlimpMessageProcessor implementation.
+  void ProcessMessage(scoped_ptr<BlimpMessage> message,
+                      const net::CompletionCallback& callback) override;
+
+  // The connection to be authenticated.
+  scoped_ptr<BlimpConnection> connection_;
+
+  // Handler to pass successfully authenticated connections to.
+  base::WeakPtr<ConnectionHandler> connection_handler_;
+
+  // A timer to fail authentication on timeout.
+  base::OneShotTimer timeout_timer_;
+
+  DISALLOW_COPY_AND_ASSIGN(Authenticator);
+};
+
+Authenticator::Authenticator(
+    scoped_ptr<BlimpConnection> connection,
+    base::WeakPtr<ConnectionHandler> connection_handler)
+    : connection_(std::move(connection)),
+      connection_handler_(connection_handler) {
+  connection_->SetConnectionErrorObserver(this);
+  connection_->SetIncomingMessageProcessor(this);
+  timeout_timer_.Start(
+      FROM_HERE, base::TimeDelta::FromSeconds(kAuthTimeoutDurationInSeconds),
+      this, &Authenticator::OnAuthenticationTimeout);
+}
+
+Authenticator::~Authenticator() {}
+
+void Authenticator::OnConnectionAuthenticated(bool authenticated) {
+  connection_->SetIncomingMessageProcessor(nullptr);
+  connection_->SetConnectionErrorObserver(nullptr);
+
+  if (authenticated && connection_handler_) {
+    connection_handler_->HandleConnection(std::move(connection_));
+  }
+
+  delete this;
+}
+
+void Authenticator::OnAuthenticationTimeout() {
+  DVLOG(1) << "Connection authentication timeout";
+  OnConnectionAuthenticated(false);
+}
+
+void Authenticator::OnConnectionError(int error) {
+  DVLOG(1) << "Connection error before authenticated "
+           << net::ErrorToString(error);
+  OnConnectionAuthenticated(false);
+}
+
+void Authenticator::ProcessMessage(scoped_ptr<BlimpMessage> message,
+                                   const net::CompletionCallback& callback) {
+  if (message->type() == BlimpMessage::PROTOCOL_CONTROL) {
+    // TODO(haibinlu): check client token.
+    OnConnectionAuthenticated(true);
+  } else {
+    DVLOG(1) << "The first message is not START_CONNECTION";
+    OnConnectionAuthenticated(false);
+  }
+
+  callback.Run(net::OK);
+}
+
+}  // namespace
+
+EngineAuthenticationHandler::EngineAuthenticationHandler(
+    ConnectionHandler* connection_handler)
+    : connection_handler_weak_factory_(connection_handler) {}
+
+EngineAuthenticationHandler::~EngineAuthenticationHandler() {}
+
+void EngineAuthenticationHandler::HandleConnection(
+    scoped_ptr<BlimpConnection> connection) {
+  // Authenticator manages its own lifetime.
+  new Authenticator(std::move(connection),
+                    connection_handler_weak_factory_.GetWeakPtr());
+}
+
+}  // namespace blimp
diff --git a/blimp/net/engine_authentication_handler.h b/blimp/net/engine_authentication_handler.h
new file mode 100644
index 0000000..686a096
--- /dev/null
+++ b/blimp/net/engine_authentication_handler.h
@@ -0,0 +1,40 @@
+// 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_NET_ENGINE_AUTHENTICATION_HANDLER_H_
+#define BLIMP_NET_ENGINE_AUTHENTICATION_HANDLER_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "blimp/net/blimp_net_export.h"
+#include "blimp/net/connection_handler.h"
+
+namespace blimp {
+
+class BlimpConnection;
+class BlimpMessage;
+
+// Authenticates connections and passes successfully authenticated connections
+// to |connection_handler|.
+class BLIMP_NET_EXPORT EngineAuthenticationHandler : public ConnectionHandler {
+ public:
+  explicit EngineAuthenticationHandler(ConnectionHandler* connection_handler);
+
+  ~EngineAuthenticationHandler() override;
+
+  // ConnectionHandler implementation.
+  void HandleConnection(scoped_ptr<BlimpConnection> connection) override;
+
+ private:
+  // Used to abandon pending authenticated connections if |this| is deleted.
+  base::WeakPtrFactory<ConnectionHandler> connection_handler_weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(EngineAuthenticationHandler);
+};
+
+}  // namespace blimp
+
+#endif  // BLIMP_NET_ENGINE_AUTHENTICATION_HANDLER_H_
diff --git a/blimp/net/engine_authentication_handler_unittest.cc b/blimp/net/engine_authentication_handler_unittest.cc
new file mode 100644
index 0000000..9a3f4ca
--- /dev/null
+++ b/blimp/net/engine_authentication_handler_unittest.cc
@@ -0,0 +1,123 @@
+// 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/memory/ref_counted.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "blimp/common/create_blimp_message.h"
+#include "blimp/common/proto/blimp_message.pb.h"
+#include "blimp/net/blimp_connection.h"
+#include "blimp/net/blimp_transport.h"
+#include "blimp/net/common.h"
+#include "blimp/net/connection_error_observer.h"
+#include "blimp/net/engine_authentication_handler.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::SaveArg;
+
+namespace blimp {
+
+class EngineAuthenticationHandlerTest : public testing::Test {
+ public:
+  EngineAuthenticationHandlerTest()
+      : runner_(new base::TestMockTimeTaskRunner),
+        runner_handle_(runner_),
+        auth_handler_(new EngineAuthenticationHandler(&connection_handler_)),
+        connection_(new testing::StrictMock<MockBlimpConnection>()) {}
+
+  ~EngineAuthenticationHandlerTest() override {}
+
+ protected:
+  void ExpectOnConnection() {
+    EXPECT_CALL(*connection_, SetConnectionErrorObserver(_))
+        .Times(2)
+        .WillRepeatedly(SaveArg<0>(&error_observer_));
+    EXPECT_CALL(*connection_, SetIncomingMessageProcessor(_))
+        .Times(2)
+        .WillRepeatedly(SaveArg<0>(&incoming_message_processor_));
+  }
+
+  scoped_refptr<base::TestMockTimeTaskRunner> runner_;
+  base::ThreadTaskRunnerHandle runner_handle_;
+  testing::StrictMock<MockConnectionHandler> connection_handler_;
+  scoped_ptr<EngineAuthenticationHandler> auth_handler_;
+  scoped_ptr<testing::StrictMock<MockBlimpConnection>> connection_;
+  ConnectionErrorObserver* error_observer_ = nullptr;
+  BlimpMessageProcessor* incoming_message_processor_ = nullptr;
+};
+
+TEST_F(EngineAuthenticationHandlerTest, AuthenticationSucceeds) {
+  ExpectOnConnection();
+  EXPECT_CALL(connection_handler_, HandleConnectionPtr(Eq(connection_.get())));
+  auth_handler_->HandleConnection(std::move(connection_));
+  EXPECT_NE(nullptr, error_observer_);
+  EXPECT_NE(nullptr, incoming_message_processor_);
+
+  scoped_ptr<BlimpMessage> blimp_message = CreateStartConnectionMessage("", 0);
+  net::TestCompletionCallback process_message_cb;
+  incoming_message_processor_->ProcessMessage(std::move(blimp_message),
+                                              process_message_cb.callback());
+  EXPECT_EQ(net::OK, process_message_cb.WaitForResult());
+  EXPECT_EQ(nullptr, error_observer_);
+  EXPECT_EQ(nullptr, incoming_message_processor_);
+}
+
+TEST_F(EngineAuthenticationHandlerTest, WrongMessageReceived) {
+  ExpectOnConnection();
+  auth_handler_->HandleConnection(std::move(connection_));
+
+  InputMessage* input_message;
+  scoped_ptr<BlimpMessage> blimp_message = CreateBlimpMessage(&input_message);
+  net::TestCompletionCallback process_message_cb;
+  incoming_message_processor_->ProcessMessage(std::move(blimp_message),
+                                              process_message_cb.callback());
+  EXPECT_EQ(net::OK, process_message_cb.WaitForResult());
+  EXPECT_EQ(nullptr, error_observer_);
+  EXPECT_EQ(nullptr, incoming_message_processor_);
+}
+
+TEST_F(EngineAuthenticationHandlerTest, ConnectionError) {
+  ExpectOnConnection();
+  auth_handler_->HandleConnection(std::move(connection_));
+  EXPECT_NE(nullptr, error_observer_);
+  EXPECT_NE(nullptr, incoming_message_processor_);
+  error_observer_->OnConnectionError(net::ERR_FAILED);
+  EXPECT_EQ(nullptr, error_observer_);
+  EXPECT_EQ(nullptr, incoming_message_processor_);
+}
+
+TEST_F(EngineAuthenticationHandlerTest, Timeout) {
+  ExpectOnConnection();
+  auth_handler_->HandleConnection(std::move(connection_));
+  EXPECT_NE(nullptr, error_observer_);
+  EXPECT_NE(nullptr, incoming_message_processor_);
+
+  runner_->FastForwardBy(base::TimeDelta::FromSeconds(11));
+  EXPECT_EQ(nullptr, error_observer_);
+  EXPECT_EQ(nullptr, incoming_message_processor_);
+}
+
+TEST_F(EngineAuthenticationHandlerTest, AuthHandlerDeletedFirst) {
+  ExpectOnConnection();
+  auth_handler_->HandleConnection(std::move(connection_));
+  auth_handler_.reset();
+
+  scoped_ptr<BlimpMessage> blimp_message = CreateStartConnectionMessage("", 0);
+  net::TestCompletionCallback process_message_cb;
+  incoming_message_processor_->ProcessMessage(std::move(blimp_message),
+                                              process_message_cb.callback());
+  EXPECT_EQ(net::OK, process_message_cb.WaitForResult());
+}
+
+}  // namespace blimp
diff --git a/blimp/net/test_common.cc b/blimp/net/test_common.cc
index 06eddac..888841ae 100644
--- a/blimp/net/test_common.cc
+++ b/blimp/net/test_common.cc
@@ -47,6 +47,10 @@
 
 MockPacketWriter::~MockPacketWriter() {}
 
+MockBlimpConnection::MockBlimpConnection() {}
+
+MockBlimpConnection::~MockBlimpConnection() {}
+
 MockConnectionErrorObserver::MockConnectionErrorObserver() {}
 
 MockConnectionErrorObserver::~MockConnectionErrorObserver() {}
diff --git a/blimp/net/test_common.h b/blimp/net/test_common.h
index 58ee2f6..b42c3d8 100644
--- a/blimp/net/test_common.h
+++ b/blimp/net/test_common.h
@@ -9,6 +9,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "blimp/common/proto/blimp_message.pb.h"
+#include "blimp/net/blimp_connection.h"
 #include "blimp/net/blimp_message_processor.h"
 #include "blimp/net/blimp_transport.h"
 #include "blimp/net/connection_error_observer.h"
@@ -165,6 +166,20 @@
                     const net::CompletionCallback&));
 };
 
+class MockBlimpConnection : public BlimpConnection {
+ public:
+  MockBlimpConnection();
+  ~MockBlimpConnection() override;
+
+  MOCK_METHOD1(SetConnectionErrorObserver,
+               void(ConnectionErrorObserver* observer));
+
+  MOCK_METHOD1(SetIncomingMessageProcessor,
+               void(BlimpMessageProcessor* processor));
+
+  MOCK_CONST_METHOD0(GetOutgoingMessageProcessor, BlimpMessageProcessor*());
+};
+
 class MockConnectionErrorObserver : public ConnectionErrorObserver {
  public:
   MockConnectionErrorObserver();
diff --git a/build/all.gyp b/build/all.gyp
index 63e7178..de8ad1f 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -87,12 +87,16 @@
             ['chromecast==0', {
               'dependencies': [
                 '../android_webview/android_webview.gyp:android_webview_apk',
-                '../android_webview/android_webview.gyp:system_webview_apk',
                 '../android_webview/android_webview_shell.gyp:system_webview_shell_apk',
                 '../chrome/android/chrome_apk.gyp:chrome_public_apk',
                 '../chrome/android/chrome_apk.gyp:chrome_sync_shell_apk',
               ],
             }],
+            ['chromecast==0 and use_webview_internal_framework==0', {
+              'dependencies': [
+                '../android_webview/android_webview.gyp:system_webview_apk',
+              ],
+            }],
             # TODO: Enable packed relocations for x64. See: b/20532404
             ['target_arch != "x64"', {
               'dependencies': [
diff --git a/build/android/adb_install_apk.py b/build/android/adb_install_apk.py
index 6e72e64..dc5b6f1 100755
--- a/build/android/adb_install_apk.py
+++ b/build/android/adb_install_apk.py
@@ -59,6 +59,8 @@
   parser.add_argument('--blacklist-file', help='Device blacklist JSON file.')
   parser.add_argument('-v', '--verbose', action='count',
                       help='Enable verbose logging.')
+  parser.add_argument('--downgrade', action='store_true',
+                      help='If set, allows downgrading of apk.')
 
   args = parser.parse_args()
 
@@ -103,9 +105,11 @@
   def blacklisting_install(device):
     try:
       if args.splits:
-        device.InstallSplitApk(apk, splits, reinstall=args.keep_data)
+        device.InstallSplitApk(apk, splits, reinstall=args.keep_data,
+                               allow_downgrade=args.downgrade)
       else:
-        device.Install(apk, reinstall=args.keep_data)
+        device.Install(apk, reinstall=args.keep_data,
+                       allow_downgrade=args.downgrade)
     except device_errors.CommandFailedError:
       logging.exception('Failed to install %s', args.apk_name)
       if blacklist:
diff --git a/build/android/devil/android/decorators.py b/build/android/devil/android/decorators.py
index b263790b..004ac8bc 100644
--- a/build/android/devil/android/decorators.py
+++ b/build/android/devil/android/decorators.py
@@ -19,7 +19,9 @@
 DEFAULT_RETRIES_ATTR = '_default_retries'
 
 
-def _TimeoutRetryWrapper(f, timeout_func, retries_func, pass_values=False):
+def _TimeoutRetryWrapper(
+    f, timeout_func, retries_func, retry_if_func=timeout_retry.AlwaysRetry,
+    pass_values=False):
   """ Wraps a funcion with timeout and retry handling logic.
 
   Args:
@@ -50,7 +52,8 @@
         desc = '%s(%s)' % (f.__name__, ', '.join(itertools.chain(
             (str(a) for a in args),
             ('%s=%s' % (k, str(v)) for k, v in kwargs.iteritems()))))
-        return timeout_retry.Run(impl, timeout, retries, desc=desc)
+        return timeout_retry.Run(impl, timeout, retries, desc=desc,
+                                 retry_if_func=retry_if_func)
     except reraiser_thread.TimeoutError as e:
       raise device_errors.CommandTimeoutError(str(e)), None, (
           sys.exc_info()[2])
@@ -75,6 +78,25 @@
   return _TimeoutRetryWrapper(f, get_timeout, get_retries)
 
 
+def WithTimeoutAndConditionalRetries(retry_if_func):
+  """Returns a decorator that handles timeouts and, in some cases, retries.
+
+  'timeout' and 'retries' kwargs must be passed to the function.
+
+  Args:
+    retry_if_func: A unary callable that takes an exception and returns
+      whether failures should be retried.
+  Returns:
+    The actual decorator.
+  """
+  def decorator(f):
+    get_timeout = lambda *a, **kw: kw['timeout']
+    get_retries = lambda *a, **kw: kw['retries']
+    return _TimeoutRetryWrapper(
+        f, get_timeout, get_retries, retry_if_func=retry_if_func)
+  return decorator
+
+
 def WithExplicitTimeoutAndRetries(timeout, retries):
   """Returns a decorator that handles timeouts and retries.
 
diff --git a/build/android/devil/android/decorators_test.py b/build/android/devil/android/decorators_test.py
index 1b6179e6..a00b128 100644
--- a/build/android/devil/android/decorators_test.py
+++ b/build/android/devil/android/decorators_test.py
@@ -82,6 +82,36 @@
           timeout=10, retries=1)
     self.assertEquals(exception_desc, str(e.exception))
 
+  def testConditionalRetriesDecoratorRetries(self):
+    def do_not_retry_no_adb_error(exc):
+      return not isinstance(exc, device_errors.NoAdbError)
+
+    actual_tries = [0]
+
+    @decorators.WithTimeoutAndConditionalRetries(do_not_retry_no_adb_error)
+    def alwaysRaisesCommandFailedError(timeout=None, retries=None):
+      actual_tries[0] += 1
+      raise device_errors.CommandFailedError('Command failed :(')
+
+    with self.assertRaises(device_errors.CommandFailedError):
+      alwaysRaisesCommandFailedError(timeout=10, retries=10)
+    self.assertEquals(11, actual_tries[0])
+
+  def testConditionalRetriesDecoratorDoesntRetry(self):
+    def do_not_retry_no_adb_error(exc):
+      return not isinstance(exc, device_errors.NoAdbError)
+
+    actual_tries = [0]
+
+    @decorators.WithTimeoutAndConditionalRetries(do_not_retry_no_adb_error)
+    def alwaysRaisesNoAdbError(timeout=None, retries=None):
+      actual_tries[0] += 1
+      raise device_errors.NoAdbError()
+
+    with self.assertRaises(device_errors.NoAdbError):
+      alwaysRaisesNoAdbError(timeout=10, retries=10)
+    self.assertEquals(1, actual_tries[0])
+
   def testDefaultsFunctionDecoratorDoesTimeouts(self):
     """Tests that the defaults decorator handles timeout logic."""
     DecoratorsTest._decorated_function_called_count = 0
diff --git a/build/android/devil/android/device_utils.py b/build/android/devil/android/device_utils.py
index a379a65c..c0920c8 100644
--- a/build/android/devil/android/device_utils.py
+++ b/build/android/devil/android/device_utils.py
@@ -76,6 +76,7 @@
     'android.permission.NFC',
     'android.permission.READ_SYNC_SETTINGS',
     'android.permission.READ_SYNC_STATS',
+    'android.permission.RECEIVE_BOOT_COMPLETED',
     'android.permission.USE_CREDENTIALS',
     'android.permission.VIBRATE',
     'android.permission.WAKE_LOCK',
@@ -90,6 +91,9 @@
     'com.google.android.c2dm.permission.RECEIVE',
     'com.google.android.providers.gsf.permission.READ_GSERVICES',
     'com.sec.enterprise.knox.MDM_CONTENT_PROVIDER',
+    'org.chromium.chrome.permission.C2D_MESSAGE',
+    'org.chromium.chrome.permission.READ_WRITE_BOOKMARK_FOLDERS',
+    'org.chromium.chrome.TOS_ACKED',
 ]
 
 _CURRENT_FOCUS_CRASH_RE = re.compile(
@@ -544,17 +548,18 @@
 
   @decorators.WithTimeoutAndRetriesFromInstance(
       min_default_timeout=INSTALL_DEFAULT_TIMEOUT)
-  def Install(self, apk, reinstall=False, permissions=None, timeout=None,
-              retries=None):
+  def Install(self, apk, allow_downgrade=False, reinstall=False,
+              permissions=None, timeout=None, retries=None):
     """Install an APK.
 
     Noop if an identical APK is already installed.
 
     Args:
       apk: An ApkHelper instance or string containing the path to the APK.
+      allow_downgrade: A boolean indicating if we should allow downgrades.
+      reinstall: A boolean indicating if we should keep any existing app data.
       permissions: Set of permissions to set. If not set, finds permissions with
           apk helper. To set no permissions, pass [].
-      reinstall: A boolean indicating if we should keep any existing app data.
       timeout: timeout in seconds
       retries: number of retries
 
@@ -563,14 +568,14 @@
       CommandTimeoutError if the installation times out.
       DeviceUnreachableError on missing device.
     """
-    self._InstallInternal(apk, None, reinstall=reinstall,
-                          permissions=permissions)
+    self._InstallInternal(apk, None, allow_downgrade=allow_downgrade,
+                          reinstall=reinstall, permissions=permissions)
 
   @decorators.WithTimeoutAndRetriesFromInstance(
       min_default_timeout=INSTALL_DEFAULT_TIMEOUT)
-  def InstallSplitApk(self, base_apk, split_apks, reinstall=False,
-                      allow_cached_props=False, permissions=None, timeout=None,
-                      retries=None):
+  def InstallSplitApk(self, base_apk, split_apks, allow_downgrade=False,
+                      reinstall=False, allow_cached_props=False,
+                      permissions=None, timeout=None, retries=None):
     """Install a split APK.
 
     Noop if all of the APK splits are already installed.
@@ -579,6 +584,7 @@
       base_apk: An ApkHelper instance or string containing the path to the base
           APK.
       split_apks: A list of strings of paths of all of the APK splits.
+      allow_downgrade: A boolean indicating if we should allow downgrades.
       reinstall: A boolean indicating if we should keep any existing app data.
       allow_cached_props: Whether to use cached values for device properties.
       permissions: Set of permissions to set. If not set, finds permissions with
@@ -594,10 +600,12 @@
     """
     self._InstallInternal(base_apk, split_apks, reinstall=reinstall,
                           allow_cached_props=allow_cached_props,
-                          permissions=permissions)
+                          permissions=permissions,
+                          allow_downgrade=allow_downgrade)
 
-  def _InstallInternal(self, base_apk, split_apks, reinstall=False,
-                       allow_cached_props=False, permissions=None):
+  def _InstallInternal(self, base_apk, split_apks, allow_downgrade=False,
+                       reinstall=False, allow_cached_props=False,
+                       permissions=None):
     if split_apks:
       self._CheckSdkLevel(version_codes.LOLLIPOP)
 
@@ -643,9 +651,11 @@
       if split_apks:
         partial = package_name if len(apks_to_install) < len(all_apks) else None
         self.adb.InstallMultiple(
-            apks_to_install, partial=partial, reinstall=reinstall)
+            apks_to_install, partial=partial, reinstall=reinstall,
+            allow_downgrade=allow_downgrade)
       else:
-        self.adb.Install(base_apk.path, reinstall=reinstall)
+        self.adb.Install(
+            base_apk.path, reinstall=reinstall, allow_downgrade=allow_downgrade)
       if (permissions is None
           and self.build_version_sdk >= version_codes.MARSHMALLOW):
         permissions = base_apk.GetPermissions()
@@ -2102,13 +2112,14 @@
     if ('android.permission.WRITE_EXTERNAL_STORAGE' in permissions
         and 'android.permission.READ_EXTERNAL_STORAGE' not in permissions):
       permissions.append('android.permission.READ_EXTERNAL_STORAGE')
-    cmd = ';'.join('pm grant %s %s' %(package, p) for p in permissions)
+    cmd = ';'.join('pm grant %s %s' % (package, p) for p in permissions)
     if cmd:
       output = self.RunShellCommand(cmd)
       if output:
         logging.warning('Possible problem when granting permissions. Blacklist '
                         'may need to be updated.')
-        logging.warning(output)
+        for line in output:
+          logging.warning('  %s', line)
 
   @decorators.WithTimeoutAndRetriesFromInstance()
   def IsScreenOn(self, timeout=None, retries=None):
diff --git a/build/android/devil/android/device_utils_test.py b/build/android/devil/android/device_utils_test.py
index bed9437d..c8c0952 100755
--- a/build/android/devil/android/device_utils_test.py
+++ b/build/android/devil/android/device_utils_test.py
@@ -572,7 +572,8 @@
     with self.patch_call(self.call.device.build_version_sdk, return_value=23):
       with self.assertCalls(
           (self.call.device._GetApplicationPathsInternal('test.package'), []),
-          self.call.adb.Install('/fake/test/app.apk', reinstall=False),
+          self.call.adb.Install('/fake/test/app.apk', reinstall=False,
+                                allow_downgrade=False),
           (self.call.device.GrantPermissions('test.package', ['p1']), [])):
         self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
 
@@ -580,21 +581,24 @@
     with self.patch_call(self.call.device.build_version_sdk, return_value=20):
       with self.assertCalls(
           (self.call.device._GetApplicationPathsInternal('test.package'), []),
-          (self.call.adb.Install('/fake/test/app.apk', reinstall=False))):
+          (self.call.adb.Install('/fake/test/app.apk', reinstall=False,
+                                 allow_downgrade=False))):
         self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
 
   def testInstall_findPermissions(self):
     with self.patch_call(self.call.device.build_version_sdk, return_value=23):
       with self.assertCalls(
           (self.call.device._GetApplicationPathsInternal('test.package'), []),
-          (self.call.adb.Install('/fake/test/app.apk', reinstall=False)),
+          (self.call.adb.Install('/fake/test/app.apk', reinstall=False,
+                                 allow_downgrade=False)),
           (self.call.device.GrantPermissions('test.package', ['p1']), [])):
         self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
 
   def testInstall_passPermissions(self):
     with self.assertCalls(
         (self.call.device._GetApplicationPathsInternal('test.package'), []),
-        (self.call.adb.Install('/fake/test/app.apk', reinstall=False)),
+        (self.call.adb.Install('/fake/test/app.apk', reinstall=False,
+                               allow_downgrade=False)),
         (self.call.device.GrantPermissions('test.package', ['p1', 'p2']), [])):
       self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0,
                           permissions=['p1', 'p2'])
@@ -607,7 +611,8 @@
             ['/fake/test/app.apk']),
          (['/fake/test/app.apk'], None)),
         self.call.device.Uninstall('test.package'),
-        self.call.adb.Install('/fake/test/app.apk', reinstall=False)):
+        self.call.adb.Install('/fake/test/app.apk', reinstall=False,
+                              allow_downgrade=False)):
       self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0,
                           permissions=[])
 
@@ -618,7 +623,8 @@
         (self.call.device._ComputeStaleApks('test.package',
             ['/fake/test/app.apk']),
          (['/fake/test/app.apk'], None)),
-        self.call.adb.Install('/fake/test/app.apk', reinstall=True)):
+        self.call.adb.Install('/fake/test/app.apk', reinstall=True,
+                              allow_downgrade=False)):
       self.device.Install(DeviceUtilsInstallTest.mock_apk,
           reinstall=True, retries=0, permissions=[])
 
@@ -636,11 +642,25 @@
   def testInstall_fails(self):
     with self.assertCalls(
         (self.call.device._GetApplicationPathsInternal('test.package'), []),
-        (self.call.adb.Install('/fake/test/app.apk', reinstall=False),
+        (self.call.adb.Install('/fake/test/app.apk', reinstall=False,
+                               allow_downgrade=False),
          self.CommandError('Failure\r\n'))):
       with self.assertRaises(device_errors.CommandFailedError):
         self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
 
+  def testInstall_downgrade(self):
+    with self.assertCalls(
+        (self.call.device._GetApplicationPathsInternal('test.package'),
+         ['/fake/data/app/test.package.apk']),
+        (self.call.device._ComputeStaleApks('test.package',
+            ['/fake/test/app.apk']),
+         (['/fake/test/app.apk'], None)),
+        self.call.adb.Install('/fake/test/app.apk', reinstall=True,
+                              allow_downgrade=True)):
+      self.device.Install(DeviceUtilsInstallTest.mock_apk,
+          reinstall=True, retries=0, permissions=[], allow_downgrade=True)
+
+
 class DeviceUtilsInstallSplitApkTest(DeviceUtilsTest):
 
   mock_apk = _MockApkHelper('base.apk', 'test.package', ['p1'])
@@ -655,7 +675,8 @@
          ['split2.apk']),
         (self.call.device._GetApplicationPathsInternal('test.package'), []),
         (self.call.adb.InstallMultiple(
-            ['base.apk', 'split2.apk'], partial=None, reinstall=False))):
+            ['base.apk', 'split2.apk'], partial=None, reinstall=False,
+            allow_downgrade=False))):
       self.device.InstallSplitApk(DeviceUtilsInstallSplitApkTest.mock_apk,
           ['split1.apk', 'split2.apk', 'split3.apk'], permissions=[], retries=0)
 
@@ -673,11 +694,33 @@
                                             ['base.apk', 'split2.apk']),
          (['split2.apk'], None)),
         (self.call.adb.InstallMultiple(
-            ['split2.apk'], partial='test.package', reinstall=True))):
+            ['split2.apk'], partial='test.package', reinstall=True,
+            allow_downgrade=False))):
       self.device.InstallSplitApk(DeviceUtilsInstallSplitApkTest.mock_apk,
                                   ['split1.apk', 'split2.apk', 'split3.apk'],
                                   reinstall=True, permissions=[], retries=0)
 
+  def testInstallSplitApk_downgrade(self):
+    with self.assertCalls(
+        (self.call.device._CheckSdkLevel(21)),
+        (mock.call.devil.android.sdk.split_select.SelectSplits(
+            self.device, 'base.apk',
+            ['split1.apk', 'split2.apk', 'split3.apk'],
+            allow_cached_props=False),
+         ['split2.apk']),
+        (self.call.device._GetApplicationPathsInternal('test.package'),
+         ['base-on-device.apk', 'split2-on-device.apk']),
+        (self.call.device._ComputeStaleApks('test.package',
+                                            ['base.apk', 'split2.apk']),
+         (['split2.apk'], None)),
+        (self.call.adb.InstallMultiple(
+            ['split2.apk'], partial='test.package', reinstall=True,
+            allow_downgrade=True))):
+      self.device.InstallSplitApk(DeviceUtilsInstallSplitApkTest.mock_apk,
+                                  ['split1.apk', 'split2.apk', 'split3.apk'],
+                                  reinstall=True, permissions=[], retries=0,
+                                  allow_downgrade=True)
+
 
 class DeviceUtilsUninstallTest(DeviceUtilsTest):
   def testUninstall_callsThrough(self):
diff --git a/build/android/devil/android/sdk/adb_wrapper.py b/build/android/devil/android/sdk/adb_wrapper.py
index b254a75..38db0e1 100644
--- a/build/android/devil/android/sdk/adb_wrapper.py
+++ b/build/android/devil/android/sdk/adb_wrapper.py
@@ -64,6 +64,10 @@
     raise device_errors.NoAdbError()
 
 
+def _ShouldRetryAdbCmd(exc):
+  return not isinstance(exc, device_errors.NoAdbError)
+
+
 DeviceStat = collections.namedtuple('DeviceStat',
                                     ['st_mode', 'st_size', 'st_time'])
 
@@ -99,15 +103,22 @@
     cmd.extend(args)
     return cmd
 
-  # pylint: disable=unused-argument
+  #pylint: disable=unused-argument
   @classmethod
-  @decorators.WithTimeoutAndRetries
+  @decorators.WithTimeoutAndConditionalRetries(_ShouldRetryAdbCmd)
   def _RunAdbCmd(cls, args, timeout=None, retries=None, device_serial=None,
                  check_error=True, cpu_affinity=None):
     # pylint: disable=no-member
-    status, output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
-        cls._BuildAdbCmd(args, device_serial, cpu_affinity=cpu_affinity),
-        timeout_retry.CurrentTimeoutThreadGroup().GetRemainingTime())
+    try:
+      status, output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
+          cls._BuildAdbCmd(args, device_serial, cpu_affinity=cpu_affinity),
+          timeout_retry.CurrentTimeoutThreadGroup().GetRemainingTime())
+    except OSError as e:
+      if e.errno in (errno.ENOENT, errno.ENOEXEC):
+        raise device_errors.NoAdbError()
+      else:
+        raise
+
     if status != 0:
       raise device_errors.AdbCommandFailedError(
           args, output, status, device_serial)
@@ -464,13 +475,15 @@
     return [a.strip() for a in
             self._RunDeviceAdbCmd(['jdwp'], timeout, retries).split('\n')]
 
-  def Install(self, apk_path, forward_lock=False, reinstall=False,
-              sd_card=False, timeout=60*2, retries=_DEFAULT_RETRIES):
+  def Install(self, apk_path, forward_lock=False, allow_downgrade=False,
+              reinstall=False, sd_card=False, timeout=60*2,
+              retries=_DEFAULT_RETRIES):
     """Install an apk on the device.
 
     Args:
       apk_path: Host path to the APK file.
       forward_lock: (optional) If set forward-locks the app.
+      allow_downgrade: (optional) If set, allows for downgrades.
       reinstall: (optional) If set reinstalls the app, keeping its data.
       sd_card: (optional) If set installs on the SD card.
       timeout: (optional) Timeout per try in seconds.
@@ -484,6 +497,8 @@
       cmd.append('-r')
     if sd_card:
       cmd.append('-s')
+    if allow_downgrade:
+      cmd.append('-d')
     cmd.append(apk_path)
     output = self._RunDeviceAdbCmd(cmd, timeout, retries)
     if 'Success' not in output:
@@ -500,10 +515,10 @@
       forward_lock: (optional) If set forward-locks the app.
       reinstall: (optional) If set reinstalls the app, keeping its data.
       sd_card: (optional) If set installs on the SD card.
-      timeout: (optional) Timeout per try in seconds.
-      retries: (optional) Number of retries to attempt.
       allow_downgrade: (optional) Allow versionCode downgrade.
       partial: (optional) Package ID if apk_paths doesn't include all .apks.
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
     """
     for path in apk_paths:
       VerifyLocalFileExists(path)
diff --git a/build/android/devil/utils/timeout_retry.py b/build/android/devil/utils/timeout_retry.py
index 1d748a9..e950e11 100644
--- a/build/android/devil/utils/timeout_retry.py
+++ b/build/android/devil/utils/timeout_retry.py
@@ -125,8 +125,12 @@
   log_func('*' * 80)
 
 
+def AlwaysRetry(_exception):
+  return True
+
+
 def Run(func, timeout, retries, args=None, kwargs=None, desc=None,
-        error_log_func=logging.critical):
+        error_log_func=logging.critical, retry_if_func=AlwaysRetry):
   """Runs the passed function in a separate thread with timeouts and retries.
 
   Args:
@@ -138,6 +142,8 @@
     desc: An optional description of |func| used in logging. If omitted,
       |func.__name__| will be used.
     error_log_func: Logging function when logging errors.
+    retry_if_func: Unary callable that takes an exception and returns
+      whether |func| should be retried. Defaults to always retrying.
 
   Returns:
     The return value of func(*args, **kwargs).
@@ -163,13 +169,13 @@
           logging.info('Still working on %s', desc if desc else func.__name__)
         else:
           return thread_group.GetAllReturnValues()[0]
-    except reraiser_thread.TimeoutError:
+    except reraiser_thread.TimeoutError as e:
       # Timeouts already get their stacks logged.
-      if num_try > retries:
+      if num_try > retries or not retry_if_func(e):
         raise
       # Do not catch KeyboardInterrupt.
-    except Exception:  # pylint: disable=broad-except
-      if num_try > retries:
+    except Exception as e:  # pylint: disable=broad-except
+      if num_try > retries or not retry_if_func(e):
         raise
       _LogLastException(thread_name, num_try, retries + 1, error_log_func)
     num_try += 1
diff --git a/build/android/devil_chromium.py b/build/android/devil_chromium.py
index d626af6..d8a3d5d 100644
--- a/build/android/devil_chromium.py
+++ b/build/android/devil_chromium.py
@@ -16,7 +16,10 @@
   'forwarder_device': {
     'armeabi-v7a': 'forwarder_dist',
     'arm64-v8a': 'forwarder_dist',
+    'mips': 'forwarder_dist',
+    'mips64': 'forwarder_dist',
     'x86': 'forwarder_dist',
+    'x86_64': 'forwarder_dist',
   },
   'forwarder_host': {
     'any': 'host_forwarder',
@@ -24,7 +27,10 @@
   'md5sum_device': {
     'armeabi-v7a': 'md5sum_dist',
     'arm64-v8a': 'md5sum_dist',
+    'mips': 'md5sum_dist',
+    'mips64': 'md5sum_dist',
     'x86': 'md5sum_dist',
+    'x86_64': 'md5sum_dist',
   },
   'md5sum_host': {
     'any': 'md5sum_bin_host',
diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py
index a8eb7c4..10c7ba2b 100644
--- a/build/android/gyp/util/build_utils.py
+++ b/build/android/gyp/util/build_utils.py
@@ -253,10 +253,10 @@
 
   # None converts to ZIP_STORED, when passed explicitly rather than the
   # default passed to the ZipFile constructor.
-  args = []
+  compress_type = zip_file.compression
   if compress is not None:
-    args.append(zipfile.ZIP_DEFLATED if compress else zipfile.ZIP_STORED)
-  zip_file.writestr(zipinfo, data, *args)
+    compress_type = zipfile.ZIP_DEFLATED if compress else zipfile.ZIP_STORED
+  zip_file.writestr(zipinfo, data, compress_type)
 
 
 def DoZip(inputs, output, base_dir=None):
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance.py b/build/android/pylib/instrumentation/instrumentation_test_instance.py
index 4536f6e74..b13fdb28f 100644
--- a/build/android/pylib/instrumentation/instrumentation_test_instance.py
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance.py
@@ -44,6 +44,9 @@
     'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetPackage')
 _EXTRA_DRIVER_TARGET_CLASS = (
     'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetClass')
+_EXTRA_TIMEOUT_SCALE = (
+    'org.chromium.test.driver.OnDeviceInstrumentationDriver.TimeoutScale')
+
 _PARAMETERIZED_TEST_ANNOTATION = 'ParameterizedTest'
 _PARAMETERIZED_TEST_SET_ANNOTATION = 'ParameterizedTest$Set'
 _NATIVE_CRASH_RE = re.compile('native crash', re.IGNORECASE)
@@ -606,6 +609,7 @@
     env = {
       _EXTRA_DRIVER_TARGET_PACKAGE: self.test_package,
       _EXTRA_DRIVER_TARGET_CLASS: self.test_runner,
+      _EXTRA_TIMEOUT_SCALE: self._timeout_scale,
     }
 
     if test_list:
diff --git a/build/common.gypi b/build/common.gypi
index dc57c6ca..e51b958 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -1096,6 +1096,9 @@
       # do a developer build.
       'android_app_version_name%': 'Developer Build',
       'android_app_version_code%': 1,
+
+      # Use the internal version of the framework to build Android WebView.
+      'use_webview_internal_framework%': 0,
     },
 
     # Copy conditionally-set variables out one scope.
@@ -1250,6 +1253,7 @@
     'mac_views_browser%': '<(mac_views_browser)',
     'android_app_version_name%': '<(android_app_version_name)',
     'android_app_version_code%': '<(android_app_version_code)',
+    'use_webview_internal_framework%': '<(use_webview_internal_framework)',
     'enable_webvr%': '<(enable_webvr)',
 
     # Turns on compiler optimizations in V8 in Debug build.
@@ -2132,9 +2136,6 @@
           '-t', 'ios',
           '--no-output-all-resource-defines',
         ],
-        # iOS uses a whitelist to filter resources.
-        'grit_whitelist%': '<(DEPTH)/build/ios/grit_whitelist.txt',
-
         # Enable host builds when generating with ninja-ios.
         'conditions': [
           ['"<(GENERATOR)"=="ninja"', {
@@ -2300,7 +2301,6 @@
         'release_valgrind_build': 1,
         'werror': '',
         'component': 'static_library',
-        'use_system_zlib': 0,
       }],
 
       # Build tweaks for DrMemory.
@@ -3160,6 +3160,7 @@
               '_SCL_SECURE_NO_DEPRECATE',
             ],
             'msvs_disabled_warnings': [
+              # forcing value to bool 'true' or 'false' (performance warning)
               4800,
             ],
             'msvs_settings': {
@@ -4138,7 +4139,7 @@
                       '-g',
                     ],
                     'ldflags': [
-                      # We want to statically link libstdc++/libgcc_s.
+                      # We want to statically link libstdc++/libgcc.
                       '-static-libstdc++',
                       '-static-libgcc',
                     ],
@@ -4150,6 +4151,34 @@
                       '-march=armv7-a',
                       '-mtune=cortex-a8',
                     ],
+                    'target_conditions': [
+                      [ '_type=="executable" and OS!="android"', {
+                        # Statically link whole libstdc++ and libgcc in
+                        # executables to ensure only one copy at runtime.
+                        'ldflags': [
+                          # Note executables also get -static-stdlibc++/libgcc.
+                          # Despite including libstdc++/libgcc archives, we
+                          # still need to specify static linking for them in
+                          # order to prevent the executable from having a
+                          # dynamic dependency on them.
+
+                          # Export stdlibc++ and libgcc symbols to force shlibs
+                          # to refer to these symbols from the executable.
+                          '-Wl,--export-dynamic',
+
+                          '-lm', # stdlibc++ requires math.h
+
+                          # In case we redefined stdlibc++ symbols
+                          # (e.g. tc_malloc)
+                          '-Wl,--allow-multiple-definition',
+
+                          '-Wl,--whole-archive',
+                          '-l:libstdc++.a',
+                          '-l:libgcc.a',
+                          '-Wl,--no-whole-archive',
+                        ],
+                      }]
+                    ],
                   }],
                 ],
               }],
@@ -4552,13 +4581,9 @@
                   '-fsanitize=memory',
                   '-fsanitize-memory-track-origins=<(msan_track_origins)',
                   '-fsanitize-blacklist=<(msan_blacklist)',
-                  # TODO(eugenis): Remove when msan migrates to new ABI (crbug.com/560589).
-                  '-fPIC',
                 ],
                 'ldflags': [
                   '-fsanitize=memory',
-                  # TODO(eugenis): Remove when msan migrates to new ABI (crbug.com/560589).
-                  '-pie',
                 ],
                 'defines': [
                   'MEMORY_SANITIZER',
@@ -5636,7 +5661,7 @@
             # it's enabled. This will generally only be true for system-level
             # installed Express users.
             'msvs_disabled_warnings': [
-              4702,
+              4702, # unreachable code
             ],
           }],
         ],
@@ -5720,6 +5745,10 @@
           # should work through these at some point -- they may be removed from
           # the RTM release in the /W4 set.
           4456, 4457, 4458, 4459,
+
+          # TODO(brucedawson): http://crbug.com/554200 4312 is a VS
+          # 2015 64-bit warning for integer to larger pointer
+          4312,
         ],
         'msvs_settings': {
           'VCCLCompilerTool': {
@@ -5804,6 +5833,13 @@
             ['clang==1', {
               'VCCLCompilerTool': {
                 'AdditionalOptions': [
+                  # Don't warn about unused function parameters.
+                  # (This is also used on other platforms.)
+                  '-Wno-unused-parameter',
+                  # Don't warn about the "struct foo f = {0};" initialization
+                  # pattern.
+                  '-Wno-missing-field-initializers',
+
                   # Many files use intrinsics without including this header.
                   # TODO(hans): Fix those files, or move this to sub-GYPs.
                   '/FIIntrin.h',
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn
index 596f9c4..18bd775 100644
--- a/build/config/BUILD.gn
+++ b/build/config/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//build/config/allocator.gni")
 import("//build/config/chrome_build.gni")
+import("//build/config/chromecast_build.gni")
 import("//build/config/crypto.gni")
 import("//build/config/features.gni")
 import("//build/config/sanitizers/sanitizers.gni")
@@ -399,6 +400,52 @@
   }
 }
 
+# Executable configs -----------------------------------------------------------
+
+# Windows linker setup for EXEs and DLLs.
+if (is_win) {
+  _windows_linker_configs = [
+    "//build/config/win:sdk_link",
+    "//build/config/win:common_linker_setup",
+  ]
+}
+
+# This config defines the configs applied to all executables.
+config("executable_config") {
+  configs = []
+
+  if (is_win) {
+    configs += _windows_linker_configs
+  } else if (is_mac) {
+    configs += [
+      "//build/config/mac:mac_dynamic_flags",
+      "//build/config/mac:mac_executable_flags",
+    ]
+  } else if (is_linux || is_android) {
+    configs += [ "//build/config/gcc:executable_ldconfig" ]
+    if (is_android) {
+      configs += [ "//build/config/android:executable_config" ]
+    } else if (is_chromecast) {
+      configs += [ "//build/config/chromecast:executable_config" ]
+    }
+  }
+}
+
+# Shared library configs -------------------------------------------------------
+
+# This config defines the configs applied to all shared libraries.
+config("shared_library_config") {
+  configs = []
+
+  if (is_win) {
+    configs += _windows_linker_configs
+  } else if (is_mac) {
+    configs += [ "//build/config/mac:mac_dynamic_flags" ]
+  } else if (is_chromecast) {
+    configs += [ "//build/config/chromecast:shared_library_config" ]
+  }
+}
+
 # Add this config to your target to enable precompiled headers.
 #
 # Precompiled headers are done on a per-target basis. If you have just a couple
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index b674db9d..54bf372 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -497,12 +497,11 @@
   _native_compiler_configs += [ "//build/config:release" ]
 }
 
-# Windows linker setup for EXEs and DLLs.
 if (is_win) {
+  # Many targets remove these configs, so they are not contained within
+  # //build/config:executable_config for easy removal.
   _windows_linker_configs = [
     "//build/config/win:default_incremental_linking",
-    "//build/config/win:sdk_link",
-    "//build/config/win:common_linker_setup",
 
     # Default to console-mode apps. Most of our targets are tests and such
     # that shouldn't use the windows subsystem.
@@ -511,20 +510,12 @@
 }
 
 # Executable defaults.
-_executable_configs =
-    _native_compiler_configs + [ "//build/config:default_libs" ]
+_executable_configs = _native_compiler_configs + [
+                        "//build/config:default_libs",
+                        "//build/config:executable_config",
+                      ]
 if (is_win) {
   _executable_configs += _windows_linker_configs
-} else if (is_mac) {
-  _executable_configs += [
-    "//build/config/mac:mac_dynamic_flags",
-    "//build/config/mac:mac_executable_flags",
-  ]
-} else if (is_linux || is_android) {
-  _executable_configs += [ "//build/config/gcc:executable_ldconfig" ]
-  if (is_android) {
-    _executable_configs += [ "//build/config/android:executable_config" ]
-  }
 }
 set_defaults("executable") {
   configs = _executable_configs
@@ -537,12 +528,12 @@
 
 # Shared library and loadable module defaults (also for components in component
 # mode).
-_shared_library_configs =
-    _native_compiler_configs + [ "//build/config:default_libs" ]
+_shared_library_configs = _native_compiler_configs + [
+                            "//build/config:default_libs",
+                            "//build/config:shared_library_config",
+                          ]
 if (is_win) {
   _shared_library_configs += _windows_linker_configs
-} else if (is_mac) {
-  _shared_library_configs += [ "//build/config/mac:mac_dynamic_flags" ]
 } else if (is_android) {
   # Strip native JNI exports from shared libraries by default. Binaries that
   # want this can remove this config.
diff --git a/build/config/android/BUILD.gn b/build/config/android/BUILD.gn
index cfbde79..fe3897c 100644
--- a/build/config/android/BUILD.gn
+++ b/build/config/android/BUILD.gn
@@ -145,7 +145,9 @@
   lib_dirs = [ "$android_libcpp_root/libs/$android_app_abi" ]
 
   # The libc++ runtime library (must come first).
-  if (is_component_build) {
+  # ASan needs to dynamically link to libc++ even in static builds so
+  # that it can interpose operator new.
+  if (is_component_build || is_asan) {
     libs = [ "c++_shared" ]
   } else {
     libs = [ "c++_static" ]
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index 337b43be..84ed05c 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -103,6 +103,9 @@
     # Adds intrumentation to each function. Writes a file with the order that
     # functions are called at startup.
     use_order_profiling = false
+
+    # Use the internal version of the framework to build Android WebView.
+    use_webview_internal_framework = false
   }
 
   # Host stuff -----------------------------------------------------------------
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 3727e8d..4673bf4 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -1700,7 +1700,6 @@
   srcjar_path = invoker.srcjar_path
   r_text_path = invoker.r_text_path
   build_config = invoker.build_config
-  resource_dirs = invoker.resource_dirs
   android_manifest = invoker.android_manifest
 
   non_constant_id = true
@@ -1724,17 +1723,30 @@
       r_text_path,
     ]
 
-    sources_build_rel = exec_script("//build/android/gyp/find.py",
-                                    rebase_path(resource_dirs, root_build_dir),
-                                    "list lines")
-    sources = rebase_path(sources_build_rel, ".", root_build_dir)
+    _all_resource_dirs = []
+    sources = []
+
+    if (defined(invoker.resource_dirs)) {
+      _all_resource_dirs += invoker.resource_dirs
+      sources_build_rel =
+          exec_script("//build/android/gyp/find.py",
+                      rebase_path(invoker.resource_dirs, root_build_dir),
+                      "list lines")
+      sources += rebase_path(sources_build_rel, ".", root_build_dir)
+    }
+
+    if (defined(invoker.generated_resource_dirs)) {
+      assert(defined(invoker.generated_resource_files))
+      _all_resource_dirs += invoker.generated_resource_dirs
+      sources += invoker.generated_resource_files
+    }
 
     inputs = [
       build_config,
       android_manifest,
     ]
 
-    rebase_resource_dirs = rebase_path(resource_dirs, root_build_dir)
+    _rebased_all_resource_dirs = rebase_path(_all_resource_dirs, root_build_dir)
     rebase_build_config = rebase_path(build_config, root_build_dir)
     args = [
       "--depfile",
@@ -1745,7 +1757,7 @@
       android_aapt_path,
       "--android-manifest",
       rebase_path(android_manifest, root_build_dir),
-      "--resource-dirs=$rebase_resource_dirs",
+      "--resource-dirs=$_rebased_all_resource_dirs",
       "--srcjar-out",
       rebase_path(srcjar_path, root_build_dir),
       "--resource-zip-out",
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index e8b6572..aeb7f1e4 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -5,6 +5,7 @@
 import("//base/android/linker/config.gni")
 import("//build/config/android/config.gni")
 import("//build/config/android/internal_rules.gni")
+import("//build/config/sanitizers/sanitizers.gni")
 import("//build/toolchain/toolchain.gni")
 import("//third_party/android_platform/config.gni")
 import("//tools/grit/grit_rule.gni")
@@ -564,6 +565,12 @@
 #     listed in deps will be included by libraries/apks that depend on this
 #     target.
 #   resource_dirs: List of directories containing resources for this target.
+#   generated_resource_dirs: List of directories containing resources for this
+#     target which are *generated* by a dependency. |generated_resource_files|
+#     must be specified if |generated_resource_dirs| is specified.
+#   generated_resource_files: List of all files in |generated_resource_dirs|.
+#     |generated_resource_dirs| must be specified in |generated_resource_files|
+#     is specified.
 #   android_manifest: AndroidManifest.xml for this target. Defaults to
 #     //build/android/AndroidManifest.xml.
 #   custom_package: java package for generated .java files.
@@ -631,6 +638,8 @@
                              "android_manifest",
                              "custom_package",
                              "deps",
+                             "generated_resource_dirs",
+                             "generated_resource_files",
                              "resource_dirs",
                              "shared_resources",
                              "v14_skip",
@@ -1322,7 +1331,7 @@
   _native_libs_deps = []
 
   if (defined(invoker.native_libs) && invoker.native_libs != []) {
-    if (is_component_build) {
+    if (is_component_build || is_asan) {
       _native_libs += [ "$root_shlib_dir/libc++_shared.so" ]
       _native_libs_deps += [ "//build/android:cpplib_stripped" ]
     }
diff --git a/build/config/chromecast/BUILD.gn b/build/config/chromecast/BUILD.gn
new file mode 100644
index 0000000..41f1c07
--- /dev/null
+++ b/build/config/chromecast/BUILD.gn
@@ -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.
+
+import("//build/config/chromecast_build.gni")
+
+assert(is_chromecast)
+
+config("static_config") {
+  ldflags = [
+    # We want to statically link libstdc++/libgcc.
+    "-static-libstdc++",
+    "-static-libgcc",
+  ]
+}
+
+config("executable_config") {
+  ldflags = [
+    # Export stdlibc++ and libgcc symbols to force shlibs to refer to these
+    # symbols from the executable.
+    "-Wl,--export-dynamic",
+
+    "-lm",  # stdlibc++ requires math.h
+
+    # In case we redefined stdlibc++ symbols (e.g. tc_malloc)
+    "-Wl,--allow-multiple-definition",
+
+    "-Wl,--whole-archive",
+    "-l:libstdc++.a",
+    "-l:libgcc.a",
+    "-Wl,--no-whole-archive",
+  ]
+
+  # Despite including libstdc++/libgcc archives, we still need to specify
+  # static linking for them in order to prevent the executable from having a
+  # dynamic dependency on them.
+  configs = [ ":static_config" ]
+}
+
+config("shared_library_config") {
+  configs = [ ":static_config" ]
+}
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index a4ff2ed6..10148bd 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -779,16 +779,6 @@
       ]
     }
   } else {
-    # Common GCC warning setup.
-    cflags += [
-      # Enables.
-      "-Wendif-labels",  # Weird old-style text after an #endif.
-
-      # Disables.
-      "-Wno-missing-field-initializers",  # "struct foo f = {0};"
-      "-Wno-unused-parameter",  # Unused function parameters.
-    ]
-
     if (treat_warnings_as_errors) {
       cflags += [ "-Werror" ]
     }
@@ -830,6 +820,18 @@
     }
   }
 
+  # Common Clang and GCC warning setup.
+  if (!is_win || is_clang) {
+    cflags += [
+      # Enables.
+      "-Wendif-labels",  # Weird old-style text after an #endif.
+
+      # Disables.
+      "-Wno-missing-field-initializers",  # "struct foo f = {0};"
+      "-Wno-unused-parameter",  # Unused function parameters.
+    ]
+  }
+
   if (is_clang) {
     cflags += [
       # This warns on using ints as initializers for floats in
diff --git a/build/config/sanitizers/BUILD.gn b/build/config/sanitizers/BUILD.gn
index 2adab21f..193f19a 100644
--- a/build/config/sanitizers/BUILD.gn
+++ b/build/config/sanitizers/BUILD.gn
@@ -36,12 +36,7 @@
     ldflags += [ "-fsanitize=thread" ]
   }
   if (is_msan) {
-    ldflags += [
-      "-fsanitize=memory",
-
-      # TODO(eugenis): Remove when msan migrates to new ABI (crbug.com/560589).
-      "-pie",
-    ]
+    ldflags += [ "-fsanitize=memory" ]
   }
   if (is_ubsan) {
     ldflags += [ "-fsanitize=undefined" ]
@@ -144,9 +139,6 @@
         "-fsanitize=memory",
         "-fsanitize-memory-track-origins=$msan_track_origins",
         "-fsanitize-blacklist=$msan_blacklist_path",
-
-        # TODO(eugenis): Remove when msan migrates to new ABI (crbug.com/560589).
-        "-fPIC",
       ]
     }
     if (is_ubsan) {
diff --git a/build/config/sysroot.gni b/build/config/sysroot.gni
index 2ca6451..29a2b61 100644
--- a/build/config/sysroot.gni
+++ b/build/config/sysroot.gni
@@ -50,6 +50,12 @@
   }
 
   if (sysroot != "") {
+    # Our sysroot images only contains gcc 4.6 headers, but chromium requires
+    # gcc 4.9. Clang is able to detect and work with the 4.6 headers while
+    # gcc is not. This check can be removed if we ever update to a more modern
+    # sysroot.
+    assert(is_clang, "sysroot images require clang (try use_sysroot=false)")
+
     _script_arch = current_cpu
     if (_script_arch == "x86") {
       _script_arch = "i386"
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi
index 4cffcbc..340d212 100644
--- a/build/gn_migration.gypi
+++ b/build/gn_migration.gypi
@@ -216,6 +216,7 @@
             '../third_party/WebKit/Source/web/web_tests.gyp:webkit_unit_tests_apk',
             '../third_party/WebKit/Source/wtf/wtf_tests.gyp:wtf_unittests_apk',
             '../tools/android/heap_profiler/heap_profiler.gyp:heap_profiler_unittests_apk',
+            '../tools/android/android_tools.gyp:memconsumer',
             '../tools/imagediff/image_diff.gyp:image_diff#host',
             '../tools/telemetry/telemetry.gyp:bitmaptools#host',
             '../ui/base/ui_base_tests.gyp:ui_base_unittests_apk',
@@ -772,7 +773,6 @@
             '../ipc/ipc.gyp:ipc_tests_apk',
             '../media/media.gyp:media_perftests_apk',
             '../sandbox/sandbox.gyp:sandbox_linux_unittests_deps',
-            '../tools/android/android_tools.gyp:memconsumer',
             '../ui/android/ui_android.gyp:ui_android_unittests_apk',
             '../url/url.gyp:url_unittests',
           ],
@@ -783,7 +783,6 @@
             '../android_webview/android_webview.gyp:android_webview_test_apk',
             '../android_webview/android_webview.gyp:android_webview_unittests',
             '../android_webview/android_webview.gyp:android_webview_unittests_apk',
-            '../android_webview/android_webview.gyp:system_webview_apk',
             '../android_webview/android_webview_shell.gyp:system_webview_shell_apk',
             '../android_webview/android_webview_shell.gyp:system_webview_shell_layout_test_apk',
             '../android_webview/android_webview_shell.gyp:system_webview_shell_page_cycler_apk',
@@ -791,6 +790,11 @@
             '../chrome/android/chrome_apk.gyp:chrome_sync_shell_test_apk',
           ],
         }],
+        ['OS=="android" and chromecast==0 and use_webview_internal_framework==0', {
+          'dependencies': [
+            '../android_webview/android_webview.gyp:system_webview_apk',
+          ],
+        }],
         ['OS=="android" and target_arch != "x64"', {
           'dependencies': [
             '../third_party/android_platform/relocation_packer.gyp:android_relocation_packer_unittests#host'
@@ -800,4 +804,3 @@
     },
   ]
 }
-
diff --git a/build/ios/OWNERS b/build/ios/OWNERS
index 4caf405d..1b3348e7 100644
--- a/build/ios/OWNERS
+++ b/build/ios/OWNERS
@@ -1,4 +1,2 @@
 rohitrao@chromium.org
 stuartmorgan@chromium.org
-
-per-file grit_whitelist.txt=*
diff --git a/build/ios/PRESUBMIT.py b/build/ios/PRESUBMIT.py
deleted file mode 100644
index bbd17b3..0000000
--- a/build/ios/PRESUBMIT.py
+++ /dev/null
@@ -1,42 +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.
-
-import os
-
-"""Chromium presubmit script for src/tools/ios.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details on the presubmit API built into depot_tools.
-"""
-
-WHITELIST_FILE = 'build/ios/grit_whitelist.txt'
-
-def _CheckWhitelistSorted(input_api, output_api):
-  for path in input_api.LocalPaths():
-    if WHITELIST_FILE == path:
-      lines = open(os.path.join('../..', WHITELIST_FILE)).readlines()
-      i = 0
-      while i < len(lines) - 1 and lines[i] <= lines[i + 1]:
-        i += 1
-      if i < len(lines) - 1:
-        return [output_api.PresubmitError(
-            'The file ' + WHITELIST_FILE + ' must be sorted.  ' +
-            'First offending line: #' + str(i + 2))]
-  return []
-
-def _CommonChecks(input_api, output_api):
-  """Checks common to both upload and commit."""
-  results = []
-  results.extend(_CheckWhitelistSorted(input_api, output_api))
-  return results
-
-def CheckChangeOnUpload(input_api, output_api):
-  results = []
-  results.extend(_CommonChecks(input_api, output_api))
-  return results
-
-def CheckChangeOnCommit(input_api, output_api):
-  results = []
-  results.extend(_CommonChecks(input_api, output_api))
-  return results
diff --git a/build/ios/grit_whitelist.txt b/build/ios/grit_whitelist.txt
deleted file mode 100644
index cc2ffdc..0000000
--- a/build/ios/grit_whitelist.txt
+++ /dev/null
@@ -1,620 +0,0 @@
-IDR_AUTOFILL_TOOLTIP_ICON
-IDR_AUTOFILL_TOOLTIP_ICON_H
-IDR_CONTROLLED_SETTING_MANDATORY
-IDR_FLAGS_FAVICON
-IDR_HISTORY_FAVICON
-IDR_HISTORY_HTML
-IDR_HISTORY_JS
-IDR_INCOGNITO_TAB_HTML
-IDR_INFOBAR_AUTOLOGIN
-IDR_INFOBAR_RESTORE_SESSION
-IDR_INFOBAR_SAVE_PASSWORD
-IDR_MD_POLICY_HTML
-IDR_NET_ERROR_HTML
-IDR_OMAHA_HTML
-IDR_OMAHA_JS
-IDR_OMNIBOX_CLEAR_IOS
-IDR_OMNIBOX_CLEAR_OTR_IOS
-IDR_OMNIBOX_CLEAR_OTR_PRESSED_IOS
-IDR_OMNIBOX_CLEAR_PRESSED_IOS
-IDR_OMNIBOX_HTTPS_INVALID
-IDR_OMNIBOX_HTTPS_POLICY_WARNING
-IDR_OMNIBOX_HTTPS_VALID
-IDR_OMNIBOX_KEYBOARD_VIEW_APPEND
-IDR_OMNIBOX_KEYBOARD_VIEW_APPEND_HIGHLIGHTED
-IDR_OMNIBOX_KEYBOARD_VIEW_APPEND_INCOGNITO
-IDR_OMNIBOX_KEYBOARD_VIEW_APPEND_INCOGNITO_HIGHLIGHTED
-IDR_OMNIBOX_SEARCH_SECURED
-IDR_OMNIBOX_STAR
-IDR_OMNIBOX_STAR_INCOGNITO
-IDR_OTHER_DEVICES_JS
-IDR_PAGEINFO_BAD
-IDR_PAGEINFO_GOOD
-IDR_PAGEINFO_INFO
-IDR_PAGEINFO_WARNING_MAJOR
-IDR_PAGEINFO_WARNING_MINOR
-IDR_POLICY_CSS
-IDR_POLICY_HTML
-IDR_POLICY_JS
-IDR_SAD_TAB
-IDR_SIGNIN_INTERNALS_INDEX_HTML
-IDR_SIGNIN_INTERNALS_INDEX_JS
-IDR_TOOLBAR_SHADOW_FULL_BLEED
-IDR_UBER_UTILS_JS
-IDS_ABOUT_MAC
-IDS_ABOUT_VERSION_32BIT
-IDS_ABOUT_VERSION_64BIT
-IDS_ABOUT_VERSION_COMPANY_NAME
-IDS_ABOUT_VERSION_COPYRIGHT
-IDS_ACCEPT_LANGUAGES
-IDS_ACCNAME_BACK
-IDS_ACCNAME_CLEAR_TEXT
-IDS_ACCNAME_CLOSE
-IDS_ACCNAME_FORWARD
-IDS_ACCNAME_LOCATION
-IDS_ACCNAME_VOICE_SEARCH
-IDS_ALLOW_INSECURE_CONTENT_BUTTON
-IDS_ALLOW_INSECURE_LOCALHOST
-IDS_ALLOW_INSECURE_LOCALHOST_DESCRIPTION
-IDS_ALTERNATE_NAV_URL_VIEW_LABEL
-IDS_APP_CANCEL
-IDS_APP_OK
-IDS_APP_UNTITLED_SHORTCUT_FILE_NAME
-IDS_AUTOFILL_CARD_UNMASK_CONFIRM_BUTTON
-IDS_AUTOFILL_CARD_UNMASK_EXPIRATION_DATE_SEPARATOR
-IDS_AUTOFILL_CARD_UNMASK_INVALID_EXPIRATION_DATE
-IDS_AUTOFILL_CARD_UNMASK_NEW_CARD_LINK
-IDS_AUTOFILL_CARD_UNMASK_PROMPT_STORAGE_CHECKBOX
-IDS_AUTOFILL_CARD_UNMASK_PROMPT_STORAGE_TOOLTIP_IOS
-IDS_AUTOFILL_CARD_UNMASK_VERIFICATION_IN_PROGRESS
-IDS_AUTOFILL_CARD_UNMASK_VERIFICATION_SUCCESS
-IDS_AUTOFILL_CLEAR_LOCAL_COPY_BUTTON
-IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC
-IDS_AUTOLOGIN_INFOBAR_CANCEL_BUTTON
-IDS_AUTOLOGIN_INFOBAR_MESSAGE
-IDS_AUTOLOGIN_INFOBAR_OK_BUTTON
-IDS_BLOCKED_DISPLAYING_INSECURE_CONTENT
-IDS_BLOCK_INSECURE_CONTENT_BUTTON
-IDS_BOOKMARK_ADD_EDITOR_TITLE
-IDS_BOOKMARK_ALL_TABS_DIALOG_TITLE
-IDS_BOOKMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER
-IDS_BOOKMARK_BUBBLE_REMOVE_BOOKMARK
-IDS_BOOKMARK_EDITOR_CONFIRM_DELETE
-IDS_BOOKMARK_EDITOR_NEW_FOLDER_NAME
-IDS_BOOKMARK_EDITOR_TITLE
-IDS_BOOKMARK_FOLDER_CHOOSER_TITLE
-IDS_BOOKMARK_FOLDER_EDITOR_TITLE
-IDS_BOOKMARK_FOLDER_EDITOR_WINDOW_TITLE
-IDS_BOOKMARK_FOLDER_EDITOR_WINDOW_TITLE_NEW
-IDS_BOOKMARK_MANAGER_FOLDER_SECTION
-IDS_BOOKMARK_MANAGER_FOLDER_TITLE
-IDS_BOOKMARK_MANAGER_NAME_INPUT_PLACE_HOLDER
-IDS_BOOKMARK_MANAGER_REMOVE_TITLE
-IDS_BOOKMARK_MANAGER_URL_INPUT_PLACE_HOLDER
-IDS_BOOKMARK_NEW_FOLDER_BUTTON_TITLE
-IDS_CANCEL
-IDS_CHILD_AVATAR_LABEL
-IDS_CHROME_TO_DEVICE_PRINT_TO_PHONE
-IDS_CHROME_TO_DEVICE_SNAPSHOTS
-IDS_CLOSE
-IDS_CONTEXTUAL_SEARCH_HEADER
-IDS_CONTEXTUAL_SEARCH_PROMO_DESCRIPTION_1
-IDS_CONTEXTUAL_SEARCH_PROMO_DESCRIPTION_2
-IDS_CONTEXTUAL_SEARCH_PROMO_FEATURE_NAME
-IDS_CONTEXTUAL_SEARCH_PROMO_OPTIN
-IDS_CONTEXTUAL_SEARCH_PROMO_OPTOUT
-IDS_COULDNT_OPEN_PROFILE_ERROR
-IDS_CRASHES_BUG_LINK_LABEL
-IDS_CRASHES_CRASH_COUNT_BANNER_FORMAT
-IDS_CRASHES_CRASH_HEADER_FORMAT
-IDS_CRASHES_CRASH_TIME_FORMAT
-IDS_CRASHES_DISABLED_HEADER
-IDS_CRASHES_DISABLED_MESSAGE
-IDS_CRASHES_NO_CRASHES_MESSAGE
-IDS_CRASHES_TITLE
-IDS_CRASHES_UPLOAD_MESSAGE
-IDS_DEFAULT_AVATAR_NAME_10
-IDS_DEFAULT_AVATAR_NAME_11
-IDS_DEFAULT_AVATAR_NAME_12
-IDS_DEFAULT_AVATAR_NAME_13
-IDS_DEFAULT_AVATAR_NAME_14
-IDS_DEFAULT_AVATAR_NAME_15
-IDS_DEFAULT_AVATAR_NAME_16
-IDS_DEFAULT_AVATAR_NAME_17
-IDS_DEFAULT_AVATAR_NAME_18
-IDS_DEFAULT_AVATAR_NAME_19
-IDS_DEFAULT_AVATAR_NAME_20
-IDS_DEFAULT_AVATAR_NAME_21
-IDS_DEFAULT_AVATAR_NAME_22
-IDS_DEFAULT_AVATAR_NAME_23
-IDS_DEFAULT_AVATAR_NAME_24
-IDS_DEFAULT_AVATAR_NAME_25
-IDS_DEFAULT_AVATAR_NAME_26
-IDS_DEFAULT_AVATAR_NAME_8
-IDS_DEFAULT_AVATAR_NAME_9
-IDS_DEFAULT_ENCODING
-IDS_DEFAULT_PROFILE_NAME
-IDS_DEFAULT_TAB_TITLE
-IDS_DELETE
-IDS_DISABLE_TOUCH_ADJUSTMENT_DESCRIPTION
-IDS_DISABLE_TOUCH_ADJUSTMENT_NAME
-IDS_DONE
-IDS_EASY_UNLOCK_SCREENLOCK_USER_POD_AUTH_VALUE
-IDS_EDIT_FIND_MAC
-IDS_ERRORPAGES_BUTTON_DIAGNOSE
-IDS_ERRORPAGES_BUTTON_LESS
-IDS_ERRORPAGES_BUTTON_MORE
-IDS_ERRORPAGES_BUTTON_RELOAD
-IDS_ERRORPAGES_BUTTON_SHOW_SAVED_COPY
-IDS_ERRORPAGES_BUTTON_SHOW_SAVED_COPY_HELP
-IDS_ERRORPAGES_DETAILS_ADDRESS_UNREACHABLE
-IDS_ERRORPAGES_DETAILS_BAD_GATEWAY
-IDS_ERRORPAGES_DETAILS_BAD_SSL_CLIENT_AUTH_CERT
-IDS_ERRORPAGES_DETAILS_BLOCKED
-IDS_ERRORPAGES_DETAILS_BLOCKED_BY_ADMINISTRATOR
-IDS_ERRORPAGES_DETAILS_BLOCKED_ENROLLMENT_CHECK_PENDING
-IDS_ERRORPAGES_DETAILS_CACHE_MISS
-IDS_ERRORPAGES_DETAILS_CACHE_READ_FAILURE
-IDS_ERRORPAGES_DETAILS_CONNECTION_CLOSED
-IDS_ERRORPAGES_DETAILS_CONNECTION_FAILED
-IDS_ERRORPAGES_DETAILS_CONNECTION_REFUSED
-IDS_ERRORPAGES_DETAILS_CONNECTION_RESET
-IDS_ERRORPAGES_DETAILS_DNS_PROBE_RUNNING
-IDS_ERRORPAGES_DETAILS_DOWNLOAD_FILE_TYPE_ERROR
-IDS_ERRORPAGES_DETAILS_EMPTY_RESPONSE
-IDS_ERRORPAGES_DETAILS_FILE_ACCESS_DENIED
-IDS_ERRORPAGES_DETAILS_FILE_NOT_FOUND
-IDS_ERRORPAGES_DETAILS_FORBIDDEN
-IDS_ERRORPAGES_DETAILS_GATEWAY_TIMEOUT
-IDS_ERRORPAGES_DETAILS_GONE
-IDS_ERRORPAGES_DETAILS_HTTP_VERSION_NOT_SUPPORTED
-IDS_ERRORPAGES_DETAILS_ICANN_NAME_COLLISION
-IDS_ERRORPAGES_DETAILS_INTERNAL_SERVER_ERROR
-IDS_ERRORPAGES_DETAILS_INTERNET_DISCONNECTED
-IDS_ERRORPAGES_DETAILS_NAME_NOT_RESOLVED
-IDS_ERRORPAGES_DETAILS_NETWORK_ACCESS_DENIED
-IDS_ERRORPAGES_DETAILS_NETWORK_CHANGED
-IDS_ERRORPAGES_DETAILS_NETWORK_IO_SUSPENDED
-IDS_ERRORPAGES_DETAILS_NOT_IMPLEMENTED
-IDS_ERRORPAGES_DETAILS_PROXY_CONNECTION_FAILED
-IDS_ERRORPAGES_DETAILS_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION
-IDS_ERRORPAGES_DETAILS_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH
-IDS_ERRORPAGES_DETAILS_RESPONSE_HEADERS_MULTIPLE_LOCATION
-IDS_ERRORPAGES_DETAILS_SERVICE_UNAVAILABLE
-IDS_ERRORPAGES_DETAILS_SSL_FALLBACK_BEYOND_MINIMUM_VERSION
-IDS_ERRORPAGES_DETAILS_SSL_PROTOCOL_ERROR
-IDS_ERRORPAGES_DETAILS_SSL_VERSION_OR_CIPHER_MISMATCH
-IDS_ERRORPAGES_DETAILS_TEMPORARILY_THROTTLED
-IDS_ERRORPAGES_DETAILS_TEMPORARY_BACKOFF
-IDS_ERRORPAGES_DETAILS_TIMED_OUT
-IDS_ERRORPAGES_DETAILS_TOO_MANY_REDIRECTS
-IDS_ERRORPAGES_DETAILS_UNKNOWN
-IDS_ERRORPAGES_HEADING_ACCESS_DENIED
-IDS_ERRORPAGES_HEADING_BAD_SSL_CLIENT_AUTH_CERT
-IDS_ERRORPAGES_HEADING_BLOCKED
-IDS_ERRORPAGES_HEADING_BLOCKED_BY_ADMINISTRATOR
-IDS_ERRORPAGES_HEADING_CACHE_MISS
-IDS_ERRORPAGES_HEADING_CACHE_READ_FAILURE
-IDS_ERRORPAGES_HEADING_DOWNLOAD_FILE_TYPE_ERROR
-IDS_ERRORPAGES_HEADING_DUPLICATE_HEADERS
-IDS_ERRORPAGES_HEADING_EMPTY_RESPONSE
-IDS_ERRORPAGES_HEADING_FILE_ACCESS_DENIED
-IDS_ERRORPAGES_HEADING_HTTP_SERVER_ERROR
-IDS_ERRORPAGES_HEADING_INTERNET_DISCONNECTED
-IDS_ERRORPAGES_HEADING_NETWORK_ACCESS_DENIED
-IDS_ERRORPAGES_HEADING_NETWORK_IO_SUSPENDED
-IDS_ERRORPAGES_HEADING_NOT_AVAILABLE
-IDS_ERRORPAGES_HEADING_NOT_FOUND
-IDS_ERRORPAGES_HEADING_PINNING_FAILURE
-IDS_ERRORPAGES_HEADING_PROXY_CONNECTION_FAILED
-IDS_ERRORPAGES_HEADING_SSL_FALLBACK_BEYOND_MINIMUM_VERSION
-IDS_ERRORPAGES_HEADING_SSL_PROTOCOL_ERROR
-IDS_ERRORPAGES_HEADING_SSL_VERSION_OR_CIPHER_MISMATCH
-IDS_ERRORPAGES_HEADING_TOO_MANY_REDIRECTS
-IDS_ERRORPAGES_HEADING_WEAK_SERVER_EPHEMERAL_DH_KEY
-IDS_ERRORPAGES_HTTP_POST_WARNING
-IDS_ERRORPAGES_SUGGESTION_CHECK_CONNECTION_BODY
-IDS_ERRORPAGES_SUGGESTION_CHECK_CONNECTION_HEADER
-IDS_ERRORPAGES_SUGGESTION_GOOGLE_SEARCH
-IDS_ERRORPAGES_SUGGESTION_LEARNMORE_BODY
-IDS_ERRORPAGES_SUGGESTION_PROXY_DISABLE_PLATFORM
-IDS_ERRORPAGES_SUGGESTION_RELOAD_REPOST_BODY
-IDS_ERRORPAGES_SUGGESTION_RELOAD_REPOST_HEADER
-IDS_ERRORPAGES_SUMMARY_ADDRESS_UNREACHABLE
-IDS_ERRORPAGES_SUMMARY_BAD_GATEWAY
-IDS_ERRORPAGES_SUMMARY_BAD_SSL_CLIENT_AUTH_CERT
-IDS_ERRORPAGES_SUMMARY_BLOCKED
-IDS_ERRORPAGES_SUMMARY_BLOCKED_BY_ADMINISTRATOR
-IDS_ERRORPAGES_SUMMARY_BLOCKED_ENROLLMENT_CHECK_PENDING
-IDS_ERRORPAGES_SUMMARY_CACHE_MISS
-IDS_ERRORPAGES_SUMMARY_CACHE_READ_FAILURE
-IDS_ERRORPAGES_SUMMARY_CONNECTION_REFUSED
-IDS_ERRORPAGES_SUMMARY_CONNECTION_RESET
-IDS_ERRORPAGES_SUMMARY_DNS_PROBE_RUNNING
-IDS_ERRORPAGES_SUMMARY_DOWNLOAD_FILE_TYPE_ERROR
-IDS_ERRORPAGES_SUMMARY_DUPLICATE_HEADERS
-IDS_ERRORPAGES_SUMMARY_EMPTY_RESPONSE
-IDS_ERRORPAGES_SUMMARY_FILE_ACCESS_DENIED
-IDS_ERRORPAGES_SUMMARY_FORBIDDEN
-IDS_ERRORPAGES_SUMMARY_GATEWAY_TIMEOUT
-IDS_ERRORPAGES_SUMMARY_GONE
-IDS_ERRORPAGES_SUMMARY_ICANN_NAME_COLLISION
-IDS_ERRORPAGES_SUMMARY_INTERNAL_SERVER_ERROR
-IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED
-IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED_INSTRUCTIONS_TEMPLATE
-IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED_PLATFORM
-IDS_ERRORPAGES_SUMMARY_NAME_NOT_RESOLVED
-IDS_ERRORPAGES_SUMMARY_NETWORK_ACCESS_DENIED
-IDS_ERRORPAGES_SUMMARY_NETWORK_CHANGED
-IDS_ERRORPAGES_SUMMARY_NETWORK_IO_SUSPENDED
-IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE
-IDS_ERRORPAGES_SUMMARY_NOT_FOUND
-IDS_ERRORPAGES_SUMMARY_PROXY_CONNECTION_FAILED
-IDS_ERRORPAGES_SUMMARY_SERVICE_UNAVAILABLE
-IDS_ERRORPAGES_SUMMARY_SSL_FALLBACK_BEYOND_MINIMUM_VERSION
-IDS_ERRORPAGES_SUMMARY_SSL_PROTOCOL_ERROR
-IDS_ERRORPAGES_SUMMARY_SSL_VERSION_OR_CIPHER_MISMATCH
-IDS_ERRORPAGES_SUMMARY_TEMPORARILY_THROTTLED
-IDS_ERRORPAGES_SUMMARY_TEMPORARY_BACKOFF
-IDS_ERRORPAGES_SUMMARY_TIMED_OUT
-IDS_ERRORPAGES_SUMMARY_TOO_MANY_REDIRECTS
-IDS_ERRORPAGES_SUMMARY_WEAK_SERVER_EPHEMERAL_DH_KEY
-IDS_ERRORPAGES_SUMMARY_WEBSITE_CANNOT_HANDLE
-IDS_ERRORPAGES_TITLE_ACCESS_DENIED
-IDS_ERRORPAGES_TITLE_BLOCKED
-IDS_ERRORPAGES_TITLE_LOAD_FAILED
-IDS_ERRORPAGES_TITLE_NOT_AVAILABLE
-IDS_ERRORPAGES_TITLE_NOT_FOUND
-IDS_ERRORPAGE_FUN_DISABLED
-IDS_ERRORPAGE_NET_BUTTON_DETAILS
-IDS_ERRORPAGE_NET_BUTTON_HIDE_DETAILS
-IDS_FEEDBACK_REPORT_PAGE_TITLE
-IDS_FEEDBACK_REPORT_URL_LABEL
-IDS_FEEDBACK_SEND_REPORT
-IDS_FEEDBACK_USER_EMAIL_LABEL
-IDS_FIND_IN_PAGE_CLOSE_TOOLTIP
-IDS_FIND_IN_PAGE_COUNT
-IDS_FIND_IN_PAGE_NEXT_TOOLTIP
-IDS_FIND_IN_PAGE_PREVIOUS_TOOLTIP
-IDS_FULLSCREEN
-IDS_GROUP_BY_DOMAIN_LABEL
-IDS_GUEST_PROFILE_NAME
-IDS_HARMFUL_V3_EXPLANATION_PARAGRAPH
-IDS_HARMFUL_V3_HEADING
-IDS_HARMFUL_V3_PRIMARY_PARAGRAPH
-IDS_HARMFUL_V3_PROCEED_PARAGRAPH
-IDS_HELPER_NAME
-IDS_HISTORY_ACTION_MENU_DESCRIPTION
-IDS_HISTORY_BLOCKED_VISIT_TEXT
-IDS_HISTORY_BROWSERESULTS
-IDS_HISTORY_CONTINUED
-IDS_HISTORY_DATE_WITH_RELATIVE_TIME
-IDS_HISTORY_DELETE_PRIOR_VISITS_CONFIRM_BUTTON
-IDS_HISTORY_DELETE_PRIOR_VISITS_WARNING
-IDS_HISTORY_DELETE_PRIOR_VISITS_WARNING_NO_INCOGNITO
-IDS_HISTORY_FILTER_ALLOWED
-IDS_HISTORY_FILTER_ALLOW_ITEMS
-IDS_HISTORY_FILTER_BLOCKED
-IDS_HISTORY_FILTER_BLOCK_ITEMS
-IDS_HISTORY_FOUND_SEARCH_RESULTS
-IDS_HISTORY_HAS_SYNCED_RESULTS
-IDS_HISTORY_INTERVAL
-IDS_HISTORY_IN_CONTENT_PACK
-IDS_HISTORY_LOADING
-IDS_HISTORY_MORE_FROM_SITE
-IDS_HISTORY_NEWER
-IDS_HISTORY_NEWEST
-IDS_HISTORY_NO_RESULTS
-IDS_HISTORY_NO_SEARCH_RESULTS
-IDS_HISTORY_NO_SYNCED_RESULTS
-IDS_HISTORY_NUMBER_VISITS
-IDS_HISTORY_OLDER
-IDS_HISTORY_OPEN_CLEAR_BROWSING_DATA_DIALOG
-IDS_HISTORY_OTHER_DEVICES_X_MORE
-IDS_HISTORY_OTHER_SESSIONS_COLLAPSE_SESSION
-IDS_HISTORY_OTHER_SESSIONS_EXPAND_SESSION
-IDS_HISTORY_OTHER_SESSIONS_OPEN_ALL
-IDS_HISTORY_RANGE_ALL_TIME
-IDS_HISTORY_RANGE_LABEL
-IDS_HISTORY_RANGE_MONTH
-IDS_HISTORY_RANGE_NEXT
-IDS_HISTORY_RANGE_PREVIOUS
-IDS_HISTORY_RANGE_TODAY
-IDS_HISTORY_RANGE_WEEK
-IDS_HISTORY_REMOVE_BOOKMARK
-IDS_HISTORY_REMOVE_PAGE
-IDS_HISTORY_REMOVE_SELECTED_ITEMS
-IDS_HISTORY_SEARCHRESULTSFOR
-IDS_HISTORY_SEARCH_BUTTON
-IDS_HISTORY_SEARCH_RESULT
-IDS_HISTORY_SEARCH_RESULTS
-IDS_HISTORY_TITLE
-IDS_HISTORY_UNKNOWN_DEVICE
-IDS_HTTP_POST_WARNING
-IDS_HTTP_POST_WARNING_RESEND
-IDS_HTTP_POST_WARNING_TITLE
-IDS_IMPORT_FROM_FIREFOX
-IDS_IMPORT_FROM_ICEWEASEL
-IDS_LEGACY_DEFAULT_PROFILE_NAME
-IDS_LEGACY_SUPERVISED_USER_NEW_AVATAR_LABEL
-IDS_LIBADDRESSINPUT_ADDRESS_LINE_1_LABEL
-IDS_LIBADDRESSINPUT_AREA
-IDS_LIBADDRESSINPUT_COUNTRY_OR_REGION_LABEL
-IDS_LIBADDRESSINPUT_COUNTY
-IDS_LIBADDRESSINPUT_DEPARTMENT
-IDS_LIBADDRESSINPUT_DISTRICT
-IDS_LIBADDRESSINPUT_DO_SI
-IDS_LIBADDRESSINPUT_EMIRATE
-IDS_LIBADDRESSINPUT_ISLAND
-IDS_LIBADDRESSINPUT_LOCALITY_LABEL
-IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_POSTAL_CODE
-IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_POSTAL_CODE_URL
-IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_ZIP
-IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_ZIP_URL
-IDS_LIBADDRESSINPUT_MISSING_REQUIRED_FIELD
-IDS_LIBADDRESSINPUT_MISSING_REQUIRED_POSTAL_CODE_EXAMPLE
-IDS_LIBADDRESSINPUT_MISSING_REQUIRED_POSTAL_CODE_EXAMPLE_AND_URL
-IDS_LIBADDRESSINPUT_MISSING_REQUIRED_ZIP_CODE_EXAMPLE
-IDS_LIBADDRESSINPUT_MISSING_REQUIRED_ZIP_CODE_EXAMPLE_AND_URL
-IDS_LIBADDRESSINPUT_NEIGHBORHOOD
-IDS_LIBADDRESSINPUT_OBLAST
-IDS_LIBADDRESSINPUT_ORGANIZATION_LABEL
-IDS_LIBADDRESSINPUT_PARISH
-IDS_LIBADDRESSINPUT_PIN_CODE_LABEL
-IDS_LIBADDRESSINPUT_POSTAL_CODE_LABEL
-IDS_LIBADDRESSINPUT_POST_TOWN
-IDS_LIBADDRESSINPUT_PO_BOX_FORBIDDEN_VALUE
-IDS_LIBADDRESSINPUT_PREFECTURE
-IDS_LIBADDRESSINPUT_PROVINCE
-IDS_LIBADDRESSINPUT_RECIPIENT_LABEL
-IDS_LIBADDRESSINPUT_STATE
-IDS_LIBADDRESSINPUT_SUBURB
-IDS_LIBADDRESSINPUT_UNKNOWN_VALUE
-IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE
-IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE_EXAMPLE
-IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE_EXAMPLE_AND_URL
-IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP
-IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP_CODE_EXAMPLE
-IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP_CODE_EXAMPLE_AND_URL
-IDS_LIBADDRESSINPUT_VILLAGE_TOWNSHIP
-IDS_LIBADDRESSINPUT_ZIP_CODE_LABEL
-IDS_LOGIN_DIALOG_OK_BUTTON_LABEL
-IDS_LOGIN_DIALOG_PASSWORD_FIELD
-IDS_LOGIN_DIALOG_TITLE
-IDS_LOGIN_DIALOG_USERNAME_FIELD
-IDS_MALWARE_V3_ADVICE_HEADING
-IDS_MALWARE_V3_EXPLANATION_PARAGRAPH
-IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_ADVICE
-IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_HISTORY
-IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE
-IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE_ADVICE
-IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE_HISTORY
-IDS_MALWARE_V3_HEADING
-IDS_MALWARE_V3_PRIMARY_PARAGRAPH
-IDS_MALWARE_V3_PROCEED_PARAGRAPH
-IDS_MALWARE_V3_PROCEED_PARAGRAPH_NOT_RECOMMEND
-IDS_MALWARE_V3_PROCEED_PARAGRAPH_SOCIAL
-IDS_MIDI_SYSEX_INFOBAR_QUESTION
-IDS_MIDI_SYSEX_PERMISSION_FRAGMENT
-IDS_MOBILE_WELCOME_URL
-IDS_NACL_DEBUG_MASK_CHOICE_DEBUG_ALL
-IDS_NACL_DEBUG_MASK_CHOICE_EXCLUDE_UTILS_PNACL
-IDS_NACL_DEBUG_MASK_CHOICE_INCLUDE_DEBUG
-IDS_NETWORK_PREDICTION_ENABLED_DESCRIPTION
-IDS_NEW_INCOGNITO_WINDOW_MAC
-IDS_NEW_NUMBERED_PROFILE_NAME
-IDS_NEW_TAB_CHROME_WELCOME_PAGE_TITLE
-IDS_NEW_TAB_MOST_VISITED
-IDS_NEW_TAB_RESTORE_THUMBNAILS_SHORT_LINK
-IDS_NEW_TAB_THUMBNAIL_REMOVED_NOTIFICATION
-IDS_NEW_TAB_TITLE
-IDS_NEW_TAB_UNDO_THUMBNAIL_REMOVE
-IDS_NUMBERED_PROFILE_NAME
-IDS_OK
-IDS_OMNIBOX_EMPTY_HINT
-IDS_ONE_CLICK_SIGNIN_CONFIRM_EMAIL_DIALOG_CANCEL_BUTTON
-IDS_OPEN_TABS_NOTYETSYNCED
-IDS_OPEN_TABS_PROMOCOMPUTER
-IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY
-IDS_OPTIONS_DISABLE_WEB_SERVICES
-IDS_OPTIONS_ENABLE_LOGGING
-IDS_OPTIONS_IMPROVE_BROWSING_EXPERIENCE
-IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON
-IDS_PAGEINFO_CERT_INFO_BUTTON
-IDS_PAGE_INFO_HELP_CENTER_LINK
-IDS_PAGE_INFO_INTERNAL_PAGE
-IDS_PAGE_INFO_SECURITY_BUTTON_ACCESSIBILITY_LABEL
-IDS_PAGE_INFO_SECURITY_TAB_DEPRECATED_SIGNATURE_ALGORITHM_MAJOR
-IDS_PAGE_INFO_SECURITY_TAB_DEPRECATED_SIGNATURE_ALGORITHM_MINOR
-IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_CONNECTION_TEXT
-IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_ERROR
-IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_WARNING
-IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_SENTENCE_LINK
-IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTION_DETAILS
-IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTION_DETAILS_AEAD
-IDS_PAGE_INFO_SECURITY_TAB_FALLBACK_MESSAGE
-IDS_PAGE_INFO_SECURITY_TAB_INSECURE_IDENTITY
-IDS_PAGE_INFO_SECURITY_TAB_NON_UNIQUE_NAME
-IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT
-IDS_PAGE_INFO_SECURITY_TAB_NO_REVOCATION_MECHANISM
-IDS_PAGE_INFO_SECURITY_TAB_RENEGOTIATION_MESSAGE
-IDS_PAGE_INFO_SECURITY_TAB_SSL_VERSION
-IDS_PAGE_INFO_SECURITY_TAB_UNABLE_TO_CHECK_REVOCATION
-IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY
-IDS_PAGE_INFO_SECURITY_TAB_WEAK_ENCRYPTION_CONNECTION_TEXT
-IDS_PASSWORDS_EXCEPTIONS_TAB_TITLE
-IDS_PASSWORDS_SHOW_PASSWORDS_TAB_TITLE
-IDS_PASSWORD_MANAGER_BLACKLIST_BUTTON
-IDS_PASSWORD_MANAGER_SAVE_BUTTON
-IDS_PASSWORD_MANAGER_SMART_LOCK
-IDS_PAST_TIME_TODAY
-IDS_PAST_TIME_YESTERDAY
-IDS_PDF_INFOBAR_ALWAYS_USE_READER_BUTTON
-IDS_PERMISSION_ALLOW
-IDS_PERMISSION_DENY
-IDS_PHISHING_V3_EXPLANATION_PARAGRAPH
-IDS_PHISHING_V3_HEADING
-IDS_PHISHING_V3_PRIMARY_PARAGRAPH
-IDS_PHISHING_V3_PROCEED_PARAGRAPH
-IDS_PHISHING_V4_HEADING
-IDS_PHISHING_V4_PRIMARY_PARAGRAPH
-IDS_PHISHING_V4_PROCEED_AND_REPORT_PARAGRAPH
-IDS_PLATFORM_LABEL
-IDS_PLUGIN_CONFIRM_INSTALL_DIALOG_ACCEPT_BUTTON
-IDS_PLUGIN_CONFIRM_INSTALL_DIALOG_TITLE
-IDS_PLUGIN_NOT_SUPPORTED
-IDS_POLICY_RISK_TAG_ADMIN_SHARING
-IDS_POLICY_RISK_TAG_FILTERING
-IDS_POLICY_RISK_TAG_FULL_ADMIN_ACCESS
-IDS_POLICY_RISK_TAG_GOOGLE_SHARING
-IDS_POLICY_RISK_TAG_LOCAL_DATA_ACCESS
-IDS_POLICY_RISK_TAG_SYSTEM_SECURITY
-IDS_POLICY_RISK_TAG_WEBSITE_SHARING
-IDS_PREFERENCES_CORRUPT_ERROR
-IDS_PREFERENCES_UNREADABLE_ERROR
-IDS_PRINT
-IDS_PRIVACY_POLICY_URL
-IDS_PRODUCT_NAME
-IDS_PROFILES_GUEST_PROFILE_NAME
-IDS_PROFILES_LOCAL_PROFILE_STATE
-IDS_PROFILE_TOO_NEW_ERROR
-IDS_PUSH_MESSAGES_BUBBLE_FRAGMENT
-IDS_PUSH_MESSAGES_PERMISSION_QUESTION
-IDS_RECENTLY_CLOSED
-IDS_RECENT_TABS_MENU
-IDS_SAD_TAB_HELP_LINK
-IDS_SAD_TAB_HELP_MESSAGE
-IDS_SAD_TAB_MESSAGE
-IDS_SAD_TAB_RELOAD_LABEL
-IDS_SAD_TAB_TITLE
-IDS_SAFEBROWSING_OVERRIDABLE_SAFETY_BUTTON
-IDS_SAFEBROWSING_V3_CLOSE_DETAILS_BUTTON
-IDS_SAFEBROWSING_V3_OPEN_DETAILS_BUTTON
-IDS_SAFEBROWSING_V3_TITLE
-IDS_SAFE_BROWSING_MALWARE_REPORTING_AGREE
-IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE
-IDS_SAFE_BROWSING_PRIVACY_POLICY_URL
-IDS_SAVE
-IDS_SAVE_PASSWORD
-IDS_SAVE_PASSWORD_TITLE_BRAND
-IDS_SEARCH_BOX_EMPTY_HINT
-IDS_SECURE_CONNECTION_EV
-IDS_SESSION_CRASHED_VIEW_MESSAGE
-IDS_SESSION_CRASHED_VIEW_RESTORE_BUTTON
-IDS_SETTINGS_SHOW_ADVANCED_SETTINGS
-IDS_SHORT_PRODUCT_NAME
-IDS_SHOWFULLHISTORY_LINK
-IDS_SHOW_HISTORY
-IDS_SIGNED_IN_WITH_SYNC_DISABLED
-IDS_SIGNED_IN_WITH_SYNC_SUPPRESSED
-IDS_SIGNIN_ERROR_BUBBLE_VIEW_TITLE
-IDS_SINGLE_PROFILE_DISPLAY_NAME
-IDS_SSL_NONOVERRIDABLE_HSTS
-IDS_SSL_NONOVERRIDABLE_INVALID
-IDS_SSL_NONOVERRIDABLE_MORE
-IDS_SSL_NONOVERRIDABLE_MORE_INVALID_SP3
-IDS_SSL_NONOVERRIDABLE_PINNED
-IDS_SSL_NONOVERRIDABLE_REVOKED
-IDS_SSL_OVERRIDABLE_PROCEED_PARAGRAPH
-IDS_SSL_OVERRIDABLE_SAFETY_BUTTON
-IDS_SSL_RELOAD
-IDS_SSL_V2_HEADING
-IDS_SSL_V2_PRIMARY_PARAGRAPH
-IDS_SSL_V2_TITLE
-IDS_SYNC_ACCOUNT_SYNCING_TO_USER
-IDS_SYNC_ACCOUNT_SYNCING_TO_USER_WITH_MANAGE_LINK
-IDS_SYNC_AUTHENTICATING_LABEL
-IDS_SYNC_BASIC_ENCRYPTION_DATA
-IDS_SYNC_CLEAR_USER_DATA
-IDS_SYNC_CONFIGURE_ENCRYPTION
-IDS_SYNC_DATATYPE_AUTOFILL
-IDS_SYNC_DATATYPE_BOOKMARKS
-IDS_SYNC_DATATYPE_PASSWORDS
-IDS_SYNC_DATATYPE_PREFERENCES
-IDS_SYNC_DATATYPE_TABS
-IDS_SYNC_DATATYPE_TYPED_URLS
-IDS_SYNC_EMPTY_PASSPHRASE_ERROR
-IDS_SYNC_ENABLE_SYNC_ON_ACCOUNT
-IDS_SYNC_ENCRYPTION_SECTION_TITLE
-IDS_SYNC_ENTER_GOOGLE_PASSPHRASE_BODY
-IDS_SYNC_ENTER_PASSPHRASE_BODY
-IDS_SYNC_ENTER_PASSPHRASE_BODY_WITH_DATE
-IDS_SYNC_ERROR_BUBBLE_VIEW_TITLE
-IDS_SYNC_ERROR_SIGNING_IN
-IDS_SYNC_FULL_ENCRYPTION_DATA
-IDS_SYNC_INVALID_USER_CREDENTIALS
-IDS_SYNC_LOGIN_INFO_OUT_OF_DATE
-IDS_SYNC_LOGIN_SETTING_UP
-IDS_SYNC_MENU_PRE_SYNCED_LABEL
-IDS_SYNC_MENU_SYNCED_LABEL
-IDS_SYNC_NTP_PASSWORD_ENABLE
-IDS_SYNC_NTP_PASSWORD_PROMO
-IDS_SYNC_NTP_SETUP_IN_PROGRESS
-IDS_SYNC_OPTIONS_GROUP_NAME
-IDS_SYNC_OTHER_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE
-IDS_SYNC_PASSPHRASE_ERROR_BUBBLE_VIEW_ACCEPT
-IDS_SYNC_PASSPHRASE_ERROR_BUBBLE_VIEW_MESSAGE
-IDS_SYNC_PASSPHRASE_ERROR_WRENCH_MENU_ITEM
-IDS_SYNC_PASSPHRASE_LABEL
-IDS_SYNC_PASSPHRASE_MISMATCH_ERROR
-IDS_SYNC_PASSPHRASE_MSG_EXPLICIT_POSTFIX
-IDS_SYNC_PASSPHRASE_MSG_EXPLICIT_PREFIX
-IDS_SYNC_PASSWORD_SYNC_ATTENTION
-IDS_SYNC_PROMO_NTP_BUBBLE_MESSAGE
-IDS_SYNC_PROMO_TAB_TITLE
-IDS_SYNC_RELOGIN_LINK_LABEL
-IDS_SYNC_SERVER_IS_UNREACHABLE
-IDS_SYNC_SERVICE_UNAVAILABLE
-IDS_SYNC_SETUP_ERROR
-IDS_SYNC_SIGN_IN_ERROR_BUBBLE_VIEW_ACCEPT
-IDS_SYNC_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE
-IDS_SYNC_SIGN_IN_ERROR_WRENCH_MENU_ITEM
-IDS_SYNC_START_SYNC_BUTTON_LABEL
-IDS_SYNC_STATUS_UNRECOVERABLE_ERROR
-IDS_SYNC_STOP_AND_RESTART_SYNC
-IDS_SYNC_UNAVAILABLE_ERROR_BUBBLE_VIEW_ACCEPT
-IDS_SYNC_UNAVAILABLE_ERROR_BUBBLE_VIEW_MESSAGE
-IDS_SYNC_UNRECOVERABLE_ERROR_HELP_URL
-IDS_SYNC_UPGRADE_CLIENT
-IDS_SYSTEM_FLAGS_OWNER_ONLY
-IDS_TERMS_HTML
-IDS_TIME_DAYS
-IDS_TIME_DAYS_1ST
-IDS_TIME_ELAPSED_DAYS
-IDS_TIME_ELAPSED_HOURS
-IDS_TIME_ELAPSED_MINS
-IDS_TIME_ELAPSED_SECS
-IDS_TIME_HOURS
-IDS_TIME_HOURS_1ST
-IDS_TIME_HOURS_2ND
-IDS_TIME_LONG_MINS
-IDS_TIME_LONG_MINS_1ST
-IDS_TIME_LONG_MINS_2ND
-IDS_TIME_LONG_SECS
-IDS_TIME_LONG_SECS_2ND
-IDS_TIME_MINS
-IDS_TIME_REMAINING_DAYS
-IDS_TIME_REMAINING_HOURS
-IDS_TIME_REMAINING_LONG_MINS
-IDS_TIME_REMAINING_LONG_SECS
-IDS_TIME_REMAINING_MINS
-IDS_TIME_REMAINING_SECS
-IDS_TIME_SECS
-IDS_TOOLTIP_STAR
-IDS_TOUCH_EVENTS_DESCRIPTION
-IDS_TOUCH_EVENTS_NAME
-IDS_UPGRADE_AVAILABLE
-IDS_UPGRADE_AVAILABLE_BUTTON
-IDS_VERSION_UI_COMMAND_LINE
-IDS_VERSION_UI_EXECUTABLE_PATH
-IDS_VERSION_UI_OFFICIAL
-IDS_VERSION_UI_OS
-IDS_VERSION_UI_PATH_NOTFOUND
-IDS_VERSION_UI_PROFILE_PATH
-IDS_VERSION_UI_REVISION
-IDS_VERSION_UI_TITLE
-IDS_VERSION_UI_UNOFFICIAL
-IDS_VERSION_UI_USER_AGENT
-IDS_VERSION_UI_VARIATIONS
-IDS_WEB_FONT_FAMILY
-IDS_WEB_FONT_SIZE
diff --git a/build/linux/sysroot_scripts/install-sysroot.py b/build/linux/sysroot_scripts/install-sysroot.py
index b53bd889..a9b0457 100755
--- a/build/linux/sysroot_scripts/install-sysroot.py
+++ b/build/linux/sysroot_scripts/install-sysroot.py
@@ -3,17 +3,18 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# Script to install a Debian Wheezy sysroot for making official Google Chrome
-# Linux builds.
-# The sysroot is needed to make Chrome work for Debian Wheezy.
-# This script can be run manually but is more often run as part of gclient
-# hooks. When run from hooks this script should be a no-op on non-linux
-# platforms.
+"""Install Debian Wheezy sysroots for building chromium.
+"""
+
+# The sysroot is needed to ensure that binaries will run on Debian Wheezy,
+# the oldest supported linux distribution.  This script can be run manually but
+# is more often run as part of gclient hooks. When run from hooks this script
+# in a no-op on non-linux platforms.
 
 # The sysroot image could be constructed from scratch based on the current
 # state or Debian Wheezy but for consistency we currently use a pre-built root
 # image. The image will normally need to be rebuilt every time chrome's build
-# dependancies are changed.
+# dependencies are changed.
 
 import hashlib
 import platform
@@ -25,16 +26,12 @@
 import sys
 
 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
-sys.path.append(os.path.dirname(os.path.dirname(os.path.join(SCRIPT_DIR))))
+sys.path.append(os.path.dirname(os.path.dirname(SCRIPT_DIR)))
 import detect_host_arch
 import gyp_chromium
 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'
@@ -57,6 +54,10 @@
 valid_archs = ('arm', 'i386', 'amd64', 'mips')
 
 
+class Error(Exception):
+  pass
+
+
 def GetSha1(filename):
   sha1 = hashlib.sha1()
   with open(filename, 'rb') as f:
@@ -69,10 +70,32 @@
   return sha1.hexdigest()
 
 
-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.
+def DetectHostArch():
+  # Figure out host arch using build/detect_host_arch.py and
+  # set target_arch to host arch
+  detected_host_arch = detect_host_arch.HostArch()
+  if detected_host_arch == 'x64':
+    return 'amd64'
+  elif detected_host_arch == 'ia32':
+    return 'i386'
+  elif detected_host_arch == 'arm':
+    return 'arm'
+  elif detected_host_arch == 'mips':
+    return 'mips'
+
+  raise Error('Unrecognized host arch: %s' % detected_host_arch)
+
+
+def DetectTargetArch():
+  """Attempt for determine target architecture.
+
+  This works by looking for target_arch in GYP_DEFINES.
+  """
+  # 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)
   target_arch = gyp_defines.get('target_arch')
   if target_arch == 'x64':
     return 'amd64'
@@ -85,55 +108,49 @@
   elif target_arch == 'mipsel':
     return 'mips'
   elif target_arch:
-    raise Exception('Unrecognized target_arch: %s' % target_arch)
-
-  # Figure out host arch using build/detect_host_arch.py and
-  # set target_arch to host arch
-  detected_host_arch = detect_host_arch.HostArch()
-  if detected_host_arch == 'x64':
-    return 'amd64'
-  elif detected_host_arch == 'ia32':
-    return 'i386'
-  elif detected_host_arch == 'arm':
-    return 'arm'
-  elif detected_host_arch == 'mips':
-    return 'mips'
-  else:
-    print "Unknown host arch: %s" % detected_host_arch
+    raise Error('Unrecognized target_arch: %s' % target_arch)
 
   return None
 
 
+def InstallDefaultSysroots():
+  """Install the default set of sysroot images.
+
+  This includes at least the sysroot for host architecture, and the 32-bit
+  sysroot for building the v8 snapshot image.  It can also include the cross
+  compile sysroot for ARM/MIPS if cross compiling environment can be detected.
+  """
+  host_arch = DetectHostArch()
+  InstallSysroot(host_arch)
+
+  if host_arch == 'amd64':
+    InstallSysroot('i386')
+
+  # Finally, if we can detect a non-standard target_arch such as ARM or
+  # MIPS, then install the sysroot too.
+  # Don't attampt to install arm64 since this is currently and android-only
+  # architecture.
+  target_arch = DetectTargetArch()
+  if target_arch and target_arch not in (host_arch, 'i386', 'arm64'):
+    InstallSysroot(target_arch)
+
+
 def main():
   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)
-
-  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'
+  if options.running_as_hook:
+    InstallDefaultSysroots()
   else:
-    target_arch = DetectArch(gyp_defines)
-    if not target_arch:
-      print 'Unable to detect target architecture'
+    if not options.arch:
+      print 'You much specify either --arch or --running-as-hook'
       return 1
+    InstallSysroot(options.arch)
 
-  return _InstallSysroot(target_arch)
+  return 0
 
 
-def _InstallSysroot(target_arch):
+def InstallSysroot(target_arch):
   # The sysroot directory should match the one specified in build/common.gypi.
   # TODO(thestig) Consider putting this else where to avoid having to recreate
   # it on every build.
@@ -159,8 +176,7 @@
     tarball_sha1sum = TARBALL_MIPS_SHA1SUM
     revision = REVISION_MIPS
   else:
-    print 'Unknown architecture: %s' % target_arch
-    assert(False)
+    raise Error('Unknown architecture: %s' % target_arch)
 
   url = '%s/%s/%s/%s' % (URL_PREFIX, URL_PATH, revision, tarball_filename)
 
@@ -170,7 +186,7 @@
       if s.read() == url:
         print 'Debian Wheezy %s root image already up-to-date: %s' % \
             (target_arch, sysroot)
-        return 0
+        return
 
   print 'Installing Debian Wheezy %s root image: %s' % (target_arch, sysroot)
   if os.path.isdir(sysroot):
@@ -183,24 +199,20 @@
   subprocess.check_call(['curl', '--fail', '-L', url, '-o', tarball])
   sha1sum = GetSha1(tarball)
   if sha1sum != tarball_sha1sum:
-    print 'Tarball sha1sum is wrong.'
-    print 'Expected %s, actual: %s' % (tarball_sha1sum, sha1sum)
-    return 1
+    raise Error('Tarball sha1sum is wrong.'
+                'Expected %s, actual: %s' % (tarball_sha1sum, sha1sum))
   subprocess.check_call(['tar', 'xf', tarball, '-C', sysroot])
   os.remove(tarball)
 
   with open(stamp, 'w') as s:
     s.write(url)
-  return 0
 
 
 if __name__ == '__main__':
-  parser = optparse.OptionParser('usage: %prog [OPTIONS]')
+  parser = optparse.OptionParser('usage: %prog [OPTIONS]', description=__doc__)
   parser.add_option('--running-as-hook', action='store_true',
                     default=False, help='Used when running from gclient hooks.'
-                                        ' In this mode the sysroot will only '
-                                        'be installed for official Linux '
-                                        'builds or ARM Linux builds')
+                                        ' Installs default sysroot images.')
   parser.add_option('--arch', type='choice', choices=valid_archs,
                     help='Sysroot architecture: %s' % ', '.join(valid_archs))
   options, _ = parser.parse_args()
diff --git a/build/linux/unbundle/zlib.gyp b/build/linux/unbundle/zlib.gyp
index 0a85ff0..ec80d4a 100644
--- a/build/linux/unbundle/zlib.gyp
+++ b/build/linux/unbundle/zlib.gyp
@@ -44,24 +44,5 @@
         ],
       },
     },
-    {
-      'target_name': 'zip',
-      'type': 'static_library',
-      'dependencies': [
-        'minizip',
-        '../../base/base.gyp:base',
-      ],
-      'include_dirs': [
-        '../..',
-      ],
-      'sources': [
-        'google/zip.cc',
-        'google/zip.h',
-        'google/zip_internal.cc',
-        'google/zip_internal.h',
-        'google/zip_reader.cc',
-        'google/zip_reader.h',
-      ],
-    },
   ],
 }
diff --git a/build/toolchain/get_concurrent_links.py b/build/toolchain/get_concurrent_links.py
index 32294fab..e72c12ec4 100644
--- a/build/toolchain/get_concurrent_links.py
+++ b/build/toolchain/get_concurrent_links.py
@@ -49,12 +49,14 @@
           match = memtotal_re.match(line)
           if not match:
             continue
+          mem_total_gb = float(match.group(1)) / (2 ** 20)
           # Allow 8Gb per link on Linux because Gold is quite memory hungry
-          # 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)))
+          mem_per_link_gb = 8
+          if is_lto:
+            mem_total_gb -= 20 # Reserve
+            # For LTO builds the RAM requirements are even higher
+            mem_per_link_gb = 20
+          return int(max(1, mem_total_gb / mem_per_link_gb))
     return 1
   elif sys.platform == 'darwin':
     try:
diff --git a/build/toolchain/win/setup_toolchain.py b/build/toolchain/win/setup_toolchain.py
index f395044a..4e79cd90 100644
--- a/build/toolchain/win/setup_toolchain.py
+++ b/build/toolchain/win/setup_toolchain.py
@@ -32,6 +32,10 @@
       'tmp',
       )
   env = {}
+  # This occasionally happens and leads to misleading SYSTEMROOT error messages
+  # if not caught here.
+  if output_of_set.count('=') == 0:
+    raise Exception('Invalid output_of_set. Value is:\n%s' % output_of_set)
   for line in output_of_set.splitlines():
     for envvar in envvars_to_save:
       if re.match(envvar + '=', line.lower()):
@@ -123,6 +127,8 @@
     popen = subprocess.Popen(
         args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
     variables, _ = popen.communicate()
+    if popen.returncode != 0:
+      raise Exception('"%s" failed with error %d' % (args, popen.returncode))
     env = _ExtractImportantEnvironment(variables)
     env['PATH'] = runtime_dirs + ';' + env['PATH']
 
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
index d6473d7f..e53eab5f 100755
--- a/build/vs_toolchain.py
+++ b/build/vs_toolchain.py
@@ -195,7 +195,7 @@
   """Load a list of SHA1s corresponding to the toolchains that we want installed
   to build with."""
   if os.environ.get('GYP_MSVS_VERSION') == '2015':
-    return ['581a25d2e438bb208c1e28f0e901c2318d3ebdd7'] # Update 1
+    return ['8c3265958030a53f93f9cf027cfa5d5d9717fbf6'] # Update 1
   else:
     # Default to VS2013.
     return ['9ff97c632ae1fee0c98bcd53e71770eb3a0d8deb']
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index df0083a..3be4ebb9 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -502,7 +502,9 @@
     "trees/proxy.h",
     "trees/proxy_common.cc",
     "trees/proxy_common.h",
+    "trees/proxy_impl.cc",
     "trees/proxy_impl.h",
+    "trees/proxy_main.cc",
     "trees/proxy_main.h",
     "trees/remote_proto_channel.h",
     "trees/scoped_abort_remaining_swap_promises.h",
@@ -512,8 +514,6 @@
     "trees/swap_promise_monitor.h",
     "trees/task_runner_provider.cc",
     "trees/task_runner_provider.h",
-    "trees/thread_proxy.cc",
-    "trees/thread_proxy.h",
     "trees/threaded_channel.cc",
     "trees/threaded_channel.h",
     "trees/tree_synchronizer.cc",
@@ -655,6 +655,10 @@
     "test/pixel_test_software_output_device.h",
     "test/pixel_test_utils.cc",
     "test/pixel_test_utils.h",
+    "test/proxy_impl_for_test.cc",
+    "test/proxy_impl_for_test.h",
+    "test/proxy_main_for_test.cc",
+    "test/proxy_main_for_test.h",
     "test/render_pass_test_utils.cc",
     "test/render_pass_test_utils.h",
     "test/scheduler_test_common.cc",
@@ -677,6 +681,8 @@
     "test/test_gles2_interface.h",
     "test/test_gpu_memory_buffer_manager.cc",
     "test/test_gpu_memory_buffer_manager.h",
+    "test/test_hooks.cc",
+    "test/test_hooks.h",
     "test/test_image_factory.cc",
     "test/test_image_factory.h",
     "test/test_in_process_context_provider.cc",
@@ -692,6 +698,8 @@
     "test/test_tile_priorities.h",
     "test/test_web_graphics_context_3d.cc",
     "test/test_web_graphics_context_3d.h",
+    "test/threaded_channel_for_test.cc",
+    "test/threaded_channel_for_test.h",
   ]
 
   configs += [ "//build/config:precompiled_headers" ]
diff --git a/cc/base/invalidation_region.h b/cc/base/invalidation_region.h
index 7aa4a8b2..3cf69f2 100644
--- a/cc/base/invalidation_region.h
+++ b/cc/base/invalidation_region.h
@@ -23,6 +23,7 @@
   void Clear();
   void Union(const gfx::Rect& rect);
   bool IsEmpty() const { return region_.IsEmpty(); }
+  Region* region() { return &region_; }
 
  private:
   void SimplifyIfNeeded();
diff --git a/cc/base/rtree.cc b/cc/base/rtree.cc
index 79a4bcd..9efc746 100644
--- a/cc/base/rtree.cc
+++ b/cc/base/rtree.cc
@@ -107,4 +107,8 @@
   }
 }
 
+gfx::Rect RTree::GetBounds() const {
+  return root_.bounds;
+}
+
 }  // namespace cc
diff --git a/cc/base/rtree.h b/cc/base/rtree.h
index 63f7d14..8445c93 100644
--- a/cc/base/rtree.h
+++ b/cc/base/rtree.h
@@ -75,6 +75,8 @@
 
   void Search(const gfx::Rect& query, std::vector<size_t>* results) const;
 
+  gfx::Rect GetBounds() const;
+
  private:
   // These values were empirically determined to produce reasonable performance
   // in most cases.
diff --git a/cc/base/rtree_unittest.cc b/cc/base/rtree_unittest.cc
index e58c9f6..9f6a46b 100644
--- a/cc/base/rtree_unittest.cc
+++ b/cc/base/rtree_unittest.cc
@@ -65,4 +65,31 @@
   }
 }
 
+TEST(RTreeTest, GetBoundsEmpty) {
+  RTree rtree;
+  ASSERT_EQ(gfx::Rect(), rtree.GetBounds());
+}
+
+TEST(RTreeTest, GetBoundsNonOverlapping) {
+  std::vector<gfx::Rect> rects;
+  rects.push_back(gfx::Rect(5, 6, 7, 8));
+  rects.push_back(gfx::Rect(11, 12, 13, 14));
+
+  RTree rtree;
+  rtree.Build(rects);
+
+  ASSERT_EQ(gfx::Rect(5, 6, 19, 20), rtree.GetBounds());
+}
+
+TEST(RTreeTest, GetBoundsOverlapping) {
+  std::vector<gfx::Rect> rects;
+  rects.push_back(gfx::Rect(0, 0, 10, 10));
+  rects.push_back(gfx::Rect(5, 5, 5, 5));
+
+  RTree rtree;
+  rtree.Build(rects);
+
+  ASSERT_EQ(gfx::Rect(0, 0, 10, 10), rtree.GetBounds());
+}
+
 }  // namespace cc
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 508ff1c..7bce8be 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -564,7 +564,9 @@
         'trees/proxy.h',
         'trees/proxy_common.cc',
         'trees/proxy_common.h',
+        'trees/proxy_impl.cc',
         'trees/proxy_impl.h',
+        'trees/proxy_main.cc',
         'trees/proxy_main.h',
         'trees/remote_proto_channel.h',
         'trees/scoped_abort_remaining_swap_promises.h',
@@ -572,8 +574,6 @@
         'trees/single_thread_proxy.h',
         'trees/swap_promise_monitor.cc',
         'trees/swap_promise_monitor.h',
-        'trees/thread_proxy.cc',
-        'trees/thread_proxy.h',
         'trees/task_runner_provider.cc',
         'trees/task_runner_provider.h',
         'trees/threaded_channel.cc',
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index 5332133..8ce17e2 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -258,6 +258,10 @@
       'test/pixel_test_software_output_device.h',
       'test/pixel_test_utils.cc',
       'test/pixel_test_utils.h',
+      'test/proxy_impl_for_test.cc',
+      'test/proxy_impl_for_test.h',
+      'test/proxy_main_for_test.cc',
+      'test/proxy_main_for_test.h',
       'test/render_pass_test_utils.cc',
       'test/render_pass_test_utils.h',
       'test/scheduler_test_common.cc',
@@ -280,6 +284,8 @@
       'test/test_gles2_interface.h',
       'test/test_gpu_memory_buffer_manager.cc',
       'test/test_gpu_memory_buffer_manager.h',
+      'test/test_hooks.cc',
+      'test/test_hooks.h',
       'test/test_image_factory.cc',
       'test/test_image_factory.h',
       'test/test_in_process_context_provider.cc',
@@ -295,6 +301,8 @@
       'test/test_tile_priorities.h',
       'test/test_web_graphics_context_3d.cc',
       'test/test_web_graphics_context_3d.h',
+      'test/threaded_channel_for_test.cc',
+      'test/threaded_channel_for_test.h',
     ],
   },
   'targets': [
diff --git a/cc/debug/OWNERS b/cc/debug/OWNERS
index 2de2d9b..0206f94 100644
--- a/cc/debug/OWNERS
+++ b/cc/debug/OWNERS
@@ -1,7 +1,7 @@
 # Changes to this file may break telemetry benchmarks
 per-file benchmark_instrumentation.h=set noparent
-per-file benchmark_instrumentation.h=ernstm@chromium.org
+per-file benchmark_instrumentation.h=vmpstr@chromium.org
 per-file benchmark_instrumentation.h=nduca@chromium.org
 per-file benchmark_instrumentation.cc=set noparent
-per-file benchmark_instrumentation.cc=ernstm@chromium.org
+per-file benchmark_instrumentation.cc=vmpstr@chromium.org
 per-file benchmark_instrumentation.cc=nduca@chromium.org
diff --git a/cc/debug/benchmark_instrumentation.h b/cc/debug/benchmark_instrumentation.h
index 944ac66..99cfa21f 100644
--- a/cc/debug/benchmark_instrumentation.h
+++ b/cc/debug/benchmark_instrumentation.h
@@ -20,6 +20,8 @@
 const char kBeginFrameId[] = "begin_frame_id";
 }  // namespace internal
 
+// TODO(khushalsagar): Fix these names for the telemetry benchmarks.
+// See crbug/567993.
 const char kSendBeginFrame[] = "ThreadProxy::ScheduledActionSendBeginMainFrame";
 const char kDoBeginFrame[] = "ThreadProxy::BeginMainFrame";
 
diff --git a/cc/debug/picture_debug_util.cc b/cc/debug/picture_debug_util.cc
index 2b1f773..5494d99 100644
--- a/cc/debug/picture_debug_util.cc
+++ b/cc/debug/picture_debug_util.cc
@@ -24,9 +24,10 @@
  protected:
   bool onUseEncodedData(const void* data, size_t len) override { return true; }
 
-  SkData* onEncodePixels(const SkImageInfo& info,
-                         const void* pixels,
-                         size_t row_bytes) override {
+  SkData* onEncode(const SkPixmap& pixmap) override {
+    const SkImageInfo& info = pixmap.info();
+    const void* pixels = pixmap.addr();
+    size_t row_bytes = pixmap.rowBytes();
     const int kJpegQuality = 80;
     std::vector<unsigned char> data;
 
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index a64e04e..f87d18d 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -351,6 +351,8 @@
   virtual bool DrawsContent() const;
 
   // This methods typically need to be overwritten by derived classes.
+  // TODO(chrishtr): Blink no longer resizes anything during paint. We can
+  // remove this.
   virtual void SavePaintProperties();
   // Returns true iff anything was updated that needs to be committed.
   virtual bool Update();
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 983e741..6892f39 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -573,6 +573,12 @@
   layer->SetDoubleSided(double_sided_);
   layer->SetDrawsContent(DrawsContent());
   layer->SetHideLayerAndSubtree(hide_layer_and_subtree_);
+  // If whether layer has render surface changes, we need to update draw
+  // properties.
+  // TODO(weiliangc): Should be safely removed after impl side is able to
+  // update render surfaces without rebuilding property trees.
+  if (layer->has_render_surface() != has_render_surface())
+    layer->layer_tree_impl()->set_needs_update_draw_properties();
   layer->SetHasRenderSurface(!!render_surface());
   layer->SetForceRenderSurface(force_render_surface_);
   layer->SetFilters(filters());
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 3939b99..0a88918 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -25,6 +25,7 @@
 #include "cc/layers/draw_properties.h"
 #include "cc/layers/layer_lists.h"
 #include "cc/layers/layer_position_constraint.h"
+#include "cc/layers/performance_properties.h"
 #include "cc/layers/render_surface_impl.h"
 #include "cc/layers/scroll_blocks_on.h"
 #include "cc/output/filter_operations.h"
@@ -395,6 +396,9 @@
 
   gfx::Transform DrawTransform() const;
   gfx::Transform ScreenSpaceTransform() const;
+  PerformanceProperties<LayerImpl>& performance_properties() {
+    return performance_properties_;
+  }
 
   // The following are shortcut accessors to get various information from
   // draw_properties_
@@ -872,6 +876,7 @@
   // Group of properties that need to be computed based on the layer tree
   // hierarchy before layers can be drawn.
   DrawProperties draw_properties_;
+  PerformanceProperties<LayerImpl> performance_properties_;
 
   scoped_refptr<base::trace_event::ConvertableToTraceFormat> debug_info_;
   scoped_ptr<RenderSurfaceImpl> render_surface_;
diff --git a/cc/layers/performance_properties.h b/cc/layers/performance_properties.h
new file mode 100644
index 0000000..5d1f446
--- /dev/null
+++ b/cc/layers/performance_properties.h
@@ -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.
+
+#ifndef CC_LAYERS_PERFORMANCE_PROPERTIES_H_
+#define CC_LAYERS_PERFORMANCE_PROPERTIES_H_
+
+#include "ui/gfx/transform.h"
+
+namespace cc {
+
+// Container for properties used to measure performance
+template <typename LayerType>
+struct CC_EXPORT PerformanceProperties {
+  PerformanceProperties()
+      : num_fixed_point_hits(0), translation_from_last_frame(0.f) {}
+
+  // This value stores the numer of times a layer has hit a fixed point
+  // during commit. It is used to detect jitter in layers.
+  int num_fixed_point_hits;
+  float translation_from_last_frame;
+  gfx::Transform last_commit_screen_space_transform;
+};
+
+}  // namespace cc
+
+#endif  // CC_LAYERS_PERFORMANCE_PROPERTIES_H_
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index 02b20bee..811e8068 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -78,9 +78,9 @@
       recording_source_->CreateRasterSource(can_use_lcd_text);
   layer_impl->set_gpu_raster_max_texture_size(
       layer_tree_host()->device_viewport_size());
-  layer_impl->UpdateRasterSource(raster_source, &recording_invalidation_,
+  layer_impl->UpdateRasterSource(raster_source, invalidation_.region(),
                                  nullptr);
-  DCHECK(recording_invalidation_.IsEmpty());
+  DCHECK(invalidation_.IsEmpty());
 }
 
 void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
@@ -100,10 +100,10 @@
 }
 
 void PictureLayer::SetNeedsDisplayRect(const gfx::Rect& layer_rect) {
+  DCHECK(!layer_tree_host() || !layer_tree_host()->in_paint_layer_contents());
   if (!layer_rect.IsEmpty()) {
     // Clamp invalidation to the layer bounds.
-    pending_invalidation_.Union(
-        gfx::IntersectRects(layer_rect, gfx::Rect(bounds())));
+    invalidation_.Union(gfx::IntersectRects(layer_rect, gfx::Rect(bounds())));
   }
   Layer::SetNeedsDisplayRect(layer_rect);
 }
@@ -116,8 +116,7 @@
   gfx::Size layer_size = paint_properties().bounds;
 
   if (last_updated_visible_layer_rect_ == update_rect &&
-      recording_source_->GetSize() == layer_size &&
-      pending_invalidation_.IsEmpty()) {
+      recording_source_->GetSize() == layer_size && invalidation_.IsEmpty()) {
     // Only early out if the visible content rect of this layer hasn't changed.
     return updated;
   }
@@ -132,20 +131,13 @@
   devtools_instrumentation::ScopedLayerTreeTask update_layer(
       devtools_instrumentation::kUpdateLayer, id(), layer_tree_host()->id());
 
-  // Calling paint in Blink can sometimes cause invalidations, so save
-  // off the invalidation prior to calling update.
-  // TODO(chrishtr): Blink should no longer be invalidating during paint.
-  // Try to remove this code.
-  pending_invalidation_.Swap(&recording_invalidation_);
-  pending_invalidation_.Clear();
-
   // UpdateAndExpandInvalidation will give us an invalidation that covers
   // anything not explicitly recorded in this frame. We give this region
   // to the impl side so that it drops tiles that may not have a recording
   // for them.
   DCHECK(client_);
   updated |= recording_source_->UpdateAndExpandInvalidation(
-      client_, &recording_invalidation_, layer_size, update_rect,
+      client_, invalidation_.region(), layer_size, update_rect,
       update_source_frame_number_, DisplayListRecordingSource::RECORD_NORMALLY);
   last_updated_visible_layer_rect_ = visible_layer_rect();
 
@@ -154,7 +146,7 @@
   } else {
     // If this invalidation did not affect the recording source, then it can be
     // cleared as an optimization.
-    recording_invalidation_.Clear();
+    invalidation_.Clear();
   }
 
   return updated;
diff --git a/cc/layers/picture_layer.h b/cc/layers/picture_layer.h
index 6f4f17c..7eb87f0 100644
--- a/cc/layers/picture_layer.h
+++ b/cc/layers/picture_layer.h
@@ -60,10 +60,10 @@
   scoped_ptr<DisplayListRecordingSource> recording_source_;
   devtools_instrumentation::
       ScopedLayerObjectTracker instrumentation_object_tracker_;
+
   // Invalidation to use the next time update is called.
-  InvalidationRegion pending_invalidation_;
-  // Invalidation from the last time update was called.
-  Region recording_invalidation_;
+  InvalidationRegion invalidation_;
+
   gfx::Rect last_updated_visible_layer_rect_;
 
   int update_source_frame_number_;
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc
index ce30ba0..c9756da 100644
--- a/cc/layers/scrollbar_layer_unittest.cc
+++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -632,7 +632,7 @@
   int max_size = 0;
   context->getIntegerv(GL_MAX_TEXTURE_SIZE, &max_size);
   SetScrollbarBounds(gfx::Size(max_size + 100, max_size + 100));
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 TEST_F(ScrollbarLayerTestMaxTextureSize, DelegatingRenderer) {
@@ -641,7 +641,7 @@
   int max_size = 0;
   context->getIntegerv(GL_MAX_TEXTURE_SIZE, &max_size);
   SetScrollbarBounds(gfx::Size(max_size + 100, max_size + 100));
-  RunTest(true, true);
+  RunTest(CompositorMode::Threaded, true);
 }
 
 class ScrollbarLayerTestResourceCreationAndRelease : public ScrollbarLayerTest {
diff --git a/cc/layers/surface_layer_impl.cc b/cc/layers/surface_layer_impl.cc
index 546af40..e0dcadf0 100644
--- a/cc/layers/surface_layer_impl.cc
+++ b/cc/layers/surface_layer_impl.cc
@@ -8,15 +8,19 @@
 #include "cc/debug/debug_colors.h"
 #include "cc/quads/solid_color_draw_quad.h"
 #include "cc/quads/surface_draw_quad.h"
+#include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/occlusion.h"
 
 namespace cc {
 
 SurfaceLayerImpl::SurfaceLayerImpl(LayerTreeImpl* tree_impl, int id)
     : LayerImpl(tree_impl, id), surface_scale_(0.f) {
+  layer_tree_impl()->AddSurfaceLayer(this);
 }
 
-SurfaceLayerImpl::~SurfaceLayerImpl() {}
+SurfaceLayerImpl::~SurfaceLayerImpl() {
+  layer_tree_impl()->RemoveSurfaceLayer(this);
+}
 
 scoped_ptr<LayerImpl> SurfaceLayerImpl::CreateLayerImpl(
     LayerTreeImpl* tree_impl) {
@@ -76,7 +80,6 @@
   SurfaceDrawQuad* quad =
       render_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
   quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect, surface_id_);
-  render_pass->referenced_surfaces.push_back(surface_id_);
 }
 
 void SurfaceLayerImpl::GetDebugBorderProperties(SkColor* color,
diff --git a/cc/layers/surface_layer_impl.h b/cc/layers/surface_layer_impl.h
index 2bf6a9a0..4d2c48b4 100644
--- a/cc/layers/surface_layer_impl.h
+++ b/cc/layers/surface_layer_impl.h
@@ -22,6 +22,7 @@
   void SetSurfaceId(SurfaceId surface_id);
   void SetSurfaceScale(float scale);
   void SetSurfaceSize(const gfx::Size& size);
+  SurfaceId surface_id() const { return surface_id_; }
 
   // LayerImpl overrides.
   scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
diff --git a/cc/memory.md b/cc/memory.md
new file mode 100644
index 0000000..1bac0f5
--- /dev/null
+++ b/cc/memory.md
@@ -0,0 +1,125 @@
+# Memory Usage in CC
+
+This document gives an overview of memory usage in the CC component, as well as
+information on how to analyze that memory.
+
+[TOC]
+
+## Types of Memory in Use
+
+CC uses a number of types of memory:
+
+1.  Malloc Memory - Standard system memory used for all manner of objects in CC.
+2.  Discardable Memory - Memory allocated by the discardable memory system.
+    Designed to be freeable by the system at any time (under memory pressure).
+    In most cases, only pinned discardable memory should be considered to
+    have a cost; however, the implementation of discardable memory is platform
+    dependent, and on certain platforms unpinned memory can contribute to
+    memory pressure to some degree.
+3.  Shared Memory - Memory which is allocated by the Browser and can safely
+    be transferred between processes. This memory is allocated by the browser
+    but may count against a renderer process depending on who logically "owns"
+    the memory.
+4.  GPU Memory - Memory which is allocated on the GPU and typically does not
+    count against system memory. This mainly includes OpenGL objects.
+
+## Categories Of Memory
+
+Memory-infra tracing will grab dumps of CC memory in several categories.
+
+### CC Category
+
+The CC category contains resource allocations made by ResourceProvider. All
+resource allocations are enumerated under cc/resource_memory. A subset of
+resources are used as tile memory, and are also enumerated under cc/tile_memory.
+For resources that appear in both cc/tile_memory and cc/resource_memory, the
+size will be attributed to cc/tile_memory (effective_size of cc/resource_memory
+will not include these resources).
+
+If the one-copy tile update path is in use, the cc category will also enumerate
+staging resources used as intermediates when drawing tiles. These resources are
+like tile_memory, in that they are shared with cc/resource_memory.
+
+Note that depending on the path being used, CC memory may be either shared
+memory or GPU memory:
+
+Path         | Tile Memory Type     | Staging Memory Type
+-------------|-------------------------------------------
+Bitmap       | Shared Memory        | N/A
+One Copy     | GPU Memory           | Shared Memory
+Zero Copy    | GPU or Shared Memory | N/A
+GPU          | GPU Memory           | N/A
+
+Note that these values can be determined from a memory-infra dump. For a given
+resource, hover over the small green arrow next to it's "size". This will show
+the other allocations that this resource is aliased with. If you see an
+allocation in the GPU process, the memory is generally GPU memory. Otherwise,
+the resource is typically Shared Memory.
+
+Tile and Staging memory managers are set up to evict any resource not used
+within 1s.
+
+### GPU Category
+
+This category lists the memory allocations needed to support CC's GPU path.
+Despite the name, the data in this category (within a Renderer process) is not
+GPU memory but Shared Memory.
+
+Allocations tracked here include GL command buffer support allocations such as:
+
+1.  Command Buffer Memory - memory used to send commands across the GL command
+    buffer. This is backed by Shared Memory.
+2.  Mapped Memory - memory used in certain image upload paths to share data
+    with the GPU process. This is backed by Shared Memory.
+3.  Transfer Buffer Memory - memory used to transfer data to the GPU - used in
+    different paths than mapped memory. Also backed by Shared Memory.
+
+### Discardable Category
+
+Cached images make use of Discardable memory. These allocations are managed by
+Skia and a better summary of these allocations can likely be found in the Skia
+category.
+
+### Malloc Category
+
+The malloc category shows a summary of all memory allocated through malloc.
+
+Currently the information here is not granular enough to be useful, and a
+good project would be to track down and instrument any large pools of memory
+using malloc.
+
+Some Skia caches also make use of malloc memory. For these allocations, a better
+summary can be seen in the Skia category.
+
+### Skia Category
+
+The Skia category shows all resources used by the Skia rendering system. These
+can be divided into a few subcategories. skia/gpu_resources/* includes all
+resources using GPU memory. All other categories draw from either Shared or
+malloc memory. To determine which type of memory a resource is using, hover
+over the green arrow next to its size. This will show the other allocations
+which the resource is aliased with.
+
+## Other Areas of Interest
+
+Many of the allocations under CC are aliased with memory in the Browser or GPU
+process. When investigating CC memory it may be worth looking at the following
+external categories:
+
+1.  GPU Process / GPU Category - All GPU resources allocated by CC have a
+    counterpart in the GPU/GPU category. This includes GL Textures, buffers, and
+    other GPU backed objects such as Native GPU Memory Buffers.
+2.  Browser Process / GpuMemoryBuffer Category - Resources backed by Shared
+    Memory GpuMemoryBuffers are allocated by the browser and will be tracked
+    in this category.
+3.  Browser Process / SharedMemory Category - Resources backed by Bitmap and
+    Shared Memory GpuMemoryBuffer objects are allocated by the browser and will
+    also tracked in this category.
+
+## Memory TODOs
+
+The following areas have insufficient memory instrumentation.
+
+1.  DisplayLists - DisplayLists can be quite large and are currently
+    un-instrumented. These use malloc memory and currently contribute to
+    malloc/allocated_objects/<unspecified>. [BUG](crbug.com/567465)
diff --git a/cc/output/compositor_frame_metadata.h b/cc/output/compositor_frame_metadata.h
index 72035e3..392c6b0d 100644
--- a/cc/output/compositor_frame_metadata.h
+++ b/cc/output/compositor_frame_metadata.h
@@ -9,6 +9,7 @@
 
 #include "cc/base/cc_export.h"
 #include "cc/output/viewport_selection_bound.h"
+#include "cc/surfaces/surface_id.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/events/latency_info.h"
 #include "ui/gfx/geometry/size_f.h"
@@ -57,6 +58,9 @@
   // A set of SurfaceSequences that this frame satisfies (always in the same
   // namespace as the current Surface).
   std::vector<uint32_t> satisfies_sequences;
+
+  // This is the set of Surfaces that are referenced by this frame.
+  std::vector<SurfaceId> referenced_surfaces;
 };
 
 }  // namespace cc
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 5c30003e..d052233 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -3414,8 +3414,6 @@
 
 const GLRenderer::VideoStreamTextureProgram*
 GLRenderer::GetVideoStreamTextureProgram(TexCoordPrecision precision) {
-  if (!Capabilities().using_egl_image)
-    return NULL;
   DCHECK_GE(precision, 0);
   DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
   VideoStreamTextureProgram* program =
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc
index 6c66ae7..97bd2d99 100644
--- a/cc/output/gl_renderer_unittest.cc
+++ b/cc/output/gl_renderer_unittest.cc
@@ -132,10 +132,10 @@
 
   void TestShadersWithPrecision(TexCoordPrecision precision) {
     EXPECT_PROGRAM_VALID(renderer()->GetTextureIOSurfaceProgram(precision));
+    // This program uses external textures and sampler, so it won't compile
+    // everywhere.
     if (renderer()->Capabilities().using_egl_image)
       EXPECT_PROGRAM_VALID(renderer()->GetVideoStreamTextureProgram(precision));
-    else
-      EXPECT_FALSE(renderer()->GetVideoStreamTextureProgram(precision));
   }
 
   void TestShadersWithPrecisionAndBlend(TexCoordPrecision precision,
diff --git a/cc/quads/render_pass.h b/cc/quads/render_pass.h
index bc64d74..e6cc67a6 100644
--- a/cc/quads/render_pass.h
+++ b/cc/quads/render_pass.h
@@ -117,10 +117,6 @@
   QuadList quad_list;
   SharedQuadStateList shared_quad_state_list;
 
-  // This vector contains the complete set of SurfaceIds referenced by
-  // DrawQuads in quad_list.
-  std::vector<SurfaceId> referenced_surfaces;
-
  protected:
   explicit RenderPass(size_t num_layers);
   RenderPass();
diff --git a/cc/quads/render_pass_unittest.cc b/cc/quads/render_pass_unittest.cc
index f00c006..140b7e1 100644
--- a/cc/quads/render_pass_unittest.cc
+++ b/cc/quads/render_pass_unittest.cc
@@ -26,7 +26,6 @@
   gfx::Rect output_rect;
   gfx::Rect damage_rect;
   bool has_transparent_background;
-  std::vector<SurfaceId> referenced_surfaces;
   std::vector<scoped_ptr<CopyOutputRequest>> copy_callbacks;
 };
 
@@ -48,7 +47,6 @@
     EXPECT_EQ(expected->shared_quad_state_list.size(),
               actual->shared_quad_state_list.size());
     EXPECT_EQ(expected->quad_list.size(), actual->quad_list.size());
-    EXPECT_EQ(expected->referenced_surfaces, actual->referenced_surfaces);
 
     for (auto exp_iter = expected->quad_list.cbegin(),
               act_iter = actual->quad_list.cbegin();
@@ -102,7 +100,6 @@
   EXPECT_EQ(pass->damage_rect, copy->damage_rect);
   EXPECT_EQ(pass->has_transparent_background, copy->has_transparent_background);
   EXPECT_EQ(0u, copy->quad_list.size());
-  EXPECT_EQ(0u, copy->referenced_surfaces.size());
 
   // The copy request should not be copied/duplicated.
   EXPECT_EQ(1u, pass->copy_requests.size());
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 506d1d9..4e490750 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -1537,6 +1537,10 @@
   DCHECK(resource->gpu_memory_buffer);
   DCHECK(resource->gl_id);
   DCHECK(resource->allocated);
+  // Avoid crashing in release builds if GpuMemoryBuffer allocation fails.
+  // http://crbug.com/554541
+  if (!resource->gpu_memory_buffer)
+    return;
   if (!resource->image_id) {
     GLES2Interface* gl = ContextGL();
     DCHECK(gl);
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc
index 8999b2f..44d16c1 100644
--- a/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -1228,7 +1228,7 @@
       SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
 }
 
-// See ThreadProxy::BeginMainFrame "EarlyOut_NotVisible" /
+// See ProxyMain::BeginMainFrame "EarlyOut_NotVisible" /
 // "EarlyOut_OutputSurfaceLost" cases.
 TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseInvisible) {
   SchedulerSettings default_scheduler_settings;
@@ -1282,7 +1282,7 @@
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 }
 
-// See ThreadProxy::BeginMainFrame "EarlyOut_NoUpdates" case.
+// See ProxyMain::BeginMainFrame "EarlyOut_NoUpdates" case.
 TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseCommitNotNeeded) {
   SchedulerSettings default_scheduler_settings;
   StateMachine state(default_scheduler_settings);
diff --git a/cc/surfaces/surface.cc b/cc/surfaces/surface.cc
index 8faff98..563415c2 100644
--- a/cc/surfaces/surface.cc
+++ b/cc/surfaces/surface.cc
@@ -66,12 +66,7 @@
 
   std::vector<SurfaceId> new_referenced_surfaces;
   if (current_frame_) {
-    for (auto& render_pass :
-         current_frame_->delegated_frame_data->render_pass_list) {
-      new_referenced_surfaces.insert(new_referenced_surfaces.end(),
-                                     render_pass->referenced_surfaces.begin(),
-                                     render_pass->referenced_surfaces.end());
-    }
+    new_referenced_surfaces = current_frame_->metadata.referenced_surfaces;
   }
 
   if (previous_frame) {
diff --git a/cc/surfaces/surface_aggregator.cc b/cc/surfaces/surface_aggregator.cc
index 4c1441a..ae291cb 100644
--- a/cc/surfaces/surface_aggregator.cc
+++ b/cc/surfaces/surface_aggregator.cc
@@ -58,6 +58,10 @@
   ProcessAddedAndRemovedSurfaces();
 }
 
+SurfaceAggregator::PrewalkResult::PrewalkResult() {}
+
+SurfaceAggregator::PrewalkResult::~PrewalkResult() {}
+
 // Create a clip rect for an aggregated quad from the original clip rect and
 // the clip rect from the surface it's on.
 SurfaceAggregator::ClipData SurfaceAggregator::CalculateClipRect(
@@ -491,7 +495,8 @@
 // Walk the Surface tree from surface_id. Validate the resources of the current
 // surface and its descendants, check if there are any copy requests, and
 // return the combined damage rect.
-gfx::Rect SurfaceAggregator::PrewalkTree(SurfaceId surface_id) {
+gfx::Rect SurfaceAggregator::PrewalkTree(SurfaceId surface_id,
+                                         PrewalkResult* result) {
   if (referenced_surfaces_.count(surface_id))
     return gfx::Rect();
   Surface* surface = manager_->GetSurfaceForId(surface_id);
@@ -569,7 +574,7 @@
     provider_->DeclareUsedResourcesFromChild(child_id, referenced_resources);
 
   for (const auto& render_pass : frame_data->render_pass_list)
-    has_copy_requests_ |= !render_pass->copy_requests.empty();
+    result->has_copy_requests |= !render_pass->copy_requests.empty();
 
   gfx::Rect damage_rect;
   if (!frame_data->render_pass_list.empty()) {
@@ -583,14 +588,65 @@
   SurfaceSet::iterator it =
       referenced_surfaces_.insert(surface->surface_id()).first;
   for (const auto& surface_info : child_surfaces) {
-    gfx::Rect surface_damage = PrewalkTree(surface_info.first);
+    gfx::Rect surface_damage = PrewalkTree(surface_info.first, result);
     damage_rect.Union(
         MathUtil::MapEnclosingClippedRect(surface_info.second, surface_damage));
   }
+
+  for (const auto& surface_id : surface_frame->metadata.referenced_surfaces) {
+    if (!contained_surfaces_.count(surface_id)) {
+      result->undrawn_surfaces.insert(surface_id);
+      PrewalkTree(surface_id, result);
+    }
+  }
+
   referenced_surfaces_.erase(it);
   return damage_rect;
 }
 
+void SurfaceAggregator::CopyUndrawnSurfaces(PrewalkResult* prewalk_result) {
+  // undrawn_surfaces are Surfaces that were identified by prewalk as being
+  // referenced by a drawn Surface, but aren't contained in a SurfaceDrawQuad.
+  // They need to be iterated over to ensure that any copy requests on them
+  // (or on Surfaces they reference) are executed.
+  std::vector<SurfaceId> surfaces_to_copy(
+      prewalk_result->undrawn_surfaces.begin(),
+      prewalk_result->undrawn_surfaces.end());
+
+  for (size_t i = 0; i < surfaces_to_copy.size(); i++) {
+    SurfaceId surface_id = surfaces_to_copy[i];
+    Surface* surface = manager_->GetSurfaceForId(surface_id);
+    if (!surface)
+      continue;
+    const CompositorFrame* surface_frame = surface->GetEligibleFrame();
+    if (!surface_frame)
+      continue;
+    bool surface_has_copy_requests = false;
+    for (const auto& render_pass :
+         surface_frame->delegated_frame_data->render_pass_list) {
+      surface_has_copy_requests |= !render_pass->copy_requests.empty();
+    }
+    if (!surface_has_copy_requests) {
+      // Children are not necessarily included in undrawn_surfaces (because
+      // they weren't referenced directly from a drawn surface), but may have
+      // copy requests, so make sure to check them as well.
+      for (const auto& child_id : surface_frame->metadata.referenced_surfaces) {
+        // Don't iterate over the child Surface if it was already listed as a
+        // child of a different Surface, or in the case where there's infinite
+        // recursion.
+        if (!prewalk_result->undrawn_surfaces.count(child_id)) {
+          surfaces_to_copy.push_back(child_id);
+          prewalk_result->undrawn_surfaces.insert(child_id);
+        }
+      }
+    } else {
+      SurfaceSet::iterator it = referenced_surfaces_.insert(surface_id).first;
+      CopyPasses(surface_frame->delegated_frame_data.get(), surface);
+      referenced_surfaces_.erase(it);
+    }
+  }
+}
+
 scoped_ptr<CompositorFrame> SurfaceAggregator::Aggregate(SurfaceId surface_id) {
   Surface* surface = manager_->GetSurfaceForId(surface_id);
   DCHECK(surface);
@@ -609,9 +665,11 @@
   dest_pass_list_ = &frame->delegated_frame_data->render_pass_list;
 
   valid_surfaces_.clear();
-  has_copy_requests_ = false;
-  root_damage_rect_ = PrewalkTree(surface_id);
+  PrewalkResult prewalk_result;
+  root_damage_rect_ = PrewalkTree(surface_id, &prewalk_result);
+  has_copy_requests_ = prewalk_result.has_copy_requests;
 
+  CopyUndrawnSurfaces(&prewalk_result);
   SurfaceSet::iterator it = referenced_surfaces_.insert(surface_id).first;
   CopyPasses(root_surface_frame->delegated_frame_data.get(), surface);
   referenced_surfaces_.erase(it);
diff --git a/cc/surfaces/surface_aggregator.h b/cc/surfaces/surface_aggregator.h
index 738aeec..6df7e6ba 100644
--- a/cc/surfaces/surface_aggregator.h
+++ b/cc/surfaces/surface_aggregator.h
@@ -60,6 +60,15 @@
     gfx::Rect rect;
   };
 
+  struct PrewalkResult {
+    PrewalkResult();
+    ~PrewalkResult();
+    bool has_copy_requests = false;
+    // This is the set of Surfaces that were referenced by another Surface, but
+    // not included in a SurfaceDrawQuad.
+    std::set<SurfaceId> undrawn_surfaces;
+  };
+
   ClipData CalculateClipRect(const ClipData& surface_clip,
                              const ClipData& quad_clip,
                              const gfx::Transform& target_transform);
@@ -83,7 +92,8 @@
       const ClipData& clip_rect,
       RenderPass* dest_pass,
       SurfaceId surface_id);
-  gfx::Rect PrewalkTree(SurfaceId surface_id);
+  gfx::Rect PrewalkTree(SurfaceId surface_id, PrewalkResult* result);
+  void CopyUndrawnSurfaces(PrewalkResult* prewalk);
   void CopyPasses(const DelegatedFrameData* frame_data, Surface* surface);
 
   // Remove Surfaces that were referenced before but aren't currently
diff --git a/cc/surfaces/surface_aggregator_unittest.cc b/cc/surfaces/surface_aggregator_unittest.cc
index 53b01e04..d4fb124 100644
--- a/cc/surfaces/surface_aggregator_unittest.cc
+++ b/cc/surfaces/surface_aggregator_unittest.cc
@@ -477,6 +477,112 @@
   factory_.Destroy(embedded_surface_id);
 }
 
+TEST_F(SurfaceAggregatorValidSurfaceTest, UnreferencedSurface) {
+  SurfaceId embedded_surface_id = allocator_.GenerateId();
+  SurfaceId nonexistent_surface_id = allocator_.GenerateId();
+  factory_.Create(embedded_surface_id);
+  Surface* embedded_surface = manager_.GetSurfaceForId(embedded_surface_id);
+  EXPECT_FALSE(surface_aggregator_client_.HasSurface(embedded_surface));
+
+  test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
+  test::Pass embedded_passes[] = {
+      test::Pass(embedded_quads, arraysize(embedded_quads))};
+
+  SubmitCompositorFrame(embedded_passes, arraysize(embedded_passes),
+                        embedded_surface_id);
+  scoped_ptr<CopyOutputRequest> copy_request(
+      CopyOutputRequest::CreateEmptyRequest());
+  CopyOutputRequest* copy_request_ptr = copy_request.get();
+  factory_.RequestCopyOfSurface(embedded_surface_id, copy_request.Pass());
+
+  SurfaceId parent_surface_id = allocator_.GenerateId();
+  factory_.Create(parent_surface_id);
+  Surface* parent_surface = manager_.GetSurfaceForId(parent_surface_id);
+
+  test::Quad parent_quads[] = {
+      test::Quad::SolidColorQuad(SK_ColorWHITE),
+      test::Quad::SurfaceQuad(embedded_surface_id, 1.f),
+      test::Quad::SolidColorQuad(SK_ColorBLACK)};
+  test::Pass parent_passes[] = {
+      test::Pass(parent_quads, arraysize(parent_quads))};
+
+  {
+    scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
+    AddPasses(&frame_data->render_pass_list, gfx::Rect(SurfaceSize()),
+              parent_passes, arraysize(parent_passes));
+
+    scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+    frame->delegated_frame_data = frame_data.Pass();
+    frame->metadata.referenced_surfaces.push_back(embedded_surface_id);
+
+    factory_.SubmitCompositorFrame(parent_surface_id, frame.Pass(),
+                                   SurfaceFactory::DrawCallback());
+  }
+
+  test::Quad root_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE),
+                             test::Quad::SolidColorQuad(SK_ColorBLACK)};
+  test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
+
+  {
+    scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
+    AddPasses(&frame_data->render_pass_list, gfx::Rect(SurfaceSize()),
+              root_passes, arraysize(root_passes));
+
+    scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+    frame->delegated_frame_data = frame_data.Pass();
+    frame->metadata.referenced_surfaces.push_back(parent_surface_id);
+    // Reference to Surface ID of a Surface that doesn't exist should be
+    // included in previous_contained_surfaces, but otherwise ignored.
+    frame->metadata.referenced_surfaces.push_back(nonexistent_surface_id);
+
+    factory_.SubmitCompositorFrame(root_surface_id_, frame.Pass(),
+                                   SurfaceFactory::DrawCallback());
+  }
+
+  EXPECT_FALSE(surface_aggregator_client_.HasSurface(root_surface_));
+  EXPECT_FALSE(surface_aggregator_client_.HasSurface(parent_surface));
+  EXPECT_FALSE(surface_aggregator_client_.HasSurface(embedded_surface));
+
+  scoped_ptr<CompositorFrame> aggregated_frame =
+      aggregator_.Aggregate(root_surface_id_);
+
+  EXPECT_TRUE(surface_aggregator_client_.HasSurface(root_surface_));
+  EXPECT_TRUE(surface_aggregator_client_.HasSurface(parent_surface));
+  EXPECT_TRUE(surface_aggregator_client_.HasSurface(embedded_surface));
+
+  ASSERT_TRUE(aggregated_frame);
+  ASSERT_TRUE(aggregated_frame->delegated_frame_data);
+
+  DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get();
+
+  // First pass should come from surface that had a copy request but was not
+  // referenced directly. The second pass comes from the root surface.
+  // parent_quad should be ignored because it is neither referenced through a
+  // SurfaceDrawQuad nor has a copy request on it.
+  test::Pass expected_passes[] = {
+      test::Pass(embedded_quads, arraysize(embedded_quads)),
+      test::Pass(root_quads, arraysize(root_quads))};
+  TestPassesMatchExpectations(expected_passes, arraysize(expected_passes),
+                              &frame_data->render_pass_list);
+  ASSERT_EQ(2u, frame_data->render_pass_list.size());
+  ASSERT_EQ(1u, frame_data->render_pass_list[0]->copy_requests.size());
+  DCHECK_EQ(copy_request_ptr,
+            frame_data->render_pass_list[0]->copy_requests[0].get());
+
+  SurfaceId surface_ids[] = {root_surface_id_, parent_surface_id,
+                             embedded_surface_id, nonexistent_surface_id};
+  EXPECT_EQ(arraysize(surface_ids),
+            aggregator_.previous_contained_surfaces().size());
+  for (size_t i = 0; i < arraysize(surface_ids); i++) {
+    EXPECT_TRUE(
+        aggregator_.previous_contained_surfaces().find(surface_ids[i]) !=
+        aggregator_.previous_contained_surfaces().end());
+  }
+
+  factory_.Destroy(parent_surface_id);
+  factory_.Destroy(embedded_surface_id);
+}
+
 // This tests referencing a surface that has multiple render passes.
 TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSurfaceReference) {
   SurfaceId embedded_surface_id = child_allocator_.GenerateId();
diff --git a/cc/surfaces/surface_factory_unittest.cc b/cc/surfaces/surface_factory_unittest.cc
index fa05c2e..749d7c59 100644
--- a/cc/surfaces/surface_factory_unittest.cc
+++ b/cc/surfaces/surface_factory_unittest.cc
@@ -490,10 +490,10 @@
   // Give id2 a frame that references surface_id_.
   {
     scoped_ptr<RenderPass> render_pass(RenderPass::Create());
-    render_pass->referenced_surfaces.push_back(surface_id_);
     scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
     frame_data->render_pass_list.push_back(std::move(render_pass));
     scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+    frame->metadata.referenced_surfaces.push_back(surface_id_);
     frame->delegated_frame_data = std::move(frame_data);
     factory_->SubmitCompositorFrame(id2, std::move(frame),
                                     SurfaceFactory::DrawCallback());
@@ -503,10 +503,10 @@
   // Give surface_id_ a frame that references id2.
   {
     scoped_ptr<RenderPass> render_pass(RenderPass::Create());
-    render_pass->referenced_surfaces.push_back(id2);
     scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
     frame_data->render_pass_list.push_back(std::move(render_pass));
     scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+    frame->metadata.referenced_surfaces.push_back(id2);
     frame->delegated_frame_data = std::move(frame_data);
     factory_->SubmitCompositorFrame(surface_id_, std::move(frame),
                                     SurfaceFactory::DrawCallback());
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index f5e5460..f29ae86 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -182,8 +182,7 @@
   content_root_ = content_root;
   readback_target_ = NULL;
   ref_file_ = file_name;
-  bool threaded = true;
-  RunTest(threaded, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 void LayerTreePixelTest::RunSingleThreadedPixelTest(
@@ -194,8 +193,7 @@
   content_root_ = content_root;
   readback_target_ = NULL;
   ref_file_ = file_name;
-  bool threaded = false;
-  RunTest(threaded, false);
+  RunTest(CompositorMode::SingleThreaded, false);
 }
 
 void LayerTreePixelTest::RunPixelTestWithReadbackTarget(
@@ -207,7 +205,7 @@
   content_root_ = content_root;
   readback_target_ = target;
   ref_file_ = file_name;
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 void LayerTreePixelTest::SetupTree() {
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index d7f7024..d68ec67 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -30,8 +30,10 @@
 #include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/layer_tree_host_single_thread_client.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/proxy_impl.h"
+#include "cc/trees/proxy_main.h"
 #include "cc/trees/single_thread_proxy.h"
-#include "cc/trees/thread_proxy.h"
+#include "cc/trees/threaded_channel.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "ui/gfx/geometry/size_conversions.h"
 
@@ -93,254 +95,8 @@
                                 layer_settings);
 }
 
-TestHooks::TestHooks() {}
-
-TestHooks::~TestHooks() {}
-
-DrawResult TestHooks::PrepareToDrawOnThread(
-    LayerTreeHostImpl* host_impl,
-    LayerTreeHostImpl::FrameData* frame_data,
-    DrawResult draw_result) {
-  return draw_result;
-}
-
-void TestHooks::CreateResourceAndTileTaskWorkerPool(
-    LayerTreeHostImpl* host_impl,
-    scoped_ptr<TileTaskWorkerPool>* tile_task_worker_pool,
-    scoped_ptr<ResourcePool>* resource_pool) {
-  host_impl->LayerTreeHostImpl::CreateResourceAndTileTaskWorkerPool(
-      tile_task_worker_pool, resource_pool);
-}
-
-// Adapts ThreadProxy for test. Injects test hooks for testing.
-class ThreadProxyForTest : public ThreadProxy {
- public:
-  static scoped_ptr<Proxy> Create(
-      TestHooks* test_hooks,
-      LayerTreeHost* host,
-      TaskRunnerProvider* task_runner_provider,
-      scoped_ptr<BeginFrameSource> external_begin_frame_source) {
-    return make_scoped_ptr(
-        new ThreadProxyForTest(test_hooks, host, task_runner_provider,
-                               std::move(external_begin_frame_source)));
-  }
-
-  ~ThreadProxyForTest() override {}
-
- private:
-  TestHooks* test_hooks_;
-
-  void SetNeedsUpdateLayers() override {
-    ThreadProxy::SetNeedsUpdateLayers();
-    test_hooks_->DidSetNeedsUpdateLayers();
-  }
-
-  void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override {
-    test_hooks_->ScheduledActionWillSendBeginMainFrame();
-    ThreadProxy::ScheduledActionSendBeginMainFrame(args);
-    test_hooks_->ScheduledActionSendBeginMainFrame();
-  }
-
-  DrawResult ScheduledActionDrawAndSwapIfPossible() override {
-    DrawResult result = ThreadProxy::ScheduledActionDrawAndSwapIfPossible();
-    test_hooks_->ScheduledActionDrawAndSwapIfPossible();
-    return result;
-  }
-
-  void ScheduledActionCommit() override {
-    ThreadProxy::ScheduledActionCommit();
-    test_hooks_->ScheduledActionCommit();
-  }
-
-  void ScheduledActionBeginOutputSurfaceCreation() override {
-    ThreadProxy::ScheduledActionBeginOutputSurfaceCreation();
-    test_hooks_->ScheduledActionBeginOutputSurfaceCreation();
-  }
-
-  void ScheduledActionPrepareTiles() override {
-    ThreadProxy::ScheduledActionPrepareTiles();
-    test_hooks_->ScheduledActionPrepareTiles();
-  }
-
-  void ScheduledActionInvalidateOutputSurface() override {
-    ThreadProxy::ScheduledActionInvalidateOutputSurface();
-    test_hooks_->ScheduledActionInvalidateOutputSurface();
-  }
-
-  void SendBeginMainFrameNotExpectedSoon() override {
-    ThreadProxy::SendBeginMainFrameNotExpectedSoon();
-    test_hooks_->SendBeginMainFrameNotExpectedSoon();
-  }
-
-  void DidActivateSyncTree() override {
-    ThreadProxy::DidActivateSyncTree();
-    test_hooks_->DidActivateSyncTree();
-  }
-
-  void SetThrottleFrameProductionOnImpl(bool throttle) override {
-    test_hooks_->SetThrottleFrameProductionOnImpl(throttle);
-    ThreadProxy::SetThrottleFrameProductionOnImpl(throttle);
-  }
-
-  void InitializeOutputSurfaceOnImpl(OutputSurface* output_surface) override {
-    test_hooks_->InitializeOutputSurfaceOnImpl(output_surface);
-    ThreadProxy::InitializeOutputSurfaceOnImpl(output_surface);
-  }
-
-  void MainThreadHasStoppedFlingingOnImpl() override {
-    test_hooks_->MainThreadHasStoppedFlingingOnImpl();
-    ThreadProxy::MainThreadHasStoppedFlingingOnImpl();
-  }
-
-  void SetInputThrottledUntilCommitOnImpl(bool is_throttled) override {
-    test_hooks_->SetInputThrottledUntilCommitOnImpl(is_throttled);
-    ThreadProxy::SetInputThrottledUntilCommitOnImpl(is_throttled);
-  }
-
-  void UpdateTopControlsStateOnImpl(TopControlsState constraints,
-                                    TopControlsState current,
-                                    bool animate) override {
-    test_hooks_->UpdateTopControlsStateOnImpl(constraints, current, animate);
-    ThreadProxy::UpdateTopControlsStateOnImpl(constraints, current, animate);
-  }
-
-  void SetDeferCommitsOnImpl(bool defer_commits) const override {
-    test_hooks_->SetDeferCommitsOnImpl(defer_commits);
-    ThreadProxy::SetDeferCommitsOnImpl(defer_commits);
-  }
-
-  void BeginMainFrameAbortedOnImpl(
-      CommitEarlyOutReason reason,
-      base::TimeTicks main_thread_start_time) override {
-    test_hooks_->BeginMainFrameAbortedOnImpl(reason);
-    ThreadProxy::BeginMainFrameAbortedOnImpl(reason, main_thread_start_time);
-  }
-
-  void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) override {
-    test_hooks_->SetNeedsRedrawOnImpl(damage_rect);
-    ThreadProxy::SetNeedsRedrawOnImpl(damage_rect);
-  };
-
-  void SetNeedsCommitOnImpl() override {
-    test_hooks_->SetNeedsCommitOnImpl();
-    ThreadProxy::SetNeedsCommitOnImpl();
-  }
-
-  void FinishAllRenderingOnImpl(CompletionEvent* completion) override {
-    test_hooks_->FinishAllRenderingOnImpl();
-    ThreadProxy::FinishAllRenderingOnImpl(completion);
-  };
-
-  void SetVisibleOnImpl(bool visible) override {
-    test_hooks_->SetVisibleOnImpl(visible);
-    ThreadProxy::SetVisibleOnImpl(visible);
-  }
-
-  void ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) override {
-    test_hooks_->ReleaseOutputSurfaceOnImpl();
-    ThreadProxy::ReleaseOutputSurfaceOnImpl(completion);
-  }
-
-  void FinishGLOnImpl(CompletionEvent* completion) override {
-    test_hooks_->FinishGLOnImpl();
-    ThreadProxy::FinishGLOnImpl(completion);
-  }
-
-  void StartCommitOnImpl(CompletionEvent* completion,
-                         LayerTreeHost* layer_tree_host,
-                         base::TimeTicks main_thread_start_time,
-                         bool hold_commit_for_activation) override {
-    test_hooks_->StartCommitOnImpl();
-    ThreadProxy::StartCommitOnImpl(completion, layer_tree_host,
-                                   main_thread_start_time,
-                                   hold_commit_for_activation);
-  }
-
-  void InitializeImplOnImpl(CompletionEvent* completion,
-                            LayerTreeHost* layer_tree_host) override {
-    ThreadProxy::InitializeImplOnImpl(completion, layer_tree_host);
-    test_hooks_->InitializeImplOnImpl();
-  }
-
-  void LayerTreeHostClosedOnImpl(CompletionEvent* completion) override {
-    test_hooks_->WillCloseLayerTreeHostOnImpl();
-    ThreadProxy::LayerTreeHostClosedOnImpl(completion);
-  }
-
-  void DidCompleteSwapBuffers() override {
-    test_hooks_->ReceivedDidCompleteSwapBuffers();
-    ThreadProxy::DidCompleteSwapBuffers();
-  }
-
-  void SetRendererCapabilitiesMainCopy(
-      const RendererCapabilities& capabilities) override {
-    test_hooks_->ReceivedSetRendererCapabilitiesMainCopy(capabilities);
-    ThreadProxy::SetRendererCapabilitiesMainCopy(capabilities);
-  }
-
-  void BeginMainFrameNotExpectedSoon() override {
-    test_hooks_->ReceivedBeginMainFrameNotExpectedSoon();
-    ThreadProxy::BeginMainFrameNotExpectedSoon();
-  }
-
-  void DidCommitAndDrawFrame() override {
-    test_hooks_->ReceivedDidCommitAndDrawFrame();
-    ThreadProxy::DidCommitAndDrawFrame();
-  }
-
-  void SetAnimationEvents(scoped_ptr<AnimationEventsVector> events) override {
-    test_hooks_->ReceivedSetAnimationEvents();
-    ThreadProxy::SetAnimationEvents(std::move(events));
-  }
-
-  void DidLoseOutputSurface() override {
-    test_hooks_->ReceivedDidLoseOutputSurface();
-    ThreadProxy::DidLoseOutputSurface();
-  }
-
-  void RequestNewOutputSurface() override {
-    test_hooks_->ReceivedRequestNewOutputSurface();
-    ThreadProxy::RequestNewOutputSurface();
-  }
-
-  void DidInitializeOutputSurface(
-      bool success,
-      const RendererCapabilities& capabilities) override {
-    test_hooks_->ReceivedDidInitializeOutputSurface(success, capabilities);
-    ThreadProxy::DidInitializeOutputSurface(success, capabilities);
-  }
-
-  void DidCompletePageScaleAnimation() override {
-    test_hooks_->ReceivedDidCompletePageScaleAnimation();
-    ThreadProxy::DidCompletePageScaleAnimation();
-  }
-
-  void PostFrameTimingEventsOnMain(
-      scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
-      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events)
-      override {
-    test_hooks_->ReceivedPostFrameTimingEventsOnMain();
-    ThreadProxy::PostFrameTimingEventsOnMain(std::move(composite_events),
-                                             std::move(main_frame_events));
-  }
-
-  void BeginMainFrame(scoped_ptr<BeginMainFrameAndCommitState>
-                          begin_main_frame_state) override {
-    test_hooks_->ReceivedBeginMainFrame();
-    ThreadProxy::BeginMainFrame(std::move(begin_main_frame_state));
-  };
-
-  ThreadProxyForTest(TestHooks* test_hooks,
-                     LayerTreeHost* host,
-                     TaskRunnerProvider* task_runner_provider,
-                     scoped_ptr<BeginFrameSource> external_begin_frame_source)
-      : ThreadProxy(host,
-                    task_runner_provider,
-                    std::move(external_begin_frame_source)),
-        test_hooks_(test_hooks) {}
-};
-
-// Adapts SingleThreadProxy for test. Injects test hooks for testing.
+// Creates a SingleThreadProxy that notifies the supplied |test_hooks| of
+// various actions.
 class SingleThreadProxyForTest : public SingleThreadProxy {
  public:
   static scoped_ptr<Proxy> Create(
@@ -357,7 +113,17 @@
   ~SingleThreadProxyForTest() override {}
 
  private:
-  TestHooks* test_hooks_;
+  SingleThreadProxyForTest(
+      TestHooks* test_hooks,
+      LayerTreeHost* host,
+      LayerTreeHostSingleThreadClient* client,
+      TaskRunnerProvider* task_runner_provider,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source)
+      : SingleThreadProxy(host,
+                          client,
+                          task_runner_provider,
+                          std::move(external_begin_frame_source)),
+        test_hooks_(test_hooks) {}
 
   void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override {
     test_hooks_->ScheduledActionWillSendBeginMainFrame();
@@ -397,17 +163,7 @@
     test_hooks_->SendBeginMainFrameNotExpectedSoon();
   }
 
-  SingleThreadProxyForTest(
-      TestHooks* test_hooks,
-      LayerTreeHost* host,
-      LayerTreeHostSingleThreadClient* client,
-      TaskRunnerProvider* task_runner_provider,
-      scoped_ptr<BeginFrameSource> external_begin_frame_source)
-      : SingleThreadProxy(host,
-                          client,
-                          task_runner_provider,
-                          std::move(external_begin_frame_source)),
-        test_hooks_(test_hooks) {}
+  TestHooks* test_hooks_;
 };
 
 // Adapts LayerTreeHostImpl for test. Runs real code, then invokes test hooks.
@@ -700,9 +456,10 @@
     scoped_ptr<Proxy> proxy;
     if (mode == CompositorMode::Threaded) {
       DCHECK(impl_task_runner.get());
-      proxy = ThreadProxyForTest::Create(
+      scoped_ptr<ProxyMain> proxy_main = ProxyMainForTest::CreateThreaded(
           test_hooks, layer_tree_host.get(), task_runner_provider.get(),
           std::move(external_begin_frame_source));
+      proxy = std::move(proxy_main);
     } else {
       proxy = SingleThreadProxyForTest::Create(
           test_hooks, layer_tree_host.get(), client, task_runner_provider.get(),
@@ -920,10 +677,8 @@
   }
 
   DCHECK(!impl_thread_ || impl_thread_->task_runner().get());
-  CompositorMode mode =
-      impl_thread_ ? CompositorMode::Threaded : CompositorMode::SingleThreaded;
   layer_tree_host_ = LayerTreeHostForTesting::Create(
-      this, mode, client_.get(), shared_bitmap_manager_.get(),
+      this, mode_, client_.get(), shared_bitmap_manager_.get(),
       gpu_memory_buffer_manager_.get(), task_graph_runner_.get(), settings_,
       base::ThreadTaskRunnerHandle::Get(),
       impl_thread_ ? impl_thread_->task_runner() : NULL,
@@ -1054,8 +809,9 @@
     layer_tree_host_->Composite(base::TimeTicks::Now());
 }
 
-void LayerTreeTest::RunTest(bool threaded, bool delegating_renderer) {
-  if (threaded) {
+void LayerTreeTest::RunTest(CompositorMode mode, bool delegating_renderer) {
+  mode_ = mode;
+  if (mode_ == CompositorMode::Threaded) {
     impl_thread_.reset(new base::Thread("Compositor"));
     ASSERT_TRUE(impl_thread_->Start());
   }
@@ -1162,4 +918,21 @@
   return layer_tree_host_.get();
 }
 
+ProxyMainForTest* LayerTreeTest::GetProxyMainForTest() const {
+  DCHECK(HasImplThread());
+  return static_cast<ProxyMainForTest*>(proxy());
+}
+
+ProxyImplForTest* LayerTreeTest::GetProxyImplForTest() const {
+  DCHECK(HasImplThread());
+  ThreadedChannel* threaded_channel =
+      static_cast<ThreadedChannel*>(GetProxyMainForTest()->channel_main());
+  ProxyImpl* proxy_impl = threaded_channel->GetProxyImplForTesting();
+
+  // We check for null ProxyImpl since ProxyImpl exists in the ThreadedChannel
+  // only after it is initialized.
+  DCHECK(proxy_impl);
+  return static_cast<ProxyImplForTest*>(proxy_impl);
+}
+
 }  // namespace cc
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index 59e668d..ea509d5 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -9,6 +9,9 @@
 #include "base/threading/thread.h"
 #include "cc/animation/animation_delegate.h"
 #include "cc/layers/layer_settings.h"
+#include "cc/test/proxy_impl_for_test.h"
+#include "cc/test/proxy_main_for_test.h"
+#include "cc/test/test_hooks.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_host_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -46,130 +49,6 @@
                                  LayerTreeHost* host,
                                  const LayerSettings& layer_settings);
 
-// Used by test stubs to notify the test when something interesting happens.
-class TestHooks : public AnimationDelegate {
- public:
-  TestHooks();
-  ~TestHooks() override;
-
-  void ReadSettings(const LayerTreeSettings& settings);
-
-  virtual void CreateResourceAndTileTaskWorkerPool(
-      LayerTreeHostImpl* host_impl,
-      scoped_ptr<TileTaskWorkerPool>* tile_task_worker_pool,
-      scoped_ptr<ResourcePool>* resource_pool);
-  virtual void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl,
-                                          const BeginFrameArgs& args) {}
-  virtual void DidFinishImplFrameOnThread(LayerTreeHostImpl* host_impl) {}
-  virtual void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl,
-                                             CommitEarlyOutReason reason) {}
-  virtual void WillPrepareTiles(LayerTreeHostImpl* host_impl) {}
-  virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) {}
-  virtual void WillCommitCompleteOnThread(LayerTreeHostImpl* host_impl) {}
-  virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) {}
-  virtual void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) {}
-  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) {}
-  virtual void InitializedRendererOnThread(LayerTreeHostImpl* host_impl,
-                                           bool success) {}
-  virtual DrawResult PrepareToDrawOnThread(
-      LayerTreeHostImpl* host_impl,
-      LayerTreeHostImpl::FrameData* frame_data,
-      DrawResult draw_result);
-  virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) {}
-  virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) {}
-  virtual void SwapBuffersCompleteOnThread(LayerTreeHostImpl* host_impl) {}
-  virtual void NotifyReadyToActivateOnThread(LayerTreeHostImpl* host_impl) {}
-  virtual void NotifyReadyToDrawOnThread(LayerTreeHostImpl* host_impl) {}
-  virtual void NotifyAllTileTasksCompleted(LayerTreeHostImpl* host_impl) {}
-  virtual void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl,
-                                              const Tile* tile) {}
-  virtual void AnimateLayers(LayerTreeHostImpl* host_impl,
-                             base::TimeTicks monotonic_time) {}
-  virtual void UpdateAnimationState(LayerTreeHostImpl* host_impl,
-                                    bool has_unfinished_animation) {}
-  virtual void WillAnimateLayers(LayerTreeHostImpl* host_impl,
-                                 base::TimeTicks monotonic_time) {}
-  virtual void ApplyViewportDeltas(
-      const gfx::Vector2dF& inner_delta,
-      const gfx::Vector2dF& outer_delta,
-      const gfx::Vector2dF& elastic_overscroll_delta,
-      float scale,
-      float top_controls_delta) {}
-  virtual void BeginMainFrame(const BeginFrameArgs& args) {}
-  virtual void WillBeginMainFrame() {}
-  virtual void DidBeginMainFrame() {}
-  virtual void UpdateLayerTreeHost() {}
-  virtual void DidInitializeOutputSurface() {}
-  virtual void DidFailToInitializeOutputSurface() {}
-  virtual void DidAddAnimation() {}
-  virtual void WillCommit() {}
-  virtual void DidCommit() {}
-  virtual void DidCommitAndDrawFrame() {}
-  virtual void DidCompleteSwapBuffers() {}
-  virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* host_impl,
-                                       bool visible) {}
-  virtual void ScheduleComposite() {}
-  virtual void DidSetNeedsUpdateLayers() {}
-  virtual void DidActivateSyncTree() {}
-
-  // Hooks for SchedulerClient.
-  virtual void ScheduledActionWillSendBeginMainFrame() {}
-  virtual void ScheduledActionSendBeginMainFrame() {}
-  virtual void ScheduledActionDrawAndSwapIfPossible() {}
-  virtual void ScheduledActionCommit() {}
-  virtual void ScheduledActionBeginOutputSurfaceCreation() {}
-  virtual void ScheduledActionPrepareTiles() {}
-  virtual void ScheduledActionInvalidateOutputSurface() {}
-  virtual void SendBeginFramesToChildren(const BeginFrameArgs& args) {}
-  virtual void SendBeginMainFrameNotExpectedSoon() {}
-
-  // Hooks for ProxyImpl
-  virtual void SetThrottleFrameProductionOnImpl(bool throttle) {}
-  virtual void UpdateTopControlsStateOnImpl(TopControlsState constraints,
-                                            TopControlsState current,
-                                            bool animate) {}
-  virtual void InitializeOutputSurfaceOnImpl(OutputSurface* output_surface) {}
-  virtual void MainThreadHasStoppedFlingingOnImpl() {}
-  virtual void SetInputThrottledUntilCommitOnImpl(bool is_throttled) {}
-  virtual void SetDeferCommitsOnImpl(bool defer_commits) {}
-  virtual void BeginMainFrameAbortedOnImpl(CommitEarlyOutReason reason) {}
-  virtual void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) {}
-  virtual void SetNeedsCommitOnImpl() {}
-  virtual void FinishAllRenderingOnImpl() {}
-  virtual void SetVisibleOnImpl(bool visible) {}
-  virtual void ReleaseOutputSurfaceOnImpl() {}
-  virtual void FinishGLOnImpl() {}
-  virtual void StartCommitOnImpl() {}
-  virtual void InitializeImplOnImpl() {}
-  virtual void WillCloseLayerTreeHostOnImpl() {}
-
-  // Hooks for ProxyMain
-  virtual void ReceivedDidCompleteSwapBuffers() {}
-  virtual void ReceivedSetRendererCapabilitiesMainCopy(
-      const RendererCapabilities& capabilities) {}
-  virtual void ReceivedBeginMainFrameNotExpectedSoon() {}
-  virtual void ReceivedDidCommitAndDrawFrame() {}
-  virtual void ReceivedSetAnimationEvents() {}
-  virtual void ReceivedDidLoseOutputSurface() {}
-  virtual void ReceivedRequestNewOutputSurface() {}
-  virtual void ReceivedDidInitializeOutputSurface(
-      bool success,
-      const RendererCapabilities& capabilities) {}
-  virtual void ReceivedDidCompletePageScaleAnimation() {}
-  virtual void ReceivedPostFrameTimingEventsOnMain() {}
-  virtual void ReceivedBeginMainFrame() {}
-
-  // Implementation of AnimationDelegate:
-  void NotifyAnimationStarted(base::TimeTicks monotonic_time,
-                              Animation::TargetProperty target_property,
-                              int group) override {}
-  void NotifyAnimationFinished(base::TimeTicks monotonic_time,
-                               Animation::TargetProperty target_property,
-                               int group) override {}
-
-  virtual void RequestNewOutputSurface() = 0;
-};
-
 class BeginTask;
 class LayerTreeHostClientForTesting;
 class TimeoutTask;
@@ -250,9 +129,10 @@
   virtual void BeginTest() = 0;
   virtual void SetupTree();
 
-  virtual void RunTest(bool threaded, bool delegating_renderer);
+  // TODO(khushalsagar): Add mode for running remote channel tests.
+  virtual void RunTest(CompositorMode mode, bool delegating_renderer);
 
-  bool HasImplThread() { return !!impl_thread_; }
+  bool HasImplThread() const { return !!impl_thread_; }
   base::SingleThreadTaskRunner* ImplThreadTaskRunner() {
     DCHECK(task_runner_provider());
     base::SingleThreadTaskRunner* impl_thread_task_runner =
@@ -278,6 +158,12 @@
   FakeOutputSurface* output_surface() { return output_surface_; }
   int LastCommittedSourceFrameNumber(LayerTreeHostImpl* impl) const;
 
+  // Use these only for ProxyMain tests in threaded mode.
+  // TODO(khushalsagar): Update these when adding support for remote channel
+  // tests.
+  ProxyMainForTest* GetProxyMainForTest() const;
+  ProxyImplForTest* GetProxyImplForTest() const;
+
   void DestroyLayerTreeHost();
 
   // By default, output surface recreation is synchronous.
@@ -297,6 +183,8 @@
   LayerTreeSettings settings_;
   LayerSettings layer_settings_;
 
+  CompositorMode mode_;
+
   scoped_ptr<LayerTreeHostClientForTesting> client_;
   scoped_ptr<LayerTreeHost> layer_tree_host_;
   FakeOutputSurface* output_surface_;
@@ -328,13 +216,13 @@
 
 #define SINGLE_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME) \
   TEST_F(TEST_FIXTURE_NAME, RunSingleThread_DirectRenderer) {   \
-    RunTest(false, false);                                      \
+    RunTest(CompositorMode::SingleThreaded, false);             \
   }                                                             \
   class SingleThreadDirectImplNeedsSemicolon##TEST_FIXTURE_NAME {}
 
 #define SINGLE_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME) \
   TEST_F(TEST_FIXTURE_NAME, RunSingleThread_DelegatingRenderer) {   \
-    RunTest(false, true);                                           \
+    RunTest(CompositorMode::SingleThreaded, true);                  \
   }                                                                 \
   class SingleThreadDelegatingImplNeedsSemicolon##TEST_FIXTURE_NAME {}
 
@@ -344,13 +232,13 @@
 
 #define MULTI_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME) \
   TEST_F(TEST_FIXTURE_NAME, RunMultiThread_DirectRenderer) {   \
-    RunTest(true, false);                                      \
+    RunTest(CompositorMode::Threaded, false);                  \
   }                                                            \
   class MultiThreadDirectImplNeedsSemicolon##TEST_FIXTURE_NAME {}
 
 #define MULTI_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME) \
   TEST_F(TEST_FIXTURE_NAME, RunMultiThread_DelegatingRenderer) {   \
-    RunTest(true, true);                                           \
+    RunTest(CompositorMode::Threaded, true);                       \
   }                                                                \
   class MultiThreadDelegatingImplNeedsSemicolon##TEST_FIXTURE_NAME {}
 
diff --git a/cc/test/proxy_impl_for_test.cc b/cc/test/proxy_impl_for_test.cc
new file mode 100644
index 0000000..3cd542b
--- /dev/null
+++ b/cc/test/proxy_impl_for_test.cc
@@ -0,0 +1,163 @@
+// 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/proxy_impl_for_test.h"
+
+namespace cc {
+scoped_ptr<ProxyImpl> ProxyImplForTest::Create(
+    TestHooks* test_hooks,
+    ChannelImpl* channel_impl,
+    LayerTreeHost* layer_tree_host,
+    TaskRunnerProvider* task_runner_provider,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source) {
+  return make_scoped_ptr(new ProxyImplForTest(
+      test_hooks, channel_impl, layer_tree_host, task_runner_provider,
+      std::move(external_begin_frame_source)));
+}
+
+bool ProxyImplForTest::HasCommitCompletionEvent() const {
+  return commit_completion_event_ != nullptr;
+}
+
+bool ProxyImplForTest::GetNextCommitWaitsForActivation() const {
+  return next_commit_waits_for_activation_;
+}
+
+ProxyImplForTest::ProxyImplForTest(
+    TestHooks* test_hooks,
+    ChannelImpl* channel_impl,
+    LayerTreeHost* layer_tree_host,
+    TaskRunnerProvider* task_runner_provider,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source)
+    : ProxyImpl(channel_impl,
+                layer_tree_host,
+                task_runner_provider,
+                std::move(external_begin_frame_source)),
+      test_hooks_(test_hooks) {}
+
+void ProxyImplForTest::ScheduledActionSendBeginMainFrame(
+    const BeginFrameArgs& args) {
+  test_hooks_->ScheduledActionWillSendBeginMainFrame();
+  ProxyImpl::ScheduledActionSendBeginMainFrame(args);
+  test_hooks_->ScheduledActionSendBeginMainFrame();
+}
+
+DrawResult ProxyImplForTest::ScheduledActionDrawAndSwapIfPossible() {
+  DrawResult result = ProxyImpl::ScheduledActionDrawAndSwapIfPossible();
+  test_hooks_->ScheduledActionDrawAndSwapIfPossible();
+  return result;
+}
+
+void ProxyImplForTest::ScheduledActionCommit() {
+  ProxyImpl::ScheduledActionCommit();
+  test_hooks_->ScheduledActionCommit();
+}
+
+void ProxyImplForTest::ScheduledActionBeginOutputSurfaceCreation() {
+  ProxyImpl::ScheduledActionBeginOutputSurfaceCreation();
+  test_hooks_->ScheduledActionBeginOutputSurfaceCreation();
+}
+
+void ProxyImplForTest::ScheduledActionPrepareTiles() {
+  ProxyImpl::ScheduledActionPrepareTiles();
+  test_hooks_->ScheduledActionPrepareTiles();
+}
+
+void ProxyImplForTest::ScheduledActionInvalidateOutputSurface() {
+  ProxyImpl::ScheduledActionInvalidateOutputSurface();
+  test_hooks_->ScheduledActionInvalidateOutputSurface();
+}
+
+void ProxyImplForTest::SendBeginMainFrameNotExpectedSoon() {
+  ProxyImpl::SendBeginMainFrameNotExpectedSoon();
+  test_hooks_->SendBeginMainFrameNotExpectedSoon();
+}
+
+void ProxyImplForTest::DidActivateSyncTree() {
+  ProxyImpl::DidActivateSyncTree();
+  test_hooks_->DidActivateSyncTree();
+}
+
+void ProxyImplForTest::SetThrottleFrameProductionOnImpl(bool throttle) {
+  test_hooks_->SetThrottleFrameProductionOnImpl(throttle);
+  ProxyImpl::SetThrottleFrameProductionOnImpl(throttle);
+}
+
+void ProxyImplForTest::InitializeOutputSurfaceOnImpl(
+    OutputSurface* output_surface) {
+  test_hooks_->InitializeOutputSurfaceOnImpl(output_surface);
+  ProxyImpl::InitializeOutputSurfaceOnImpl(output_surface);
+}
+
+void ProxyImplForTest::MainThreadHasStoppedFlingingOnImpl() {
+  test_hooks_->MainThreadHasStoppedFlingingOnImpl();
+  ProxyImpl::MainThreadHasStoppedFlingingOnImpl();
+}
+
+void ProxyImplForTest::SetInputThrottledUntilCommitOnImpl(bool is_throttled) {
+  test_hooks_->SetInputThrottledUntilCommitOnImpl(is_throttled);
+  ProxyImpl::SetInputThrottledUntilCommitOnImpl(is_throttled);
+}
+
+void ProxyImplForTest::UpdateTopControlsStateOnImpl(
+    TopControlsState constraints,
+    TopControlsState current,
+    bool animate) {
+  test_hooks_->UpdateTopControlsStateOnImpl(constraints, current, animate);
+  ProxyImpl::UpdateTopControlsStateOnImpl(constraints, current, animate);
+}
+
+void ProxyImplForTest::SetDeferCommitsOnImpl(bool defer_commits) const {
+  test_hooks_->SetDeferCommitsOnImpl(defer_commits);
+  ProxyImpl::SetDeferCommitsOnImpl(defer_commits);
+}
+
+void ProxyImplForTest::BeginMainFrameAbortedOnImpl(
+    CommitEarlyOutReason reason,
+    base::TimeTicks main_thread_start_time) {
+  test_hooks_->BeginMainFrameAbortedOnImpl(reason);
+  ProxyImpl::BeginMainFrameAbortedOnImpl(reason, main_thread_start_time);
+}
+
+void ProxyImplForTest::SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) {
+  test_hooks_->SetNeedsRedrawOnImpl(damage_rect);
+  ProxyImpl::SetNeedsRedrawOnImpl(damage_rect);
+}
+
+void ProxyImplForTest::SetNeedsCommitOnImpl() {
+  test_hooks_->SetNeedsCommitOnImpl();
+  ProxyImpl::SetNeedsCommitOnImpl();
+}
+
+void ProxyImplForTest::FinishAllRenderingOnImpl(CompletionEvent* completion) {
+  test_hooks_->FinishAllRenderingOnImpl();
+  ProxyImpl::FinishAllRenderingOnImpl(completion);
+}
+
+void ProxyImplForTest::SetVisibleOnImpl(bool visible) {
+  test_hooks_->SetVisibleOnImpl(visible);
+  ProxyImpl::SetVisibleOnImpl(visible);
+}
+
+void ProxyImplForTest::ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) {
+  test_hooks_->ReleaseOutputSurfaceOnImpl();
+  ProxyImpl::ReleaseOutputSurfaceOnImpl(completion);
+}
+
+void ProxyImplForTest::FinishGLOnImpl(CompletionEvent* completion) {
+  test_hooks_->FinishGLOnImpl();
+  ProxyImpl::FinishGLOnImpl(completion);
+}
+
+void ProxyImplForTest::StartCommitOnImpl(CompletionEvent* completion,
+                                         LayerTreeHost* layer_tree_host,
+                                         base::TimeTicks main_thread_start_time,
+                                         bool hold_commit_for_activation) {
+  test_hooks_->StartCommitOnImpl();
+  ProxyImpl::StartCommitOnImpl(completion, layer_tree_host,
+                               main_thread_start_time,
+                               hold_commit_for_activation);
+}
+
+}  // namespace cc
diff --git a/cc/test/proxy_impl_for_test.h b/cc/test/proxy_impl_for_test.h
new file mode 100644
index 0000000..b81ece5
--- /dev/null
+++ b/cc/test/proxy_impl_for_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_PROXY_IMPL_FOR_TEST_H_
+#define CC_TEST_PROXY_IMPL_FOR_TEST_H_
+
+#include "base/macros.h"
+#include "cc/test/test_hooks.h"
+#include "cc/trees/proxy_impl.h"
+
+namespace cc {
+// Creates a ProxyImpl that notifies the supplied |test_hooks| of various
+// actions.
+class ProxyImplForTest : public ProxyImpl {
+ public:
+  static scoped_ptr<ProxyImpl> Create(
+      TestHooks* test_hooks,
+      ChannelImpl* channel_impl,
+      LayerTreeHost* layer_tree_host,
+      TaskRunnerProvider* task_runner_provider,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source);
+
+  using ProxyImpl::PostAnimationEventsToMainThreadOnImplThread;
+  using ProxyImpl::DidLoseOutputSurfaceOnImplThread;
+  using ProxyImpl::DidCompletePageScaleAnimationOnImplThread;
+  using ProxyImpl::SendBeginMainFrameNotExpectedSoon;
+
+  bool HasCommitCompletionEvent() const;
+  bool GetNextCommitWaitsForActivation() const;
+
+  ProxyImplForTest(TestHooks* test_hooks,
+                   ChannelImpl* channel_impl,
+                   LayerTreeHost* layer_tree_host,
+                   TaskRunnerProvider* task_runner_provider,
+                   scoped_ptr<BeginFrameSource> external_begin_frame_source);
+
+  void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override;
+  DrawResult ScheduledActionDrawAndSwapIfPossible() override;
+  void ScheduledActionCommit() override;
+  void ScheduledActionBeginOutputSurfaceCreation() override;
+  void ScheduledActionPrepareTiles() override;
+  void ScheduledActionInvalidateOutputSurface() override;
+  void SendBeginMainFrameNotExpectedSoon() override;
+  void DidActivateSyncTree() override;
+  void SetThrottleFrameProductionOnImpl(bool throttle) override;
+  void InitializeOutputSurfaceOnImpl(OutputSurface* output_surface) override;
+  void MainThreadHasStoppedFlingingOnImpl() override;
+  void SetInputThrottledUntilCommitOnImpl(bool is_throttled) override;
+  void UpdateTopControlsStateOnImpl(TopControlsState constraints,
+                                    TopControlsState current,
+                                    bool animate) override;
+  void SetDeferCommitsOnImpl(bool defer_commits) const override;
+  void BeginMainFrameAbortedOnImpl(
+      CommitEarlyOutReason reason,
+      base::TimeTicks main_thread_start_time) override;
+  void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) override;
+  void SetNeedsCommitOnImpl() override;
+  void FinishAllRenderingOnImpl(CompletionEvent* completion) override;
+  void SetVisibleOnImpl(bool visible) override;
+  void ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) override;
+  void FinishGLOnImpl(CompletionEvent* completion) override;
+  void StartCommitOnImpl(CompletionEvent* completion,
+                         LayerTreeHost* layer_tree_host,
+                         base::TimeTicks main_thread_start_time,
+                         bool hold_commit_for_activation) override;
+
+  TestHooks* test_hooks_;
+};
+
+}  // namespace cc
+
+#endif  // CC_TEST_PROXY_IMPL_FOR_TEST_H_
diff --git a/cc/test/proxy_main_for_test.cc b/cc/test/proxy_main_for_test.cc
new file mode 100644
index 0000000..4588422e
--- /dev/null
+++ b/cc/test/proxy_main_for_test.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 "cc/test/proxy_main_for_test.h"
+
+#include "cc/test/threaded_channel_for_test.h"
+
+namespace cc {
+
+scoped_ptr<ProxyMain> ProxyMainForTest::CreateThreaded(
+    TestHooks* test_hooks,
+    LayerTreeHost* host,
+    TaskRunnerProvider* task_runner_provider,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source) {
+  scoped_ptr<ProxyMain> proxy_main(
+      new ProxyMainForTest(test_hooks, host, task_runner_provider,
+                           std::move(external_begin_frame_source)));
+  proxy_main->SetChannel(ThreadedChannelForTest::Create(
+      test_hooks, proxy_main.get(), task_runner_provider));
+  return proxy_main;
+}
+
+ProxyMainForTest::~ProxyMainForTest() {}
+
+ProxyMainForTest::ProxyMainForTest(
+    TestHooks* test_hooks,
+    LayerTreeHost* host,
+    TaskRunnerProvider* task_runner_provider,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source)
+    : ProxyMain(host,
+                task_runner_provider,
+                std::move(external_begin_frame_source)),
+      test_hooks_(test_hooks) {}
+
+void ProxyMainForTest::SetNeedsUpdateLayers() {
+  ProxyMain::SetNeedsUpdateLayers();
+  test_hooks_->DidSetNeedsUpdateLayers();
+}
+
+void ProxyMainForTest::DidCompleteSwapBuffers() {
+  test_hooks_->ReceivedDidCompleteSwapBuffers();
+  ProxyMain::DidCompleteSwapBuffers();
+}
+
+void ProxyMainForTest::SetRendererCapabilities(
+    const RendererCapabilities& capabilities) {
+  test_hooks_->ReceivedSetRendererCapabilitiesMainCopy(capabilities);
+  ProxyMain::SetRendererCapabilities(capabilities);
+}
+
+void ProxyMainForTest::BeginMainFrameNotExpectedSoon() {
+  test_hooks_->ReceivedBeginMainFrameNotExpectedSoon();
+  ProxyMain::BeginMainFrameNotExpectedSoon();
+}
+
+void ProxyMainForTest::DidCommitAndDrawFrame() {
+  test_hooks_->ReceivedDidCommitAndDrawFrame();
+  ProxyMain::DidCommitAndDrawFrame();
+}
+
+void ProxyMainForTest::SetAnimationEvents(
+    scoped_ptr<AnimationEventsVector> events) {
+  test_hooks_->ReceivedSetAnimationEvents();
+  ProxyMain::SetAnimationEvents(std::move(events));
+}
+
+void ProxyMainForTest::DidLoseOutputSurface() {
+  test_hooks_->ReceivedDidLoseOutputSurface();
+  ProxyMain::DidLoseOutputSurface();
+}
+
+void ProxyMainForTest::RequestNewOutputSurface() {
+  test_hooks_->ReceivedRequestNewOutputSurface();
+  ProxyMain::RequestNewOutputSurface();
+}
+
+void ProxyMainForTest::DidInitializeOutputSurface(
+    bool success,
+    const RendererCapabilities& capabilities) {
+  test_hooks_->ReceivedDidInitializeOutputSurface(success, capabilities);
+  ProxyMain::DidInitializeOutputSurface(success, capabilities);
+}
+
+void ProxyMainForTest::DidCompletePageScaleAnimation() {
+  test_hooks_->ReceivedDidCompletePageScaleAnimation();
+  ProxyMain::DidCompletePageScaleAnimation();
+}
+
+void ProxyMainForTest::PostFrameTimingEventsOnMain(
+    scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+    scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) {
+  test_hooks_->ReceivedPostFrameTimingEventsOnMain();
+  ProxyMain::PostFrameTimingEventsOnMain(std::move(composite_events),
+                                         std::move(main_frame_events));
+}
+
+void ProxyMainForTest::BeginMainFrame(
+    scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) {
+  test_hooks_->ReceivedBeginMainFrame();
+  ProxyMain::BeginMainFrame(std::move(begin_main_frame_state));
+}
+
+}  // namespace cc
diff --git a/cc/test/proxy_main_for_test.h b/cc/test/proxy_main_for_test.h
new file mode 100644
index 0000000..1669cc5a
--- /dev/null
+++ b/cc/test/proxy_main_for_test.h
@@ -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.
+
+#ifndef CC_TEST_PROXY_MAIN_FOR_TEST_H_
+#define CC_TEST_PROXY_MAIN_FOR_TEST_H_
+
+#include "base/macros.h"
+#include "cc/test/test_hooks.h"
+#include "cc/trees/proxy_main.h"
+
+namespace cc {
+
+// Creates a ProxyMain that notifies the supplied |test_hooks| of various
+// actions.
+class ProxyMainForTest : public ProxyMain {
+ public:
+  static scoped_ptr<ProxyMain> CreateThreaded(
+      TestHooks* test_hooks,
+      LayerTreeHost* host,
+      TaskRunnerProvider* task_runner_provider,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source);
+
+  ~ProxyMainForTest() override;
+
+  ProxyMainForTest(TestHooks* test_hooks,
+                   LayerTreeHost* host,
+                   TaskRunnerProvider* task_runner_provider,
+                   scoped_ptr<BeginFrameSource> external_begin_frame_source);
+
+  void SetNeedsUpdateLayers() override;
+  void DidCompleteSwapBuffers() override;
+  void SetRendererCapabilities(
+      const RendererCapabilities& capabilities) override;
+  void BeginMainFrameNotExpectedSoon() override;
+  void DidCommitAndDrawFrame() override;
+  void SetAnimationEvents(scoped_ptr<AnimationEventsVector> events) override;
+  void DidLoseOutputSurface() override;
+  void RequestNewOutputSurface() override;
+  void DidInitializeOutputSurface(
+      bool success,
+      const RendererCapabilities& capabilities) override;
+  void DidCompletePageScaleAnimation() override;
+  void PostFrameTimingEventsOnMain(
+      scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events)
+      override;
+  void BeginMainFrame(
+      scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) override;
+
+  TestHooks* test_hooks_;
+};
+
+}  // namespace cc
+
+#endif  // CC_TEST_PROXY_MAIN_FOR_TEST_H_
diff --git a/cc/test/test_hooks.cc b/cc/test/test_hooks.cc
new file mode 100644
index 0000000..5c913ac
--- /dev/null
+++ b/cc/test/test_hooks.cc
@@ -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.
+
+#include "cc/test/test_hooks.h"
+
+namespace cc {
+
+TestHooks::TestHooks() {}
+
+TestHooks::~TestHooks() {}
+
+DrawResult TestHooks::PrepareToDrawOnThread(
+    LayerTreeHostImpl* host_impl,
+    LayerTreeHostImpl::FrameData* frame_data,
+    DrawResult draw_result) {
+  return draw_result;
+}
+
+void TestHooks::CreateResourceAndTileTaskWorkerPool(
+    LayerTreeHostImpl* host_impl,
+    scoped_ptr<TileTaskWorkerPool>* tile_task_worker_pool,
+    scoped_ptr<ResourcePool>* resource_pool) {
+  host_impl->LayerTreeHostImpl::CreateResourceAndTileTaskWorkerPool(
+      tile_task_worker_pool, resource_pool);
+}
+
+}  // namespace cc
diff --git a/cc/test/test_hooks.h b/cc/test/test_hooks.h
new file mode 100644
index 0000000..fd45cbc
--- /dev/null
+++ b/cc/test/test_hooks.h
@@ -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.
+
+#ifndef CC_TEST_TEST_HOOKS_H_
+#define CC_TEST_TEST_HOOKS_H_
+
+#include "base/macros.h"
+#include "cc/animation/animation_delegate.h"
+#include "cc/trees/layer_tree_host.h"
+#include "cc/trees/layer_tree_host_impl.h"
+
+namespace cc {
+
+// Used by test stubs to notify the test when something interesting happens.
+class TestHooks : public AnimationDelegate {
+ public:
+  TestHooks();
+  ~TestHooks() override;
+
+  void ReadSettings(const LayerTreeSettings& settings);
+
+  virtual void CreateResourceAndTileTaskWorkerPool(
+      LayerTreeHostImpl* host_impl,
+      scoped_ptr<TileTaskWorkerPool>* tile_task_worker_pool,
+      scoped_ptr<ResourcePool>* resource_pool);
+  virtual void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl,
+                                          const BeginFrameArgs& args) {}
+  virtual void DidFinishImplFrameOnThread(LayerTreeHostImpl* host_impl) {}
+  virtual void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl,
+                                             CommitEarlyOutReason reason) {}
+  virtual void WillPrepareTiles(LayerTreeHostImpl* host_impl) {}
+  virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) {}
+  virtual void WillCommitCompleteOnThread(LayerTreeHostImpl* host_impl) {}
+  virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) {}
+  virtual void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) {}
+  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) {}
+  virtual void InitializedRendererOnThread(LayerTreeHostImpl* host_impl,
+                                           bool success) {}
+  virtual DrawResult PrepareToDrawOnThread(
+      LayerTreeHostImpl* host_impl,
+      LayerTreeHostImpl::FrameData* frame_data,
+      DrawResult draw_result);
+  virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) {}
+  virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) {}
+  virtual void SwapBuffersCompleteOnThread(LayerTreeHostImpl* host_impl) {}
+  virtual void NotifyReadyToActivateOnThread(LayerTreeHostImpl* host_impl) {}
+  virtual void NotifyReadyToDrawOnThread(LayerTreeHostImpl* host_impl) {}
+  virtual void NotifyAllTileTasksCompleted(LayerTreeHostImpl* host_impl) {}
+  virtual void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl,
+                                              const Tile* tile) {}
+  virtual void AnimateLayers(LayerTreeHostImpl* host_impl,
+                             base::TimeTicks monotonic_time) {}
+  virtual void UpdateAnimationState(LayerTreeHostImpl* host_impl,
+                                    bool has_unfinished_animation) {}
+  virtual void WillAnimateLayers(LayerTreeHostImpl* host_impl,
+                                 base::TimeTicks monotonic_time) {}
+  virtual void ApplyViewportDeltas(
+      const gfx::Vector2dF& inner_delta,
+      const gfx::Vector2dF& outer_delta,
+      const gfx::Vector2dF& elastic_overscroll_delta,
+      float scale,
+      float top_controls_delta) {}
+  virtual void BeginMainFrame(const BeginFrameArgs& args) {}
+  virtual void WillBeginMainFrame() {}
+  virtual void DidBeginMainFrame() {}
+  virtual void UpdateLayerTreeHost() {}
+  virtual void DidInitializeOutputSurface() {}
+  virtual void DidFailToInitializeOutputSurface() {}
+  virtual void DidAddAnimation() {}
+  virtual void WillCommit() {}
+  virtual void DidCommit() {}
+  virtual void DidCommitAndDrawFrame() {}
+  virtual void DidCompleteSwapBuffers() {}
+  virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* host_impl,
+                                       bool visible) {}
+  virtual void ScheduleComposite() {}
+  virtual void DidSetNeedsUpdateLayers() {}
+  virtual void DidActivateSyncTree() {}
+
+  // Hooks for SchedulerClient.
+  virtual void ScheduledActionWillSendBeginMainFrame() {}
+  virtual void ScheduledActionSendBeginMainFrame() {}
+  virtual void ScheduledActionDrawAndSwapIfPossible() {}
+  virtual void ScheduledActionCommit() {}
+  virtual void ScheduledActionBeginOutputSurfaceCreation() {}
+  virtual void ScheduledActionPrepareTiles() {}
+  virtual void ScheduledActionInvalidateOutputSurface() {}
+  virtual void SendBeginFramesToChildren(const BeginFrameArgs& args) {}
+  virtual void SendBeginMainFrameNotExpectedSoon() {}
+
+  // Hooks for ProxyImpl
+  virtual void SetThrottleFrameProductionOnImpl(bool throttle) {}
+  virtual void UpdateTopControlsStateOnImpl(TopControlsState constraints,
+                                            TopControlsState current,
+                                            bool animate) {}
+  virtual void InitializeOutputSurfaceOnImpl(OutputSurface* output_surface) {}
+  virtual void MainThreadHasStoppedFlingingOnImpl() {}
+  virtual void SetInputThrottledUntilCommitOnImpl(bool is_throttled) {}
+  virtual void SetDeferCommitsOnImpl(bool defer_commits) {}
+  virtual void BeginMainFrameAbortedOnImpl(CommitEarlyOutReason reason) {}
+  virtual void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) {}
+  virtual void SetNeedsCommitOnImpl() {}
+  virtual void FinishAllRenderingOnImpl() {}
+  virtual void SetVisibleOnImpl(bool visible) {}
+  virtual void ReleaseOutputSurfaceOnImpl() {}
+  virtual void FinishGLOnImpl() {}
+  virtual void StartCommitOnImpl() {}
+
+  // Hooks for ProxyMain
+  virtual void ReceivedDidCompleteSwapBuffers() {}
+  virtual void ReceivedSetRendererCapabilitiesMainCopy(
+      const RendererCapabilities& capabilities) {}
+  virtual void ReceivedBeginMainFrameNotExpectedSoon() {}
+  virtual void ReceivedDidCommitAndDrawFrame() {}
+  virtual void ReceivedSetAnimationEvents() {}
+  virtual void ReceivedDidLoseOutputSurface() {}
+  virtual void ReceivedRequestNewOutputSurface() {}
+  virtual void ReceivedDidInitializeOutputSurface(
+      bool success,
+      const RendererCapabilities& capabilities) {}
+  virtual void ReceivedDidCompletePageScaleAnimation() {}
+  virtual void ReceivedPostFrameTimingEventsOnMain() {}
+  virtual void ReceivedBeginMainFrame() {}
+
+  // Implementation of AnimationDelegate:
+  void NotifyAnimationStarted(base::TimeTicks monotonic_time,
+                              Animation::TargetProperty target_property,
+                              int group) override {}
+  void NotifyAnimationFinished(base::TimeTicks monotonic_time,
+                               Animation::TargetProperty target_property,
+                               int group) override {}
+
+  virtual void RequestNewOutputSurface() = 0;
+};
+
+}  // namespace cc
+
+#endif  // CC_TEST_TEST_HOOKS_H_
diff --git a/cc/test/threaded_channel_for_test.cc b/cc/test/threaded_channel_for_test.cc
new file mode 100644
index 0000000..35489bd
--- /dev/null
+++ b/cc/test/threaded_channel_for_test.cc
@@ -0,0 +1,36 @@
+// Copyright 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/test/threaded_channel_for_test.h"
+
+#include "cc/test/proxy_impl_for_test.h"
+
+namespace cc {
+
+scoped_ptr<ThreadedChannel> ThreadedChannelForTest::Create(
+    TestHooks* test_hooks,
+    ProxyMain* proxy_main,
+    TaskRunnerProvider* task_runner_provider) {
+  return make_scoped_ptr(
+      new ThreadedChannelForTest(test_hooks, proxy_main, task_runner_provider));
+}
+
+ThreadedChannelForTest::ThreadedChannelForTest(
+    TestHooks* test_hooks,
+    ProxyMain* proxy_main,
+    TaskRunnerProvider* task_runner_provider)
+    : ThreadedChannel(proxy_main, task_runner_provider),
+      test_hooks_(test_hooks) {}
+
+scoped_ptr<ProxyImpl> ThreadedChannelForTest::CreateProxyImpl(
+    ChannelImpl* channel_impl,
+    LayerTreeHost* layer_tree_host,
+    TaskRunnerProvider* task_runner_provider,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source) {
+  return ProxyImplForTest::Create(test_hooks_, channel_impl, layer_tree_host,
+                                  task_runner_provider,
+                                  std::move(external_begin_frame_source));
+}
+
+}  // namespace cc
diff --git a/cc/test/threaded_channel_for_test.h b/cc/test/threaded_channel_for_test.h
new file mode 100644
index 0000000..bd74790
--- /dev/null
+++ b/cc/test/threaded_channel_for_test.h
@@ -0,0 +1,38 @@
+// Copyright 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TEST_THREADED_CHANNEL_FOR_TEST_H_
+#define CC_TEST_THREADED_CHANNEL_FOR_TEST_H_
+
+#include "base/macros.h"
+#include "cc/test/test_hooks.h"
+#include "cc/trees/threaded_channel.h"
+
+namespace cc {
+
+// ThreadedChannel that notifies |test_hooks| of internal actions by ProxyImpl.
+class ThreadedChannelForTest : public ThreadedChannel {
+ public:
+  static scoped_ptr<ThreadedChannel> Create(
+      TestHooks* test_hooks,
+      ProxyMain* proxy_main,
+      TaskRunnerProvider* task_runner_provider);
+
+ private:
+  ThreadedChannelForTest(TestHooks* test_hooks,
+                         ProxyMain* proxy_main,
+                         TaskRunnerProvider* task_runner_provider);
+
+  scoped_ptr<ProxyImpl> CreateProxyImpl(
+      ChannelImpl* channel_impl,
+      LayerTreeHost* layer_tree_host,
+      TaskRunnerProvider* task_runner_provider,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source) override;
+
+  TestHooks* test_hooks_;
+};
+
+}  // namespace cc
+
+#endif  // CC_TEST_THREADED_CHANNEL_FOR_TEST_H_
diff --git a/cc/trees/channel_main.h b/cc/trees/channel_main.h
index 8f8c4ee..39861e0 100644
--- a/cc/trees/channel_main.h
+++ b/cc/trees/channel_main.h
@@ -9,10 +9,12 @@
 #include "cc/base/completion_event.h"
 #include "cc/input/top_controls_state.h"
 #include "cc/output/output_surface.h"
+#include "cc/scheduler/begin_frame_source.h"
 #include "cc/scheduler/commit_earlyout_reason.h"
 #include "cc/trees/proxy_common.h"
 
 namespace cc {
+
 // ChannelMain and ChannelImpl provide an abstract communication layer for
 // the main and impl side of the compositor.
 //
@@ -25,7 +27,9 @@
 
 class CC_EXPORT ChannelMain {
  public:
-  // Interface for commands sent to the ProxyImpl
+  virtual ~ChannelMain() {}
+
+  // Interface for commands sent to ProxyImpl
   virtual void SetThrottleFrameProductionOnImpl(bool throttle) = 0;
   virtual void UpdateTopControlsStateOnImpl(TopControlsState constraints,
                                             TopControlsState current,
@@ -37,7 +41,6 @@
   virtual void FinishAllRenderingOnImpl(CompletionEvent* completion) = 0;
   virtual void SetVisibleOnImpl(bool visible) = 0;
   virtual void ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) = 0;
-  virtual void FinishGLOnImpl(CompletionEvent* completion) = 0;
   virtual void MainFrameWillHappenOnImplForTesting(
       CompletionEvent* completion,
       bool* main_frame_will_happen) = 0;
@@ -50,11 +53,14 @@
                                  LayerTreeHost* layer_tree_host,
                                  base::TimeTicks main_thread_start_time,
                                  bool hold_commit_for_activation) = 0;
-  virtual void InitializeImplOnImpl(CompletionEvent* completion,
-                                    LayerTreeHost* layer_tree_host) = 0;
-  virtual void LayerTreeHostClosedOnImpl(CompletionEvent* completion) = 0;
 
-  virtual ~ChannelMain() {}
+  // Must be called before using the channel.
+  virtual void SynchronouslyInitializeImpl(
+      LayerTreeHost* layer_tree_host,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source) = 0;
+
+  // Must be called before deleting the channel.
+  virtual void SynchronouslyCloseImpl() = 0;
 };
 
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index b5f0231..6eb60f643 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -42,8 +42,8 @@
 #include "cc/trees/layer_tree_host_common.h"
 #include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/proxy_main.h"
 #include "cc/trees/single_thread_proxy.h"
-#include "cc/trees/thread_proxy.h"
 #include "cc/trees/tree_synchronizer.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
@@ -143,8 +143,10 @@
     scoped_ptr<BeginFrameSource> external_begin_frame_source) {
   task_runner_provider_ =
       TaskRunnerProvider::Create(main_task_runner, impl_task_runner);
-  InitializeProxy(ThreadProxy::Create(this, task_runner_provider_.get(),
-                                      std::move(external_begin_frame_source)));
+  scoped_ptr<ProxyMain> proxy_main =
+      ProxyMain::CreateThreaded(this, task_runner_provider_.get(),
+                                std::move(external_begin_frame_source));
+  InitializeProxy(std::move(proxy_main));
 }
 
 void LayerTreeHost::InitializeSingleThreaded(
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 3ea2a2d..2cea8bf 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -1299,6 +1299,37 @@
   return order_changed;
 }
 
+static bool CdpPerfTracingEnabled() {
+  bool tracing_enabled;
+  TRACE_EVENT_CATEGORY_GROUP_ENABLED(
+      TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"), &tracing_enabled);
+  return tracing_enabled;
+}
+
+static float TranslationFromActiveTreeLayerScreenSpaceTransform(
+    LayerImpl* pending_tree_layer) {
+  LayerTreeImpl* layer_tree_impl = pending_tree_layer->layer_tree_impl();
+  if (layer_tree_impl) {
+    LayerImpl* active_tree_layer =
+        layer_tree_impl->FindActiveTreeLayerById(pending_tree_layer->id());
+    if (active_tree_layer) {
+      gfx::Transform active_tree_screen_space_transform =
+          active_tree_layer->draw_properties().screen_space_transform;
+      if (active_tree_screen_space_transform.IsIdentity())
+        return 0.f;
+      if (active_tree_screen_space_transform.ApproximatelyEqual(
+              pending_tree_layer->draw_properties().screen_space_transform))
+        return 0.f;
+      return (active_tree_layer->draw_properties()
+                  .screen_space_transform.To2dTranslation() -
+              pending_tree_layer->draw_properties()
+                  .screen_space_transform.To2dTranslation())
+          .Length();
+    }
+  }
+  return 0.f;
+}
+
 // Recursively walks the layer tree starting at the given node and computes all
 // the necessary transformations, clip rects, render surfaces, etc.
 static void CalculateDrawPropertiesInternal(
@@ -2068,37 +2099,50 @@
   data_for_recursion->subtree_is_visible_from_ancestor = true;
 }
 
+// A layer jitters if its screen space transform is same on two successive
+// commits, but has changed in between the commits. CalculateFrameJitter
+// computes the jitter in the entire frame.
+int LayerTreeHostCommon::CalculateFrameJitter(LayerImpl* layer) {
+  if (!layer)
+    return 0.f;
+  float jitter = 0.f;
+  layer->performance_properties().translation_from_last_frame = 0.f;
+  layer->performance_properties().last_commit_screen_space_transform =
+      layer->draw_properties().screen_space_transform;
 
-static bool ApproximatelyEqual(const gfx::Rect& r1, const gfx::Rect& r2) {
-  // TODO(vollick): This tolerance should be lower: crbug.com/471786
-  static const int tolerance = 1;
-
-  return std::abs(r1.x() - r2.x()) <= tolerance &&
-         std::abs(r1.y() - r2.y()) <= tolerance &&
-         std::abs(r1.right() - r2.right()) <= tolerance &&
-         std::abs(r1.bottom() - r2.bottom()) <= tolerance;
-}
-
-static bool ApproximatelyEqual(const gfx::Transform& a,
-                               const gfx::Transform& b) {
-  static const float component_tolerance = 0.1f;
-
-  // We may have a larger discrepancy in the scroll components due to snapping
-  // (floating point error might round the other way).
-  static const float translation_tolerance = 1.f;
-
-  for (int row = 0; row < 4; row++) {
-    for (int col = 0; col < 4; col++) {
-      const float delta =
-          std::abs(a.matrix().get(row, col) - b.matrix().get(row, col));
-      const float tolerance =
-          col == 3 && row < 3 ? translation_tolerance : component_tolerance;
-      if (delta > tolerance)
-        return false;
+  if (!layer->visible_layer_rect().IsEmpty()) {
+    if (layer->draw_properties().screen_space_transform.ApproximatelyEqual(
+            layer->performance_properties()
+                .last_commit_screen_space_transform)) {
+      float translation_from_last_commit =
+          TranslationFromActiveTreeLayerScreenSpaceTransform(layer);
+      if (translation_from_last_commit > 0.f) {
+        layer->performance_properties().num_fixed_point_hits++;
+        layer->performance_properties().translation_from_last_frame =
+            translation_from_last_commit;
+        if (layer->performance_properties().num_fixed_point_hits >
+            layer->layer_tree_impl()->kFixedPointHitsThreshold) {
+          // Jitter = Translation from fixed point * sqrt(Area of the layer).
+          // The square root of the area is used instead of the area to match
+          // the dimensions of both terms on the rhs.
+          jitter += translation_from_last_commit *
+                    sqrt(layer->visible_layer_rect().size().GetArea());
+        }
+      } else {
+        layer->performance_properties().num_fixed_point_hits = 0;
+      }
     }
   }
+  // Descendants of jittering layer will not contribute to unique jitter.
+  if (jitter > 0.f)
+    return jitter;
 
-  return true;
+  for (size_t i = 0; i < layer->children().size(); ++i) {
+    LayerImpl* child_layer =
+        LayerTreeHostCommon::get_layer_as_raw_ptr(layer->children(), i);
+    jitter += CalculateFrameJitter(child_layer);
+  }
+  return jitter;
 }
 
 void VerifyPropertyTreeValuesForSurface(RenderSurfaceImpl* render_surface,
@@ -2106,35 +2150,38 @@
   RenderSurfaceDrawProperties draw_properties;
   ComputeSurfaceDrawPropertiesUsingPropertyTrees(render_surface, property_trees,
                                                  &draw_properties);
+  // TODO(vollick): This tolerance should be lower: crbug.com/471786
+  const int tolerance = 1;
 
   // content_rect has to be computed recursively, so is computed separately from
   // other draw properties.
   draw_properties.content_rect =
       render_surface->content_rect_from_property_trees();
 
-  const bool render_surface_draw_transforms_match = ApproximatelyEqual(
-      render_surface->draw_transform(), draw_properties.draw_transform);
+  const bool render_surface_draw_transforms_match =
+      render_surface->draw_transform().ApproximatelyEqual(
+          draw_properties.draw_transform);
   CHECK(render_surface_draw_transforms_match)
       << "expected: " << render_surface->draw_transform().ToString()
       << " actual: " << draw_properties.draw_transform.ToString();
 
   const bool render_surface_screen_space_transform_match =
-      ApproximatelyEqual(render_surface->screen_space_transform(),
-                         draw_properties.screen_space_transform);
+      render_surface->screen_space_transform().ApproximatelyEqual(
+          draw_properties.screen_space_transform);
   CHECK(render_surface_screen_space_transform_match)
       << "expected: " << render_surface->screen_space_transform().ToString()
       << " actual: " << draw_properties.screen_space_transform.ToString();
 
   const bool render_surface_replica_draw_transforms_match =
-      ApproximatelyEqual(render_surface->replica_draw_transform(),
-                         draw_properties.replica_draw_transform);
+      render_surface->replica_draw_transform().ApproximatelyEqual(
+          draw_properties.replica_draw_transform);
   CHECK(render_surface_replica_draw_transforms_match)
       << "expected: " << render_surface->replica_draw_transform().ToString()
       << " actual: " << draw_properties.replica_draw_transform.ToString();
 
   const bool render_surface_replica_screen_space_transforms_match =
-      ApproximatelyEqual(render_surface->replica_screen_space_transform(),
-                         draw_properties.replica_screen_space_transform);
+      render_surface->replica_screen_space_transform().ApproximatelyEqual(
+          draw_properties.replica_screen_space_transform);
   CHECK(render_surface_replica_screen_space_transforms_match)
       << "expected: "
       << render_surface->replica_screen_space_transform().ToString()
@@ -2143,16 +2190,18 @@
 
   CHECK_EQ(render_surface->is_clipped(), draw_properties.is_clipped);
 
-  const bool render_surface_clip_rects_match = ApproximatelyEqual(
-      render_surface->clip_rect(), draw_properties.clip_rect);
+  const bool render_surface_clip_rects_match =
+      render_surface->clip_rect().ApproximatelyEqual(draw_properties.clip_rect,
+                                                     tolerance);
   CHECK(render_surface_clip_rects_match)
       << "expected: " << render_surface->clip_rect().ToString()
       << " actual: " << draw_properties.clip_rect.ToString();
 
   CHECK_EQ(render_surface->draw_opacity(), draw_properties.draw_opacity);
 
-  const bool render_surface_content_rects_match = ApproximatelyEqual(
-      render_surface->content_rect(), draw_properties.content_rect);
+  const bool render_surface_content_rects_match =
+      render_surface->content_rect().ApproximatelyEqual(
+          draw_properties.content_rect, tolerance);
   CHECK(render_surface_content_rects_match)
       << "expected: " << render_surface->content_rect().ToString()
       << " actual: " << draw_properties.content_rect.ToString();
@@ -2166,15 +2215,20 @@
   ComputeLayerDrawPropertiesUsingPropertyTrees(
       current_layer, property_trees, layers_always_allowed_lcd_text,
       can_use_lcd_text, &draw_properties);
-  const bool visible_rects_match = ApproximatelyEqual(
-      current_layer->visible_layer_rect(), draw_properties.visible_layer_rect);
+  // TODO(vollick): This tolerance should be lower: crbug.com/471786
+  const int tolerance = 1;
+
+  const bool visible_rects_match =
+      current_layer->visible_layer_rect().ApproximatelyEqual(
+          draw_properties.visible_layer_rect, tolerance);
   CHECK(visible_rects_match)
       << "expected: " << current_layer->visible_layer_rect().ToString()
       << " actual: " << draw_properties.visible_layer_rect.ToString();
 
-  const bool draw_transforms_match = ApproximatelyEqual(
-      current_layer->draw_properties().target_space_transform,
-      draw_properties.target_space_transform);
+  const bool draw_transforms_match =
+      current_layer->draw_properties()
+          .target_space_transform.ApproximatelyEqual(
+              draw_properties.target_space_transform);
   CHECK(draw_transforms_match)
       << "expected: "
       << current_layer->draw_properties().target_space_transform.ToString()
@@ -2187,14 +2241,14 @@
            draw_properties.screen_space_transform_is_animating);
 
   const bool drawable_content_rects_match =
-      ApproximatelyEqual(current_layer->drawable_content_rect(),
-                         draw_properties.drawable_content_rect);
+      current_layer->drawable_content_rect().ApproximatelyEqual(
+          draw_properties.drawable_content_rect, tolerance);
   CHECK(drawable_content_rects_match)
       << "expected: " << current_layer->drawable_content_rect().ToString()
       << " actual: " << draw_properties.drawable_content_rect.ToString();
 
-  const bool clip_rects_match =
-      ApproximatelyEqual(current_layer->clip_rect(), draw_properties.clip_rect);
+  const bool clip_rects_match = current_layer->clip_rect().ApproximatelyEqual(
+      draw_properties.clip_rect, tolerance);
   CHECK(clip_rects_match) << "expected: "
                           << current_layer->clip_rect().ToString()
                           << " actual: "
@@ -2700,6 +2754,25 @@
 void LayerTreeHostCommon::CalculateDrawProperties(
     CalcDrawPropsImplInputs* inputs) {
   CalculateDrawPropertiesAndVerify(inputs, DONT_BUILD_PROPERTY_TREES);
+
+  if (CdpPerfTracingEnabled()) {
+    LayerTreeImpl* layer_tree_impl = inputs->root_layer->layer_tree_impl();
+    if (layer_tree_impl->IsPendingTree() &&
+        layer_tree_impl->is_first_frame_after_commit()) {
+      LayerImpl* active_tree_root =
+          layer_tree_impl->FindActiveTreeLayerById(inputs->root_layer->id());
+      float jitter = 0.f;
+      if (active_tree_root) {
+        LayerImpl* last_scrolled_layer = layer_tree_impl->LayerById(
+            active_tree_root->layer_tree_impl()->LastScrolledLayerId());
+        jitter = CalculateFrameJitter(last_scrolled_layer);
+      }
+      TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"), "jitter",
+                     jitter);
+      inputs->root_layer->layer_tree_impl()->set_is_first_frame_after_commit(
+          false);
+    }
+  }
 }
 
 void LayerTreeHostCommon::CalculateDrawProperties(
diff --git a/cc/trees/layer_tree_host_common.h b/cc/trees/layer_tree_host_common.h
index 9265932..6ebd86a 100644
--- a/cc/trees/layer_tree_host_common.h
+++ b/cc/trees/layer_tree_host_common.h
@@ -115,6 +115,7 @@
                                       int current_render_surface_layer_list_id);
   };
 
+  static int CalculateFrameJitter(LayerImpl* scrolling_layer);
   static void CalculateDrawProperties(CalcDrawPropsMainInputs* inputs);
   static void PreCalculateMetaInformation(Layer* root_layer);
   static void PreCalculateMetaInformationForTesting(LayerImpl* root_layer);
diff --git a/cc/trees/layer_tree_host_common_perftest.cc b/cc/trees/layer_tree_host_common_perftest.cc
index 46080f3..9bb4550 100644
--- a/cc/trees/layer_tree_host_common_perftest.cc
+++ b/cc/trees/layer_tree_host_common_perftest.cc
@@ -79,7 +79,7 @@
 
 class CalcDrawPropsTest : public LayerTreeHostCommonPerfTest {
  public:
-  void RunCalcDrawProps() { RunTest(false, false); }
+  void RunCalcDrawProps() { RunTest(CompositorMode::SingleThreaded, false); }
 
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
@@ -132,7 +132,7 @@
 class BspTreePerfTest : public CalcDrawPropsTest {
  public:
   BspTreePerfTest() : num_duplicates_(1) {}
-  void RunSortLayers() { RunTest(false, false); }
+  void RunSortLayers() { RunTest(CompositorMode::SingleThreaded, false); }
 
   void SetNumberOfDuplicates(int num_duplicates) {
     num_duplicates_ = num_duplicates;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index ea9097ee..9524e41 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -43,6 +43,7 @@
 #include "cc/layers/painted_scrollbar_layer_impl.h"
 #include "cc/layers/render_surface_impl.h"
 #include "cc/layers/scrollbar_layer_impl_base.h"
+#include "cc/layers/surface_layer_impl.h"
 #include "cc/layers/viewport.h"
 #include "cc/output/compositor_frame_metadata.h"
 #include "cc/output/copy_output_request.h"
@@ -1588,6 +1589,10 @@
         !OuterViewportScrollLayer()->user_scrollable_vertical();
   }
 
+  for (LayerImpl* surface_layer : active_tree_->SurfaceLayers()) {
+    metadata.referenced_surfaces.push_back(
+        static_cast<SurfaceLayerImpl*>(surface_layer)->surface_id());
+  }
   if (!InnerViewportScrollLayer())
     return metadata;
 
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 3dd4fb9..ca513c0 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -9282,5 +9282,54 @@
   EXPECT_EQ(node->data.sublayer_scale, gfx::Vector2dF(2.f, 2.f));
 }
 
+TEST_F(LayerTreeHostImplTest, JitterTest) {
+  host_impl_->SetViewportSize(gfx::Size(100, 100));
+
+  host_impl_->CreatePendingTree();
+  CreateScrollAndContentsLayers(host_impl_->pending_tree(),
+                                gfx::Size(100, 100));
+
+  host_impl_->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f);
+  host_impl_->pending_tree()->BuildPropertyTreesForTesting();
+  const int scroll = 5;
+  int accumulated_scroll = 0;
+  for (int i = 0; i < host_impl_->pending_tree()->kFixedPointHitsThreshold + 1;
+       ++i) {
+    host_impl_->ActivateSyncTree();
+    host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::GESTURE);
+    host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, scroll));
+    accumulated_scroll += scroll;
+    host_impl_->ScrollEnd();
+    host_impl_->active_tree()->UpdateDrawProperties(false);
+
+    host_impl_->CreatePendingTree();
+    host_impl_->pending_tree()->set_source_frame_number(i + 1);
+    LayerImpl* content_layer = host_impl_->pending_tree()
+                                   ->OuterViewportScrollLayer()
+                                   ->children()[0]
+                                   .get();
+    // The scroll done on the active tree is undone on the pending tree.
+    gfx::Transform translate;
+    translate.Translate(0, accumulated_scroll);
+    content_layer->SetTransform(translate);
+
+    LayerTreeImpl* pending_tree = host_impl_->pending_tree();
+    pending_tree->PushPageScaleFromMainThread(1.f, 1.f, 1.f);
+    pending_tree->property_trees()->needs_rebuild = true;
+    pending_tree->BuildPropertyTreesForTesting();
+    pending_tree->set_needs_update_draw_properties();
+    pending_tree->UpdateDrawProperties(false);
+    LayerImpl* last_scrolled_layer = pending_tree->LayerById(
+        host_impl_->active_tree()->LastScrolledLayerId());
+    float jitter =
+        LayerTreeHostCommon::CalculateFrameJitter(last_scrolled_layer);
+    // There should not be any jitter measured till we hit the fixed point hits
+    // threshold.
+    float expected_jitter =
+        (i == pending_tree->kFixedPointHitsThreshold) ? 500 : 0;
+    EXPECT_EQ(jitter, expected_jitter);
+  }
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_perftest.cc b/cc/trees/layer_tree_host_perftest.cc
index af33851..3acd9a5 100644
--- a/cc/trees/layer_tree_host_perftest.cc
+++ b/cc/trees/layer_tree_host_perftest.cc
@@ -149,13 +149,13 @@
 TEST_F(LayerTreeHostPerfTestJsonReader, TenTenSingleThread) {
   SetTestName("10_10_single_thread");
   ReadTestFile("10_10_layer_tree");
-  RunTest(false, false);
+  RunTest(CompositorMode::SingleThreaded, false);
 }
 
 TEST_F(LayerTreeHostPerfTestJsonReader, TenTenThreaded) {
   SetTestName("10_10_threaded_impl_side");
   ReadTestFile("10_10_layer_tree");
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 // Simulates a tab switcher scene with two stacks of 10 tabs each.
@@ -164,14 +164,14 @@
   full_damage_each_frame_ = true;
   SetTestName("10_10_single_thread_full_damage_each_frame");
   ReadTestFile("10_10_layer_tree");
-  RunTest(false, false);
+  RunTest(CompositorMode::SingleThreaded, false);
 }
 
 TEST_F(LayerTreeHostPerfTestJsonReader, TenTenThreaded_FullDamageEachFrame) {
   full_damage_each_frame_ = true;
   SetTestName("10_10_threaded_impl_side_full_damage_each_frame");
   ReadTestFile("10_10_layer_tree");
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 // Invalidates a leaf layer in the tree on the main thread after every commit.
@@ -205,13 +205,13 @@
 TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenSingleThread) {
   SetTestName("10_10_single_thread_leaf_invalidates");
   ReadTestFile("10_10_layer_tree");
-  RunTest(false, false);
+  RunTest(CompositorMode::SingleThreaded, false);
 }
 
 TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenThreaded) {
   SetTestName("10_10_threaded_impl_side_leaf_invalidates");
   ReadTestFile("10_10_layer_tree");
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 // Simulates main-thread scrolling on each frame.
@@ -246,7 +246,7 @@
   // crbug.com/444219 is fixed.
   bool old_verify_property_trees = verify_property_trees();
   set_verify_property_trees(false);
-  RunTest(false, false);
+  RunTest(CompositorMode::SingleThreaded, false);
   set_verify_property_trees(old_verify_property_trees);
 }
 
@@ -257,7 +257,7 @@
   // crbug.com/444219 is fixed.
   bool old_verify_property_trees = verify_property_trees();
   set_verify_property_trees(false);
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
   set_verify_property_trees(old_verify_property_trees);
 }
 
@@ -333,7 +333,7 @@
   measure_commit_cost_ = true;
   SetTestName("dense_layer_tree");
   ReadTestFile("dense_layer_tree");
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 // Simulates a page with several large, transformed and animated layers.
@@ -342,7 +342,7 @@
   measure_commit_cost_ = true;
   SetTestName("heavy_page");
   ReadTestFile("heavy_layer_tree");
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 }  // namespace
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index a68cb02..fdcc26d 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -49,7 +49,6 @@
 #include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/single_thread_proxy.h"
-#include "cc/trees/thread_proxy.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "skia/ext/refptr.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -74,9 +73,9 @@
  public:
   LayerTreeHostTestHasImplThreadTest() : threaded_(false) {}
 
-  void RunTest(bool threaded, bool delegating_renderer) override {
-    threaded_ = threaded;
-    LayerTreeHostTest::RunTest(threaded, delegating_renderer);
+  void RunTest(CompositorMode mode, bool delegating_renderer) override {
+    threaded_ = mode == CompositorMode::Threaded;
+    LayerTreeHostTest::RunTest(mode, delegating_renderer);
   }
 
   void BeginTest() override {
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index ead16f2..8c5dd8aa 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -785,49 +785,49 @@
 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
        LoseAfterEvict_SingleThread_DirectRenderer) {
   lose_after_evict_ = true;
-  RunTest(false, false);
+  RunTest(CompositorMode::SingleThreaded, false);
 }
 
 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
        LoseAfterEvict_SingleThread_DelegatingRenderer) {
   lose_after_evict_ = true;
-  RunTest(false, true);
+  RunTest(CompositorMode::SingleThreaded, true);
 }
 
 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
        LoseAfterEvict_MultiThread_DirectRenderer) {
   lose_after_evict_ = true;
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
        LoseAfterEvict_MultiThread_DelegatingRenderer) {
   lose_after_evict_ = true;
-  RunTest(true, true);
+  RunTest(CompositorMode::Threaded, true);
 }
 
 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
        LoseBeforeEvict_SingleThread_DirectRenderer) {
   lose_after_evict_ = false;
-  RunTest(false, false);
+  RunTest(CompositorMode::SingleThreaded, false);
 }
 
 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
        LoseBeforeEvict_SingleThread_DelegatingRenderer) {
   lose_after_evict_ = false;
-  RunTest(false, true);
+  RunTest(CompositorMode::SingleThreaded, true);
 }
 
 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
        LoseBeforeEvict_MultiThread_DirectRenderer) {
   lose_after_evict_ = false;
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
        LoseBeforeEvict_MultiThread_DelegatingRenderer) {
   lose_after_evict_ = false;
-  RunTest(true, true);
+  RunTest(CompositorMode::Threaded, true);
 }
 
 class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc
index 44c5ffb99..32a54949 100644
--- a/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -146,39 +146,39 @@
 TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
        GLRenderer_RunSingleThread) {
   use_gl_renderer_ = true;
-  RunTest(false, false);
+  RunTest(CompositorMode::SingleThreaded, false);
 }
 
 TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
        GLRenderer_RunMultiThread) {
   use_gl_renderer_ = true;
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
        GLRenderer_RunSingleThread_OutOfOrderCallbacks) {
   use_gl_renderer_ = true;
   out_of_order_callbacks_ = true;
-  RunTest(false, false);
+  RunTest(CompositorMode::SingleThreaded, false);
 }
 
 TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
        GLRenderer_RunMultiThread_OutOfOrderCallbacks) {
   use_gl_renderer_ = true;
   out_of_order_callbacks_ = true;
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
        SoftwareRenderer_RunSingleThread) {
   use_gl_renderer_ = false;
-  RunTest(false, false);
+  RunTest(CompositorMode::SingleThreaded, false);
 }
 
 TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
        SoftwareRenderer_RunMultiThread) {
   use_gl_renderer_ = false;
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 // TODO(crbug.com/564832): Remove this test when the workaround it tests is no
diff --git a/cc/trees/layer_tree_host_unittest_proxy.cc b/cc/trees/layer_tree_host_unittest_proxy.cc
index 2605dd9..e00b0854 100644
--- a/cc/trees/layer_tree_host_unittest_proxy.cc
+++ b/cc/trees/layer_tree_host_unittest_proxy.cc
@@ -7,15 +7,16 @@
 #include "cc/test/fake_content_layer_client.h"
 #include "cc/test/fake_picture_layer.h"
 #include "cc/test/layer_tree_test.h"
-#include "cc/trees/thread_proxy.h"
+#include "cc/trees/proxy_impl.h"
+#include "cc/trees/proxy_main.h"
 
-#define THREAD_PROXY_TEST_F(TEST_FIXTURE_NAME) \
+#define PROXY_MAIN_THREADED_TEST_F(TEST_FIXTURE_NAME) \
   TEST_F(TEST_FIXTURE_NAME, MultiThread) { Run(true); }
 
-// Do common tests for single thread proxy and thread proxy.
+// Do common tests for single thread proxy and proxy main in threaded mode.
 // TODO(simonhong): Add SINGLE_THREAD_PROXY_TEST_F
 #define PROXY_TEST_SCHEDULED_ACTION(TEST_FIXTURE_NAME) \
-  THREAD_PROXY_TEST_F(TEST_FIXTURE_NAME);
+  PROXY_MAIN_THREADED_TEST_F(TEST_FIXTURE_NAME);
 
 namespace cc {
 
@@ -28,7 +29,9 @@
     // We don't need to care about delegating mode.
     bool delegating_renderer = true;
 
-    RunTest(threaded, delegating_renderer);
+    CompositorMode mode =
+        threaded ? CompositorMode::Threaded : CompositorMode::SingleThreaded;
+    RunTest(mode, delegating_renderer);
   }
 
   void BeginTest() override {}
@@ -71,12 +74,12 @@
 
 PROXY_TEST_SCHEDULED_ACTION(ProxyTestScheduledActionsBasic);
 
-class ThreadProxyTest : public ProxyTest {
+class ProxyMainThreaded : public ProxyTest {
  protected:
-  ThreadProxyTest()
+  ProxyMainThreaded()
       : update_check_layer_(
             FakePictureLayer::Create(layer_settings(), &client_)) {}
-  ~ThreadProxyTest() override {}
+  ~ProxyMainThreaded() override {}
 
   void SetupTree() override {
     layer_tree_host()->SetRootLayer(update_check_layer_);
@@ -84,83 +87,69 @@
     client_.set_bounds(update_check_layer_->bounds());
   }
 
-  const ThreadProxy::MainThreadOnly& ThreadProxyMainOnly() const {
-    DCHECK(task_runner_provider());
-    DCHECK(task_runner_provider()->HasImplThread());
-    DCHECK(proxy());
-    return static_cast<const ThreadProxy*>(proxy())->main();
-  }
-
-  const ThreadProxy::CompositorThreadOnly& ThreadProxyImplOnly() const {
-    DCHECK(task_runner_provider());
-    DCHECK(task_runner_provider()->HasImplThread());
-    DCHECK(proxy());
-    return static_cast<const ThreadProxy*>(proxy())->impl();
-  }
-
  protected:
   FakeContentLayerClient client_;
   scoped_refptr<FakePictureLayer> update_check_layer_;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(ThreadProxyTest);
+  DISALLOW_COPY_AND_ASSIGN(ProxyMainThreaded);
 };
 
-class ThreadProxyTestSetNeedsCommit : public ThreadProxyTest {
+class ProxyMainThreadedSetNeedsCommit : public ProxyMainThreaded {
  protected:
-  ThreadProxyTestSetNeedsCommit() {}
-  ~ThreadProxyTestSetNeedsCommit() override {}
+  ProxyMainThreadedSetNeedsCommit() {}
+  ~ProxyMainThreadedSetNeedsCommit() override {}
 
   void BeginTest() override {
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().max_requested_pipeline_stage);
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->max_requested_pipeline_stage());
 
     proxy()->SetNeedsCommit();
 
-    EXPECT_EQ(ThreadProxy::COMMIT_PIPELINE_STAGE,
-              ThreadProxyMainOnly().max_requested_pipeline_stage);
+    EXPECT_EQ(ProxyMain::COMMIT_PIPELINE_STAGE,
+              GetProxyMainForTest()->max_requested_pipeline_stage());
   }
 
   void DidBeginMainFrame() override {
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().max_requested_pipeline_stage);
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().current_pipeline_stage);
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->max_requested_pipeline_stage());
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->current_pipeline_stage());
   }
 
   void DidCommit() override {
     EXPECT_EQ(1, update_check_layer_->update_count());
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().current_pipeline_stage);
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->current_pipeline_stage());
     EndTest();
   }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(ThreadProxyTestSetNeedsCommit);
+  DISALLOW_COPY_AND_ASSIGN(ProxyMainThreadedSetNeedsCommit);
 };
 
-THREAD_PROXY_TEST_F(ThreadProxyTestSetNeedsCommit);
+PROXY_MAIN_THREADED_TEST_F(ProxyMainThreadedSetNeedsCommit);
 
-class ThreadProxyTestSetNeedsAnimate : public ThreadProxyTest {
+class ProxyMainThreadedSetNeedsAnimate : public ProxyMainThreaded {
  protected:
-  ThreadProxyTestSetNeedsAnimate() {}
-  ~ThreadProxyTestSetNeedsAnimate() override {}
+  ProxyMainThreadedSetNeedsAnimate() {}
+  ~ProxyMainThreadedSetNeedsAnimate() override {}
 
   void BeginTest() override {
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().max_requested_pipeline_stage);
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->max_requested_pipeline_stage());
 
     proxy()->SetNeedsAnimate();
 
-    EXPECT_EQ(ThreadProxy::ANIMATE_PIPELINE_STAGE,
-              ThreadProxyMainOnly().max_requested_pipeline_stage);
+    EXPECT_EQ(ProxyMain::ANIMATE_PIPELINE_STAGE,
+              GetProxyMainForTest()->max_requested_pipeline_stage());
   }
 
   void DidBeginMainFrame() override {
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().max_requested_pipeline_stage);
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().current_pipeline_stage);
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->max_requested_pipeline_stage());
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->current_pipeline_stage());
   }
 
   void DidCommit() override {
@@ -169,31 +158,31 @@
   }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(ThreadProxyTestSetNeedsAnimate);
+  DISALLOW_COPY_AND_ASSIGN(ProxyMainThreadedSetNeedsAnimate);
 };
 
-THREAD_PROXY_TEST_F(ThreadProxyTestSetNeedsAnimate);
+PROXY_MAIN_THREADED_TEST_F(ProxyMainThreadedSetNeedsAnimate);
 
-class ThreadProxyTestSetNeedsUpdateLayers : public ThreadProxyTest {
+class ProxyMainThreadedSetNeedsUpdateLayers : public ProxyMainThreaded {
  protected:
-  ThreadProxyTestSetNeedsUpdateLayers() {}
-  ~ThreadProxyTestSetNeedsUpdateLayers() override {}
+  ProxyMainThreadedSetNeedsUpdateLayers() {}
+  ~ProxyMainThreadedSetNeedsUpdateLayers() override {}
 
   void BeginTest() override {
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().max_requested_pipeline_stage);
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->max_requested_pipeline_stage());
 
     proxy()->SetNeedsUpdateLayers();
 
-    EXPECT_EQ(ThreadProxy::UPDATE_LAYERS_PIPELINE_STAGE,
-              ThreadProxyMainOnly().max_requested_pipeline_stage);
+    EXPECT_EQ(ProxyMain::UPDATE_LAYERS_PIPELINE_STAGE,
+              GetProxyMainForTest()->max_requested_pipeline_stage());
   }
 
   void DidBeginMainFrame() override {
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().max_requested_pipeline_stage);
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().current_pipeline_stage);
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->max_requested_pipeline_stage());
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->current_pipeline_stage());
   }
 
   void DidCommit() override {
@@ -202,40 +191,40 @@
   }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(ThreadProxyTestSetNeedsUpdateLayers);
+  DISALLOW_COPY_AND_ASSIGN(ProxyMainThreadedSetNeedsUpdateLayers);
 };
 
-THREAD_PROXY_TEST_F(ThreadProxyTestSetNeedsUpdateLayers);
+PROXY_MAIN_THREADED_TEST_F(ProxyMainThreadedSetNeedsUpdateLayers);
 
-class ThreadProxyTestSetNeedsUpdateLayersWhileAnimating
-    : public ThreadProxyTest {
+class ProxyMainThreadedSetNeedsUpdateLayersWhileAnimating
+    : public ProxyMainThreaded {
  protected:
-  ThreadProxyTestSetNeedsUpdateLayersWhileAnimating() {}
-  ~ThreadProxyTestSetNeedsUpdateLayersWhileAnimating() override {}
+  ProxyMainThreadedSetNeedsUpdateLayersWhileAnimating() {}
+  ~ProxyMainThreadedSetNeedsUpdateLayersWhileAnimating() override {}
 
   void BeginTest() override { proxy()->SetNeedsAnimate(); }
 
   void WillBeginMainFrame() override {
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().max_requested_pipeline_stage);
-    EXPECT_EQ(ThreadProxy::ANIMATE_PIPELINE_STAGE,
-              ThreadProxyMainOnly().current_pipeline_stage);
-    EXPECT_EQ(ThreadProxy::ANIMATE_PIPELINE_STAGE,
-              ThreadProxyMainOnly().final_pipeline_stage);
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->max_requested_pipeline_stage());
+    EXPECT_EQ(ProxyMain::ANIMATE_PIPELINE_STAGE,
+              GetProxyMainForTest()->current_pipeline_stage());
+    EXPECT_EQ(ProxyMain::ANIMATE_PIPELINE_STAGE,
+              GetProxyMainForTest()->final_pipeline_stage());
 
     proxy()->SetNeedsUpdateLayers();
 
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().max_requested_pipeline_stage);
-    EXPECT_EQ(ThreadProxy::UPDATE_LAYERS_PIPELINE_STAGE,
-              ThreadProxyMainOnly().final_pipeline_stage);
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->max_requested_pipeline_stage());
+    EXPECT_EQ(ProxyMain::UPDATE_LAYERS_PIPELINE_STAGE,
+              GetProxyMainForTest()->final_pipeline_stage());
   }
 
   void DidBeginMainFrame() override {
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().max_requested_pipeline_stage);
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().current_pipeline_stage);
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->max_requested_pipeline_stage());
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->current_pipeline_stage());
   }
 
   void DidCommit() override {
@@ -244,39 +233,39 @@
   }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(ThreadProxyTestSetNeedsUpdateLayersWhileAnimating);
+  DISALLOW_COPY_AND_ASSIGN(ProxyMainThreadedSetNeedsUpdateLayersWhileAnimating);
 };
 
-THREAD_PROXY_TEST_F(ThreadProxyTestSetNeedsUpdateLayersWhileAnimating);
+PROXY_MAIN_THREADED_TEST_F(ProxyMainThreadedSetNeedsUpdateLayersWhileAnimating);
 
-class ThreadProxyTestSetNeedsCommitWhileAnimating : public ThreadProxyTest {
+class ProxyMainThreadedSetNeedsCommitWhileAnimating : public ProxyMainThreaded {
  protected:
-  ThreadProxyTestSetNeedsCommitWhileAnimating() {}
-  ~ThreadProxyTestSetNeedsCommitWhileAnimating() override {}
+  ProxyMainThreadedSetNeedsCommitWhileAnimating() {}
+  ~ProxyMainThreadedSetNeedsCommitWhileAnimating() override {}
 
   void BeginTest() override { proxy()->SetNeedsAnimate(); }
 
   void WillBeginMainFrame() override {
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().max_requested_pipeline_stage);
-    EXPECT_EQ(ThreadProxy::ANIMATE_PIPELINE_STAGE,
-              ThreadProxyMainOnly().current_pipeline_stage);
-    EXPECT_EQ(ThreadProxy::ANIMATE_PIPELINE_STAGE,
-              ThreadProxyMainOnly().final_pipeline_stage);
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->max_requested_pipeline_stage());
+    EXPECT_EQ(ProxyMain::ANIMATE_PIPELINE_STAGE,
+              GetProxyMainForTest()->current_pipeline_stage());
+    EXPECT_EQ(ProxyMain::ANIMATE_PIPELINE_STAGE,
+              GetProxyMainForTest()->final_pipeline_stage());
 
     proxy()->SetNeedsCommit();
 
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().max_requested_pipeline_stage);
-    EXPECT_EQ(ThreadProxy::COMMIT_PIPELINE_STAGE,
-              ThreadProxyMainOnly().final_pipeline_stage);
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->max_requested_pipeline_stage());
+    EXPECT_EQ(ProxyMain::COMMIT_PIPELINE_STAGE,
+              GetProxyMainForTest()->final_pipeline_stage());
   }
 
   void DidBeginMainFrame() override {
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().max_requested_pipeline_stage);
-    EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE,
-              ThreadProxyMainOnly().current_pipeline_stage);
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->max_requested_pipeline_stage());
+    EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
+              GetProxyMainForTest()->current_pipeline_stage());
   }
 
   void DidCommit() override {
@@ -285,15 +274,15 @@
   }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(ThreadProxyTestSetNeedsCommitWhileAnimating);
+  DISALLOW_COPY_AND_ASSIGN(ProxyMainThreadedSetNeedsCommitWhileAnimating);
 };
 
-THREAD_PROXY_TEST_F(ThreadProxyTestSetNeedsCommitWhileAnimating);
+PROXY_MAIN_THREADED_TEST_F(ProxyMainThreadedSetNeedsCommitWhileAnimating);
 
-class ThreadProxyTestCommitWaitsForActivation : public ThreadProxyTest {
+class ProxyMainThreadedCommitWaitsForActivation : public ProxyMainThreaded {
  protected:
-  ThreadProxyTestCommitWaitsForActivation() : commits_completed_(0) {}
-  ~ThreadProxyTestCommitWaitsForActivation() override {}
+  ProxyMainThreadedCommitWaitsForActivation() : commits_completed_(0) {}
+  ~ProxyMainThreadedCommitWaitsForActivation() override {}
 
   void BeginTest() override { proxy()->SetNeedsCommit(); }
 
@@ -302,25 +291,25 @@
       case 0:
         // The first commit does not wait for activation. Verify that the
         // completion event is cleared.
-        EXPECT_FALSE(ThreadProxyImplOnly().commit_completion_event);
-        EXPECT_FALSE(ThreadProxyImplOnly().next_commit_waits_for_activation);
+        EXPECT_FALSE(GetProxyImplForTest()->HasCommitCompletionEvent());
+        EXPECT_FALSE(GetProxyImplForTest()->GetNextCommitWaitsForActivation());
         break;
       case 1:
         // The second commit should be held until activation.
-        EXPECT_TRUE(ThreadProxyImplOnly().commit_completion_event);
-        EXPECT_TRUE(ThreadProxyImplOnly().next_commit_waits_for_activation);
+        EXPECT_TRUE(GetProxyImplForTest()->HasCommitCompletionEvent());
+        EXPECT_TRUE(GetProxyImplForTest()->GetNextCommitWaitsForActivation());
         break;
       case 2:
         // The third commit should not wait for activation.
-        EXPECT_FALSE(ThreadProxyImplOnly().commit_completion_event);
-        EXPECT_FALSE(ThreadProxyImplOnly().next_commit_waits_for_activation);
+        EXPECT_FALSE(GetProxyImplForTest()->HasCommitCompletionEvent());
+        EXPECT_FALSE(GetProxyImplForTest()->GetNextCommitWaitsForActivation());
     }
   }
 
   void DidActivateSyncTree() override {
     // The next_commit_waits_for_activation should have been cleared after the
     // sync tree is activated.
-    EXPECT_FALSE(ThreadProxyImplOnly().next_commit_waits_for_activation);
+    EXPECT_FALSE(GetProxyImplForTest()->GetNextCommitWaitsForActivation());
   }
 
   void DidCommit() override {
@@ -347,9 +336,9 @@
  private:
   int commits_completed_;
 
-  DISALLOW_COPY_AND_ASSIGN(ThreadProxyTestCommitWaitsForActivation);
+  DISALLOW_COPY_AND_ASSIGN(ProxyMainThreadedCommitWaitsForActivation);
 };
 
-THREAD_PROXY_TEST_F(ThreadProxyTestCommitWaitsForActivation);
+PROXY_MAIN_THREADED_TEST_F(ProxyMainThreadedCommitWaitsForActivation);
 
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc
index 8eeed1a..d7f8c32 100644
--- a/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -585,14 +585,20 @@
     EXPECT_EQ(device_scale_factor_, impl->active_tree()->device_scale_factor());
     switch (impl->active_tree()->source_frame_number()) {
       case 0: {
-        // GESTURE scroll on impl thread.
+        // GESTURE scroll on impl thread. Also tests that the last scrolled
+        // layer id is stored even after the scrolling ends.
         InputHandler::ScrollStatus status = impl->ScrollBegin(
             gfx::ToCeiledPoint(expected_scroll_layer_impl->position() -
                                gfx::Vector2dF(0.5f, 0.5f)),
             InputHandler::GESTURE);
         EXPECT_EQ(InputHandler::SCROLL_STARTED, status);
         impl->ScrollBy(gfx::Point(), scroll_amount_);
+        LayerImpl* scrolling_layer = impl->CurrentlyScrollingLayer();
+        CHECK(scrolling_layer);
         impl->ScrollEnd();
+        CHECK(!impl->CurrentlyScrollingLayer());
+        EXPECT_EQ(scrolling_layer->id(),
+                  impl->active_tree()->LastScrolledLayerId());
 
         // Check the scroll is applied as a delta.
         EXPECT_VECTOR_EQ(initial_offset_,
@@ -665,84 +671,84 @@
        DeviceScaleFactor1_ScrollChild_DirectRenderer) {
   device_scale_factor_ = 1.f;
   scroll_child_layer_ = true;
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 TEST_F(LayerTreeHostScrollTestCaseWithChild,
        DeviceScaleFactor1_ScrollChild_DelegatingRenderer) {
   device_scale_factor_ = 1.f;
   scroll_child_layer_ = true;
-  RunTest(true, true);
+  RunTest(CompositorMode::Threaded, true);
 }
 
 TEST_F(LayerTreeHostScrollTestCaseWithChild,
        DeviceScaleFactor15_ScrollChild_DirectRenderer) {
   device_scale_factor_ = 1.5f;
   scroll_child_layer_ = true;
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 TEST_F(LayerTreeHostScrollTestCaseWithChild,
        DeviceScaleFactor15_ScrollChild_DelegatingRenderer) {
   device_scale_factor_ = 1.5f;
   scroll_child_layer_ = true;
-  RunTest(true, true);
+  RunTest(CompositorMode::Threaded, true);
 }
 
 TEST_F(LayerTreeHostScrollTestCaseWithChild,
        DeviceScaleFactor2_ScrollChild_DirectRenderer) {
   device_scale_factor_ = 2.f;
   scroll_child_layer_ = true;
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 TEST_F(LayerTreeHostScrollTestCaseWithChild,
        DeviceScaleFactor2_ScrollChild_DelegatingRenderer) {
   device_scale_factor_ = 2.f;
   scroll_child_layer_ = true;
-  RunTest(true, true);
+  RunTest(CompositorMode::Threaded, true);
 }
 
 TEST_F(LayerTreeHostScrollTestCaseWithChild,
        DeviceScaleFactor1_ScrollRootScrollLayer_DirectRenderer) {
   device_scale_factor_ = 1.f;
   scroll_child_layer_ = false;
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 TEST_F(LayerTreeHostScrollTestCaseWithChild,
        DeviceScaleFactor1_ScrollRootScrollLayer_DelegatingRenderer) {
   device_scale_factor_ = 1.f;
   scroll_child_layer_ = false;
-  RunTest(true, true);
+  RunTest(CompositorMode::Threaded, true);
 }
 
 TEST_F(LayerTreeHostScrollTestCaseWithChild,
        DeviceScaleFactor15_ScrollRootScrollLayer_DirectRenderer) {
   device_scale_factor_ = 1.5f;
   scroll_child_layer_ = false;
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 TEST_F(LayerTreeHostScrollTestCaseWithChild,
        DeviceScaleFactor15_ScrollRootScrollLayer_DelegatingRenderer) {
   device_scale_factor_ = 1.5f;
   scroll_child_layer_ = false;
-  RunTest(true, true);
+  RunTest(CompositorMode::Threaded, true);
 }
 
 TEST_F(LayerTreeHostScrollTestCaseWithChild,
        DeviceScaleFactor2_ScrollRootScrollLayer_DirectRenderer) {
   device_scale_factor_ = 2.f;
   scroll_child_layer_ = false;
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 TEST_F(LayerTreeHostScrollTestCaseWithChild,
        DeviceScaleFactor2_ScrollRootScrollLayer_DelegatingRenderer) {
   device_scale_factor_ = 2.f;
   scroll_child_layer_ = false;
-  RunTest(true, true);
+  RunTest(CompositorMode::Threaded, true);
 }
 
 class LayerTreeHostScrollTestSimple : public LayerTreeHostScrollTest {
@@ -1260,12 +1266,12 @@
 };
 
 TEST_F(LayerTreeHostScrollTestLayerStructureChange, ScrollDestroyLayer) {
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 TEST_F(LayerTreeHostScrollTestLayerStructureChange, ScrollDestroyWholeTree) {
   scroll_destroy_whole_tree_ = true;
-  RunTest(true, false);
+  RunTest(CompositorMode::Threaded, false);
 }
 
 }  // namespace
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 2a3f658..93e8145 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -49,10 +49,12 @@
     scoped_refptr<SyncedElasticOverscroll> elastic_overscroll)
     : layer_tree_host_impl_(layer_tree_host_impl),
       source_frame_number_(-1),
+      is_first_frame_after_commit_tracker_(-1),
       hud_layer_(0),
       background_color_(0),
       has_transparent_background_(false),
       currently_scrolling_layer_id_(Layer::INVALID_ID),
+      last_scrolled_layer_id_(Layer::INVALID_ID),
       overscroll_elasticity_layer_id_(Layer::INVALID_ID),
       page_scale_layer_id_(Layer::INVALID_ID),
       inner_viewport_scroll_layer_id_(Layer::INVALID_ID),
@@ -371,8 +373,15 @@
   return LayerById(currently_scrolling_layer_id_);
 }
 
+int LayerTreeImpl::LastScrolledLayerId() const {
+  return last_scrolled_layer_id_;
+}
+
 void LayerTreeImpl::SetCurrentlyScrollingLayer(LayerImpl* layer) {
   int new_id = layer ? layer->id() : Layer::INVALID_ID;
+  if (layer)
+    last_scrolled_layer_id_ = new_id;
+
   if (currently_scrolling_layer_id_ == new_id)
     return;
 
@@ -1307,6 +1316,19 @@
   }
 }
 
+void LayerTreeImpl::AddSurfaceLayer(LayerImpl* layer) {
+  DCHECK(std::find(surface_layers_.begin(), surface_layers_.end(), layer) ==
+         surface_layers_.end());
+  surface_layers_.push_back(layer);
+}
+
+void LayerTreeImpl::RemoveSurfaceLayer(LayerImpl* layer) {
+  std::vector<LayerImpl*>::iterator it =
+      std::find(surface_layers_.begin(), surface_layers_.end(), layer);
+  DCHECK(it != surface_layers_.end());
+  surface_layers_.erase(it);
+}
+
 const std::vector<LayerImpl*>& LayerTreeImpl::LayersWithCopyOutputRequest()
     const {
   // Only the active tree needs to know about layers with copy requests, as
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 7392585..a70351a 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -57,6 +57,9 @@
 
 class CC_EXPORT LayerTreeImpl {
  public:
+  // This is the number of times a fixed point has to be hit contiuously by a
+  // layer to consider it as jittering.
+  const int kFixedPointHitsThreshold = 3;
   static scoped_ptr<LayerTreeImpl> create(
       LayerTreeHostImpl* layer_tree_host_impl,
       scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor,
@@ -140,6 +143,15 @@
     source_frame_number_ = frame_number;
   }
 
+  bool is_first_frame_after_commit() const {
+    return source_frame_number_ != is_first_frame_after_commit_tracker_;
+  }
+
+  void set_is_first_frame_after_commit(bool is_first_frame_after_commit) {
+    is_first_frame_after_commit_tracker_ =
+        is_first_frame_after_commit ? -1 : source_frame_number_;
+  }
+
   HeadsUpDisplayLayerImpl* hud_layer() { return hud_layer_; }
   void set_hud_layer(HeadsUpDisplayLayerImpl* layer_impl) {
     hud_layer_ = layer_impl;
@@ -154,6 +166,7 @@
   LayerImpl* InnerViewportContainerLayer() const;
   LayerImpl* OuterViewportContainerLayer() const;
   LayerImpl* CurrentlyScrollingLayer() const;
+  int LastScrolledLayerId() const;
   void SetCurrentlyScrollingLayer(LayerImpl* layer);
   void ClearCurrentlyScrollingLayer();
 
@@ -334,6 +347,12 @@
   void RemoveLayerWithCopyOutputRequest(LayerImpl* layer);
   const std::vector<LayerImpl*>& LayersWithCopyOutputRequest() const;
 
+  void AddSurfaceLayer(LayerImpl* layer);
+  void RemoveSurfaceLayer(LayerImpl* layer);
+  const std::vector<LayerImpl*>& SurfaceLayers() const {
+    return surface_layers_;
+  }
+
   int current_render_surface_list_id() const {
     return render_surface_layer_list_id_;
   }
@@ -426,6 +445,7 @@
   void PushTopControls(const float* top_controls_shown_ratio);
   LayerTreeHostImpl* layer_tree_host_impl_;
   int source_frame_number_;
+  int is_first_frame_after_commit_tracker_;
   scoped_ptr<LayerImpl> root_layer_;
   HeadsUpDisplayLayerImpl* hud_layer_;
   PropertyTrees property_trees_;
@@ -433,6 +453,7 @@
   bool has_transparent_background_;
 
   int currently_scrolling_layer_id_;
+  int last_scrolled_layer_id_;
   int overscroll_elasticity_layer_id_;
   int page_scale_layer_id_;
   int inner_viewport_scroll_layer_id_;
@@ -465,6 +486,7 @@
 
   std::vector<PictureLayerImpl*> picture_layers_;
   std::vector<LayerImpl*> layers_with_copy_output_request_;
+  std::vector<LayerImpl*> surface_layers_;
 
   // List of visible layers for the most recently prepared frame.
   LayerImplList render_surface_layer_list_;
diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc
new file mode 100644
index 0000000..810e73e
--- /dev/null
+++ b/cc/trees/proxy_impl.cc
@@ -0,0 +1,684 @@
+// 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/trees/proxy_impl.h"
+
+#include <algorithm>
+#include <string>
+
+#include "base/auto_reset.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/trace_event_synthetic_delay.h"
+#include "cc/debug/benchmark_instrumentation.h"
+#include "cc/debug/devtools_instrumentation.h"
+#include "cc/input/top_controls_manager.h"
+#include "cc/output/context_provider.h"
+#include "cc/output/output_surface.h"
+#include "cc/scheduler/compositor_timing_history.h"
+#include "cc/trees/layer_tree_host.h"
+#include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/task_runner_provider.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+
+namespace cc {
+
+namespace {
+
+// Measured in seconds.
+const double kSmoothnessTakesPriorityExpirationDelay = 0.25;
+
+unsigned int nextBeginFrameId = 0;
+
+}  // namespace
+
+scoped_ptr<ProxyImpl> ProxyImpl::Create(
+    ChannelImpl* channel_impl,
+    LayerTreeHost* layer_tree_host,
+    TaskRunnerProvider* task_runner_provider,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source) {
+  return make_scoped_ptr(new ProxyImpl(channel_impl, layer_tree_host,
+                                       task_runner_provider,
+                                       std::move(external_begin_frame_source)));
+}
+
+ProxyImpl::ProxyImpl(ChannelImpl* channel_impl,
+                     LayerTreeHost* layer_tree_host,
+                     TaskRunnerProvider* task_runner_provider,
+                     scoped_ptr<BeginFrameSource> external_begin_frame_source)
+    : layer_tree_host_id_(layer_tree_host->id()),
+      next_commit_waits_for_activation_(false),
+      commit_completion_event_(nullptr),
+      next_frame_is_newly_committed_frame_(false),
+      inside_draw_(false),
+      input_throttled_until_commit_(false),
+      task_runner_provider_(task_runner_provider),
+      smoothness_priority_expiration_notifier_(
+          task_runner_provider->ImplThreadTaskRunner(),
+          base::Bind(&ProxyImpl::RenewTreePriority, base::Unretained(this)),
+          base::TimeDelta::FromSeconds(
+              kSmoothnessTakesPriorityExpirationDelay)),
+      external_begin_frame_source_(std::move(external_begin_frame_source)),
+      rendering_stats_instrumentation_(
+          layer_tree_host->rendering_stats_instrumentation()),
+      channel_impl_(channel_impl) {
+  TRACE_EVENT0("cc", "ProxyImpl::ProxyImpl");
+  DCHECK(IsImplThread());
+  DCHECK(IsMainThreadBlocked());
+
+  layer_tree_host_impl_ = layer_tree_host->CreateLayerTreeHostImpl(this);
+
+  SchedulerSettings scheduler_settings(
+      layer_tree_host->settings().ToSchedulerSettings());
+
+  scoped_ptr<CompositorTimingHistory> compositor_timing_history(
+      new CompositorTimingHistory(CompositorTimingHistory::RENDERER_UMA,
+                                  rendering_stats_instrumentation_));
+
+  scheduler_ = Scheduler::Create(this, scheduler_settings, layer_tree_host_id_,
+                                 task_runner_provider_->ImplThreadTaskRunner(),
+                                 external_begin_frame_source_.get(),
+                                 std::move(compositor_timing_history));
+
+  DCHECK_EQ(scheduler_->visible(), layer_tree_host_impl_->visible());
+}
+
+ProxyImpl::BlockedMainCommitOnly::BlockedMainCommitOnly()
+    : layer_tree_host(nullptr) {}
+
+ProxyImpl::BlockedMainCommitOnly::~BlockedMainCommitOnly() {}
+
+ProxyImpl::~ProxyImpl() {
+  TRACE_EVENT0("cc", "ProxyImpl::~ProxyImpl");
+  DCHECK(IsImplThread());
+  DCHECK(IsMainThreadBlocked());
+
+  scheduler_ = nullptr;
+  external_begin_frame_source_ = nullptr;
+  layer_tree_host_impl_ = nullptr;
+  // We need to explicitly shutdown the notifier to destroy any weakptrs it is
+  // holding while still on the compositor thread. This also ensures any
+  // callbacks holding a ProxyImpl pointer are cancelled.
+  smoothness_priority_expiration_notifier_.Shutdown();
+}
+
+void ProxyImpl::SetThrottleFrameProductionOnImpl(bool throttle) {
+  TRACE_EVENT1("cc", "ProxyImpl::SetThrottleFrameProductionOnImplThread",
+               "throttle", throttle);
+  DCHECK(IsImplThread());
+  scheduler_->SetThrottleFrameProduction(throttle);
+}
+
+void ProxyImpl::UpdateTopControlsStateOnImpl(TopControlsState constraints,
+                                             TopControlsState current,
+                                             bool animate) {
+  DCHECK(IsImplThread());
+  layer_tree_host_impl_->top_controls_manager()->UpdateTopControlsState(
+      constraints, current, animate);
+}
+
+void ProxyImpl::InitializeOutputSurfaceOnImpl(OutputSurface* output_surface) {
+  TRACE_EVENT0("cc", "ProxyImpl::InitializeOutputSurfaceOnImplThread");
+  DCHECK(IsImplThread());
+
+  LayerTreeHostImpl* host_impl = layer_tree_host_impl_.get();
+  bool success = host_impl->InitializeRenderer(output_surface);
+  RendererCapabilities capabilities;
+  if (success) {
+    capabilities =
+        host_impl->GetRendererCapabilities().MainThreadCapabilities();
+  }
+
+  channel_impl_->DidInitializeOutputSurface(success, capabilities);
+
+  if (success)
+    scheduler_->DidCreateAndInitializeOutputSurface();
+}
+
+void ProxyImpl::MainThreadHasStoppedFlingingOnImpl() {
+  DCHECK(IsImplThread());
+  layer_tree_host_impl_->MainThreadHasStoppedFlinging();
+}
+
+void ProxyImpl::SetInputThrottledUntilCommitOnImpl(bool is_throttled) {
+  DCHECK(IsImplThread());
+  if (is_throttled == input_throttled_until_commit_)
+    return;
+  input_throttled_until_commit_ = is_throttled;
+  RenewTreePriority();
+}
+
+void ProxyImpl::SetDeferCommitsOnImpl(bool defer_commits) const {
+  DCHECK(IsImplThread());
+  scheduler_->SetDeferCommits(defer_commits);
+}
+
+void ProxyImpl::SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) {
+  DCHECK(IsImplThread());
+  SetNeedsRedrawRectOnImplThread(damage_rect);
+}
+
+void ProxyImpl::SetNeedsCommitOnImpl() {
+  DCHECK(IsImplThread());
+  SetNeedsCommitOnImplThread();
+}
+
+void ProxyImpl::BeginMainFrameAbortedOnImpl(
+    CommitEarlyOutReason reason,
+    base::TimeTicks main_thread_start_time) {
+  TRACE_EVENT1("cc", "ProxyImpl::BeginMainFrameAbortedOnImplThread", "reason",
+               CommitEarlyOutReasonToString(reason));
+  DCHECK(IsImplThread());
+  DCHECK(scheduler_->CommitPending());
+  DCHECK(!layer_tree_host_impl_->pending_tree());
+
+  if (CommitEarlyOutHandledCommit(reason)) {
+    SetInputThrottledUntilCommitOnImpl(false);
+    last_processed_begin_main_frame_args_ = last_begin_main_frame_args_;
+  }
+  layer_tree_host_impl_->BeginMainFrameAborted(reason);
+  scheduler_->NotifyBeginMainFrameStarted(main_thread_start_time);
+  scheduler_->BeginMainFrameAborted(reason);
+}
+
+void ProxyImpl::FinishAllRenderingOnImpl(CompletionEvent* completion) {
+  TRACE_EVENT0("cc", "ProxyImpl::FinishAllRenderingOnImplThread");
+  DCHECK(IsImplThread());
+  layer_tree_host_impl_->FinishAllRendering();
+  completion->Signal();
+}
+
+void ProxyImpl::SetVisibleOnImpl(bool visible) {
+  TRACE_EVENT1("cc", "ProxyImpl::SetVisibleOnImplThread", "visible", visible);
+  DCHECK(IsImplThread());
+  layer_tree_host_impl_->SetVisible(visible);
+  scheduler_->SetVisible(visible);
+}
+
+void ProxyImpl::ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) {
+  DCHECK(IsImplThread());
+
+  // Unlike DidLoseOutputSurfaceOnImplThread, we don't need to call
+  // LayerTreeHost::DidLoseOutputSurface since it already knows.
+  scheduler_->DidLoseOutputSurface();
+  layer_tree_host_impl_->ReleaseOutputSurface();
+  completion->Signal();
+}
+
+void ProxyImpl::FinishGLOnImpl(CompletionEvent* completion) {
+  TRACE_EVENT0("cc", "ProxyImpl::FinishGLOnImplThread");
+  DCHECK(IsImplThread());
+  if (layer_tree_host_impl_->output_surface()) {
+    ContextProvider* context_provider =
+        layer_tree_host_impl_->output_surface()->context_provider();
+    if (context_provider)
+      context_provider->ContextGL()->Finish();
+  }
+  completion->Signal();
+}
+
+void ProxyImpl::MainFrameWillHappenOnImplForTesting(
+    CompletionEvent* completion,
+    bool* main_frame_will_happen) {
+  DCHECK(IsImplThread());
+  if (layer_tree_host_impl_->output_surface()) {
+    *main_frame_will_happen = scheduler_->MainFrameForTestingWillHappen();
+  } else {
+    *main_frame_will_happen = false;
+  }
+  completion->Signal();
+}
+
+void ProxyImpl::StartCommitOnImpl(CompletionEvent* completion,
+                                  LayerTreeHost* layer_tree_host,
+                                  base::TimeTicks main_thread_start_time,
+                                  bool hold_commit_for_activation) {
+  TRACE_EVENT0("cc", "ProxyImpl::StartCommitOnImplThread");
+  DCHECK(!commit_completion_event_);
+  DCHECK(IsImplThread() && IsMainThreadBlocked());
+  DCHECK(scheduler_);
+  DCHECK(scheduler_->CommitPending());
+
+  if (hold_commit_for_activation) {
+    // This commit may be aborted. Store the value for
+    // hold_commit_for_activation so that whenever the next commit is started,
+    // the main thread will be unblocked only after pending tree activation.
+    next_commit_waits_for_activation_ = hold_commit_for_activation;
+  }
+
+  if (!layer_tree_host_impl_) {
+    TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoLayerTree",
+                         TRACE_EVENT_SCOPE_THREAD);
+    completion->Signal();
+    return;
+  }
+
+  // Ideally, we should inform to impl thread when BeginMainFrame is started.
+  // But, we can avoid a PostTask in here.
+  scheduler_->NotifyBeginMainFrameStarted(main_thread_start_time);
+  commit_completion_event_ = completion;
+  DCHECK(!blocked_main_commit().layer_tree_host);
+  blocked_main_commit().layer_tree_host = layer_tree_host;
+  scheduler_->NotifyReadyToCommit();
+}
+
+void ProxyImpl::UpdateRendererCapabilitiesOnImplThread() {
+  DCHECK(IsImplThread());
+  channel_impl_->SetRendererCapabilitiesMainCopy(
+      layer_tree_host_impl_->GetRendererCapabilities()
+          .MainThreadCapabilities());
+}
+
+void ProxyImpl::DidLoseOutputSurfaceOnImplThread() {
+  TRACE_EVENT0("cc", "ProxyImpl::DidLoseOutputSurfaceOnImplThread");
+  DCHECK(IsImplThread());
+  channel_impl_->DidLoseOutputSurface();
+  scheduler_->DidLoseOutputSurface();
+}
+
+void ProxyImpl::CommitVSyncParameters(base::TimeTicks timebase,
+                                      base::TimeDelta interval) {
+  DCHECK(IsImplThread());
+  scheduler_->CommitVSyncParameters(timebase, interval);
+}
+
+void ProxyImpl::SetEstimatedParentDrawTime(base::TimeDelta draw_time) {
+  DCHECK(IsImplThread());
+  scheduler_->SetEstimatedParentDrawTime(draw_time);
+}
+
+void ProxyImpl::DidSwapBuffersOnImplThread() {
+  DCHECK(IsImplThread());
+  scheduler_->DidSwapBuffers();
+}
+
+void ProxyImpl::DidSwapBuffersCompleteOnImplThread() {
+  TRACE_EVENT0("cc,benchmark", "ProxyImpl::DidSwapBuffersCompleteOnImplThread");
+  DCHECK(IsImplThread());
+  scheduler_->DidSwapBuffersComplete();
+  channel_impl_->DidCompleteSwapBuffers();
+}
+
+void ProxyImpl::OnResourcelessSoftareDrawStateChanged(bool resourceless_draw) {
+  DCHECK(IsImplThread());
+  scheduler_->SetResourcelessSoftareDraw(resourceless_draw);
+}
+
+void ProxyImpl::OnCanDrawStateChanged(bool can_draw) {
+  TRACE_EVENT1("cc", "ProxyImpl::OnCanDrawStateChanged", "can_draw", can_draw);
+  DCHECK(IsImplThread());
+  scheduler_->SetCanDraw(can_draw);
+}
+
+void ProxyImpl::NotifyReadyToActivate() {
+  TRACE_EVENT0("cc", "ProxyImpl::NotifyReadyToActivate");
+  DCHECK(IsImplThread());
+  scheduler_->NotifyReadyToActivate();
+}
+
+void ProxyImpl::NotifyReadyToDraw() {
+  TRACE_EVENT0("cc", "ProxyImpl::NotifyReadyToDraw");
+  DCHECK(IsImplThread());
+  scheduler_->NotifyReadyToDraw();
+}
+
+void ProxyImpl::SetNeedsRedrawOnImplThread() {
+  TRACE_EVENT0("cc", "ProxyImpl::SetNeedsRedrawOnImplThread");
+  DCHECK(IsImplThread());
+  scheduler_->SetNeedsRedraw();
+}
+
+void ProxyImpl::SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) {
+  DCHECK(IsImplThread());
+  layer_tree_host_impl_->SetViewportDamage(damage_rect);
+  SetNeedsRedrawOnImplThread();
+}
+
+void ProxyImpl::SetNeedsOneBeginImplFrameOnImplThread() {
+  TRACE_EVENT0("cc", "ProxyImpl::SetNeedsOneBeginImplFrameOnImplThread");
+  DCHECK(IsImplThread());
+  scheduler_->SetNeedsOneBeginImplFrame();
+}
+
+void ProxyImpl::SetNeedsPrepareTilesOnImplThread() {
+  DCHECK(IsImplThread());
+  scheduler_->SetNeedsPrepareTiles();
+}
+
+void ProxyImpl::SetNeedsCommitOnImplThread() {
+  TRACE_EVENT0("cc", "ProxyImpl::SetNeedsCommitOnImplThread");
+  DCHECK(IsImplThread());
+  scheduler_->SetNeedsBeginMainFrame();
+}
+
+void ProxyImpl::SetVideoNeedsBeginFrames(bool needs_begin_frames) {
+  TRACE_EVENT1("cc", "ProxyImpl::SetVideoNeedsBeginFrames",
+               "needs_begin_frames", needs_begin_frames);
+  DCHECK(IsImplThread());
+  // In tests the layer tree is destroyed after the scheduler is.
+  if (scheduler_)
+    scheduler_->SetVideoNeedsBeginFrames(needs_begin_frames);
+}
+
+void ProxyImpl::PostAnimationEventsToMainThreadOnImplThread(
+    scoped_ptr<AnimationEventsVector> events) {
+  TRACE_EVENT0("cc", "ProxyImpl::PostAnimationEventsToMainThreadOnImplThread");
+  DCHECK(IsImplThread());
+  channel_impl_->SetAnimationEvents(std::move(events));
+}
+
+bool ProxyImpl::IsInsideDraw() {
+  return inside_draw_;
+}
+
+void ProxyImpl::RenewTreePriority() {
+  DCHECK(IsImplThread());
+  bool smoothness_takes_priority =
+      layer_tree_host_impl_->pinch_gesture_active() ||
+      layer_tree_host_impl_->page_scale_animation_active() ||
+      layer_tree_host_impl_->IsActivelyScrolling();
+
+  // Schedule expiration if smoothness currently takes priority.
+  if (smoothness_takes_priority)
+    smoothness_priority_expiration_notifier_.Schedule();
+
+  // We use the same priority for both trees by default.
+  TreePriority tree_priority = SAME_PRIORITY_FOR_BOTH_TREES;
+
+  // Smoothness takes priority if we have an expiration for it scheduled.
+  if (smoothness_priority_expiration_notifier_.HasPendingNotification())
+    tree_priority = SMOOTHNESS_TAKES_PRIORITY;
+
+  // New content always takes priority when there is an invalid viewport size or
+  // ui resources have been evicted.
+  if (layer_tree_host_impl_->active_tree()->ViewportSizeInvalid() ||
+      layer_tree_host_impl_->EvictedUIResourcesExist() ||
+      input_throttled_until_commit_) {
+    // Once we enter NEW_CONTENTS_TAKES_PRIORITY mode, visible tiles on active
+    // tree might be freed. We need to set RequiresHighResToDraw to ensure that
+    // high res tiles will be required to activate pending tree.
+    layer_tree_host_impl_->SetRequiresHighResToDraw();
+    tree_priority = NEW_CONTENT_TAKES_PRIORITY;
+  }
+
+  layer_tree_host_impl_->SetTreePriority(tree_priority);
+
+  // Only put the scheduler in impl latency prioritization mode if we don't
+  // have a scroll listener. This gives the scroll listener a better chance of
+  // handling scroll updates within the same frame. The tree itself is still
+  // kept in prefer smoothness mode to allow checkerboarding.
+  ScrollHandlerState scroll_handler_state =
+      layer_tree_host_impl_->scroll_affects_scroll_handler()
+          ? ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER
+          : ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER;
+  scheduler_->SetTreePrioritiesAndScrollState(tree_priority,
+                                              scroll_handler_state);
+
+  // Notify the the client of this compositor via the output surface.
+  // TODO(epenner): Route this to compositor-thread instead of output-surface
+  // after GTFO refactor of compositor-thread (http://crbug/170828).
+  if (layer_tree_host_impl_->output_surface()) {
+    layer_tree_host_impl_->output_surface()->UpdateSmoothnessTakesPriority(
+        tree_priority == SMOOTHNESS_TAKES_PRIORITY);
+  }
+}
+
+void ProxyImpl::PostDelayedAnimationTaskOnImplThread(const base::Closure& task,
+                                                     base::TimeDelta delay) {
+  DCHECK(IsImplThread());
+  task_runner_provider_->ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE,
+                                                                 task, delay);
+}
+
+void ProxyImpl::DidActivateSyncTree() {
+  TRACE_EVENT0("cc", "ProxyImpl::DidActivateSyncTreeOnImplThread");
+  DCHECK(IsImplThread());
+
+  if (next_commit_waits_for_activation_) {
+    TRACE_EVENT_INSTANT0("cc", "ReleaseCommitbyActivation",
+                         TRACE_EVENT_SCOPE_THREAD);
+    DCHECK(commit_completion_event_);
+    commit_completion_event_->Signal();
+    commit_completion_event_ = nullptr;
+    next_commit_waits_for_activation_ = false;
+  }
+
+  last_processed_begin_main_frame_args_ = last_begin_main_frame_args_;
+}
+
+void ProxyImpl::WillPrepareTiles() {
+  DCHECK(IsImplThread());
+  scheduler_->WillPrepareTiles();
+}
+
+void ProxyImpl::DidPrepareTiles() {
+  DCHECK(IsImplThread());
+  scheduler_->DidPrepareTiles();
+}
+
+void ProxyImpl::DidCompletePageScaleAnimationOnImplThread() {
+  DCHECK(IsImplThread());
+  channel_impl_->DidCompletePageScaleAnimation();
+}
+
+void ProxyImpl::OnDrawForOutputSurface() {
+  DCHECK(IsImplThread());
+  scheduler_->OnDrawForOutputSurface();
+}
+
+void ProxyImpl::PostFrameTimingEventsOnImplThread(
+    scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+    scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) {
+  DCHECK(IsImplThread());
+  channel_impl_->PostFrameTimingEventsOnMain(std::move(composite_events),
+                                             std::move(main_frame_events));
+}
+
+void ProxyImpl::WillBeginImplFrame(const BeginFrameArgs& args) {
+  DCHECK(IsImplThread());
+  layer_tree_host_impl_->WillBeginImplFrame(args);
+  if (last_processed_begin_main_frame_args_.IsValid()) {
+    // Last processed begin main frame args records the frame args that we sent
+    // to the main thread for the last frame that we've processed. If that is
+    // set, that means the current frame is one past the frame in which we've
+    // finished the processing.
+    layer_tree_host_impl_->RecordMainFrameTiming(
+        last_processed_begin_main_frame_args_, args);
+    last_processed_begin_main_frame_args_ = BeginFrameArgs();
+  }
+}
+
+void ProxyImpl::DidFinishImplFrame() {
+  DCHECK(IsImplThread());
+  layer_tree_host_impl_->DidFinishImplFrame();
+}
+
+void ProxyImpl::ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) {
+  DCHECK(IsImplThread());
+  unsigned int begin_frame_id = nextBeginFrameId++;
+  benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task(
+      benchmark_instrumentation::kSendBeginFrame, begin_frame_id);
+  scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state(
+      new BeginMainFrameAndCommitState);
+  begin_main_frame_state->begin_frame_id = begin_frame_id;
+  begin_main_frame_state->begin_frame_args = args;
+  begin_main_frame_state->scroll_info =
+      layer_tree_host_impl_->ProcessScrollDeltas();
+  begin_main_frame_state->memory_allocation_limit_bytes =
+      layer_tree_host_impl_->memory_allocation_limit_bytes();
+  begin_main_frame_state->evicted_ui_resources =
+      layer_tree_host_impl_->EvictedUIResourcesExist();
+  // TODO(vmpstr): This needs to be fixed if
+  // main_frame_before_activation_enabled is set, since we might run this code
+  // twice before recording a duration. crbug.com/469824
+  last_begin_main_frame_args_ = begin_main_frame_state->begin_frame_args;
+  channel_impl_->BeginMainFrame(std::move(begin_main_frame_state));
+  devtools_instrumentation::DidRequestMainThreadFrame(layer_tree_host_id_);
+}
+
+DrawResult ProxyImpl::ScheduledActionDrawAndSwapIfPossible() {
+  TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionDrawAndSwap");
+  DCHECK(IsImplThread());
+
+  // SchedulerStateMachine::DidDrawIfPossibleCompleted isn't set up to
+  // handle DRAW_ABORTED_CANT_DRAW.  Moreover, the scheduler should
+  // never generate this call when it can't draw.
+  DCHECK(layer_tree_host_impl_->CanDraw());
+
+  bool forced_draw = false;
+  return DrawAndSwapInternal(forced_draw);
+}
+
+DrawResult ProxyImpl::ScheduledActionDrawAndSwapForced() {
+  TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionDrawAndSwapForced");
+  DCHECK(IsImplThread());
+  bool forced_draw = true;
+  return DrawAndSwapInternal(forced_draw);
+}
+
+void ProxyImpl::ScheduledActionCommit() {
+  TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionCommit");
+  DCHECK(IsImplThread());
+  DCHECK(IsMainThreadBlocked());
+  DCHECK(commit_completion_event_);
+
+  layer_tree_host_impl_->BeginCommit();
+  blocked_main_commit().layer_tree_host->FinishCommitOnImplThread(
+      layer_tree_host_impl_.get());
+
+  // Remove the LayerTreeHost reference before the completion event is signaled
+  // and cleared. This is necessary since blocked_main_commit() allows access
+  // only while we have the completion event to ensure the main thread is
+  // blocked for a commit.
+  blocked_main_commit().layer_tree_host = nullptr;
+
+  if (next_commit_waits_for_activation_) {
+    // For some layer types in impl-side painting, the commit is held until
+    // the sync tree is activated.  It's also possible that the
+    // sync tree has already activated if there was no work to be done.
+    TRACE_EVENT_INSTANT0("cc", "HoldCommit", TRACE_EVENT_SCOPE_THREAD);
+  } else {
+    commit_completion_event_->Signal();
+    commit_completion_event_ = nullptr;
+  }
+
+  scheduler_->DidCommit();
+
+  // Delay this step until afer the main thread has been released as it's
+  // often a good bit of work to update the tree and prepare the new frame.
+  layer_tree_host_impl_->CommitComplete();
+
+  SetInputThrottledUntilCommitOnImpl(false);
+
+  next_frame_is_newly_committed_frame_ = true;
+}
+
+void ProxyImpl::ScheduledActionActivateSyncTree() {
+  TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionActivateSyncTree");
+  DCHECK(IsImplThread());
+  layer_tree_host_impl_->ActivateSyncTree();
+}
+
+void ProxyImpl::ScheduledActionBeginOutputSurfaceCreation() {
+  TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionBeginOutputSurfaceCreation");
+  DCHECK(IsImplThread());
+  channel_impl_->RequestNewOutputSurface();
+}
+
+void ProxyImpl::ScheduledActionPrepareTiles() {
+  TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionPrepareTiles");
+  DCHECK(IsImplThread());
+  layer_tree_host_impl_->PrepareTiles();
+}
+
+void ProxyImpl::ScheduledActionInvalidateOutputSurface() {
+  TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionInvalidateOutputSurface");
+  DCHECK(IsImplThread());
+  DCHECK(layer_tree_host_impl_->output_surface());
+  layer_tree_host_impl_->output_surface()->Invalidate();
+}
+
+void ProxyImpl::SendBeginFramesToChildren(const BeginFrameArgs& args) {
+  NOTREACHED() << "Only used by SingleThreadProxy";
+}
+
+void ProxyImpl::SendBeginMainFrameNotExpectedSoon() {
+  DCHECK(IsImplThread());
+  channel_impl_->BeginMainFrameNotExpectedSoon();
+}
+
+DrawResult ProxyImpl::DrawAndSwapInternal(bool forced_draw) {
+  TRACE_EVENT_SYNTHETIC_DELAY("cc.DrawAndSwap");
+
+  DCHECK(IsImplThread());
+  DCHECK(layer_tree_host_impl_.get());
+
+  base::AutoReset<bool> mark_inside(&inside_draw_, true);
+
+  if (layer_tree_host_impl_->pending_tree()) {
+    bool update_lcd_text = false;
+    layer_tree_host_impl_->pending_tree()->UpdateDrawProperties(
+        update_lcd_text);
+  }
+
+  // This method is called on a forced draw, regardless of whether we are able
+  // to produce a frame, as the calling site on main thread is blocked until its
+  // request completes, and we signal completion here. If CanDraw() is false, we
+  // will indicate success=false to the caller, but we must still signal
+  // completion to avoid deadlock.
+
+  // We guard PrepareToDraw() with CanDraw() because it always returns a valid
+  // frame, so can only be used when such a frame is possible. Since
+  // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
+  // CanDraw() as well.
+
+  LayerTreeHostImpl::FrameData frame;
+  bool draw_frame = false;
+
+  DrawResult result;
+  if (layer_tree_host_impl_->CanDraw()) {
+    result = layer_tree_host_impl_->PrepareToDraw(&frame);
+    draw_frame = forced_draw || result == DRAW_SUCCESS;
+  } else {
+    result = DRAW_ABORTED_CANT_DRAW;
+  }
+
+  if (draw_frame) {
+    layer_tree_host_impl_->DrawLayers(&frame);
+    result = DRAW_SUCCESS;
+  } else {
+    DCHECK_NE(DRAW_SUCCESS, result);
+  }
+  layer_tree_host_impl_->DidDrawAllLayers(frame);
+
+  bool start_ready_animations = draw_frame;
+  layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
+
+  if (draw_frame)
+    layer_tree_host_impl_->SwapBuffers(frame);
+
+  // Tell the main thread that the the newly-commited frame was drawn.
+  if (next_frame_is_newly_committed_frame_) {
+    next_frame_is_newly_committed_frame_ = false;
+    channel_impl_->DidCommitAndDrawFrame();
+  }
+
+  DCHECK_NE(INVALID_RESULT, result);
+  return result;
+}
+
+bool ProxyImpl::IsImplThread() const {
+  return task_runner_provider_->IsImplThread();
+}
+
+bool ProxyImpl::IsMainThreadBlocked() const {
+  return task_runner_provider_->IsMainThreadBlocked();
+}
+
+ProxyImpl::BlockedMainCommitOnly& ProxyImpl::blocked_main_commit() {
+  DCHECK(IsMainThreadBlocked() && commit_completion_event_);
+  return main_thread_blocked_commit_vars_unsafe_;
+}
+
+}  // namespace cc
diff --git a/cc/trees/proxy_impl.h b/cc/trees/proxy_impl.h
index 4b0cdaa..092385b5 100644
--- a/cc/trees/proxy_impl.h
+++ b/cc/trees/proxy_impl.h
@@ -5,59 +5,171 @@
 #ifndef CC_TREES_PROXY_IMPL_H_
 #define CC_TREES_PROXY_IMPL_H_
 
-#include "base/memory/weak_ptr.h"
-#include "cc/base/cc_export.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 #include "cc/base/completion_event.h"
+#include "cc/base/delayed_unique_notifier.h"
 #include "cc/input/top_controls_state.h"
-#include "cc/output/output_surface.h"
-#include "cc/scheduler/commit_earlyout_reason.h"
-#include "cc/trees/proxy_common.h"
+#include "cc/scheduler/scheduler.h"
+#include "cc/trees/channel_impl.h"
+#include "cc/trees/layer_tree_host_impl.h"
 
 namespace cc {
-// TODO(khushalsagar): The impl side of ThreadProxy. It is currently defined as
-// an interface with the implementation provided by ThreadProxy and will be
-// made an independent class.
-// The methods added to this interface should only use the CompositorThreadOnly
-// variables from ThreadProxy.
-// See crbug/527200
-class CC_EXPORT ProxyImpl {
- private:
-  friend class ThreadedChannel;
 
-  // Callback for impl side commands received from the channel.
-  virtual void SetThrottleFrameProductionOnImpl(bool throttle) = 0;
+// This class aggregates all the interactions that the main side of the
+// compositor needs to have with the impl side. It is created and owned by the
+// ChannelImpl implementation. The class lives entirely on the impl thread.
+class CC_EXPORT ProxyImpl : public NON_EXPORTED_BASE(LayerTreeHostImplClient),
+                            public NON_EXPORTED_BASE(SchedulerClient) {
+ public:
+  static scoped_ptr<ProxyImpl> Create(
+      ChannelImpl* channel_impl,
+      LayerTreeHost* layer_tree_host,
+      TaskRunnerProvider* task_runner_provider,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source);
+
+  ~ProxyImpl() override;
+
+  // Virtual for testing.
+  virtual void SetThrottleFrameProductionOnImpl(bool throttle);
   virtual void UpdateTopControlsStateOnImpl(TopControlsState constraints,
                                             TopControlsState current,
-                                            bool animate) = 0;
-  virtual void InitializeOutputSurfaceOnImpl(OutputSurface* output_surface) = 0;
-  virtual void MainThreadHasStoppedFlingingOnImpl() = 0;
-  virtual void SetInputThrottledUntilCommitOnImpl(bool is_throttled) = 0;
-  virtual void SetDeferCommitsOnImpl(bool defer_commits) const = 0;
-  virtual void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) = 0;
-  virtual void SetNeedsCommitOnImpl() = 0;
-  virtual void FinishAllRenderingOnImpl(CompletionEvent* completion) = 0;
-  virtual void SetVisibleOnImpl(bool visible) = 0;
-  virtual void ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) = 0;
-  virtual void FinishGLOnImpl(CompletionEvent* completion) = 0;
-  virtual void MainFrameWillHappenOnImplForTesting(
-      CompletionEvent* completion,
-      bool* main_frame_will_happen) = 0;
+                                            bool animate);
+  virtual void InitializeOutputSurfaceOnImpl(OutputSurface* output_surface);
+  virtual void MainThreadHasStoppedFlingingOnImpl();
+  virtual void SetInputThrottledUntilCommitOnImpl(bool is_throttled);
+  virtual void SetDeferCommitsOnImpl(bool defer_commits) const;
+  virtual void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect);
+  virtual void SetNeedsCommitOnImpl();
   virtual void BeginMainFrameAbortedOnImpl(
       CommitEarlyOutReason reason,
-      base::TimeTicks main_thread_start_time) = 0;
+      base::TimeTicks main_thread_start_time);
+  virtual void FinishAllRenderingOnImpl(CompletionEvent* completion);
+  virtual void SetVisibleOnImpl(bool visible);
+  virtual void ReleaseOutputSurfaceOnImpl(CompletionEvent* completion);
+  virtual void FinishGLOnImpl(CompletionEvent* completion);
+  virtual void MainFrameWillHappenOnImplForTesting(
+      CompletionEvent* completion,
+      bool* main_frame_will_happen);
   virtual void StartCommitOnImpl(CompletionEvent* completion,
                                  LayerTreeHost* layer_tree_host,
                                  base::TimeTicks main_thread_start_time,
-                                 bool hold_commit_for_activation) = 0;
-  virtual void InitializeImplOnImpl(CompletionEvent* completion,
-                                    LayerTreeHost* layer_tree_host) = 0;
-  virtual void LayerTreeHostClosedOnImpl(CompletionEvent* completion) = 0;
-
-  // TODO(khushalsagar): Rename as GetWeakPtr() once ThreadProxy is split.
-  virtual base::WeakPtr<ProxyImpl> GetImplWeakPtr() = 0;
+                                 bool hold_commit_for_activation);
 
  protected:
-  virtual ~ProxyImpl() {}
+  // protected for testing.
+  ProxyImpl(ChannelImpl* channel_impl,
+            LayerTreeHost* layer_tree_host,
+            TaskRunnerProvider* task_runner_provider,
+            scoped_ptr<BeginFrameSource> external_begin_frame_source);
+
+ private:
+  // The members of this struct should be accessed on the impl thread only when
+  // the main thread is blocked for a commit.
+  struct BlockedMainCommitOnly {
+    BlockedMainCommitOnly();
+    ~BlockedMainCommitOnly();
+    LayerTreeHost* layer_tree_host;
+  };
+
+  friend class ProxyImplForTest;
+
+  // LayerTreeHostImplClient implementation
+  void UpdateRendererCapabilitiesOnImplThread() override;
+  void DidLoseOutputSurfaceOnImplThread() override;
+  void CommitVSyncParameters(base::TimeTicks timebase,
+                             base::TimeDelta interval) override;
+  void SetEstimatedParentDrawTime(base::TimeDelta draw_time) override;
+  void DidSwapBuffersOnImplThread() override;
+  void DidSwapBuffersCompleteOnImplThread() override;
+  void OnResourcelessSoftareDrawStateChanged(bool resourceless_draw) override;
+  void OnCanDrawStateChanged(bool can_draw) override;
+  void NotifyReadyToActivate() override;
+  void NotifyReadyToDraw() override;
+  // Please call these 3 functions through
+  // LayerTreeHostImpl's SetNeedsRedraw(), SetNeedsRedrawRect() and
+  // SetNeedsOneBeginImplFrame().
+  void SetNeedsRedrawOnImplThread() override;
+  void SetNeedsRedrawRectOnImplThread(const gfx::Rect& dirty_rect) override;
+  void SetNeedsOneBeginImplFrameOnImplThread() override;
+  void SetNeedsPrepareTilesOnImplThread() override;
+  void SetNeedsCommitOnImplThread() override;
+  void SetVideoNeedsBeginFrames(bool needs_begin_frames) override;
+  void PostAnimationEventsToMainThreadOnImplThread(
+      scoped_ptr<AnimationEventsVector> queue) override;
+  bool IsInsideDraw() override;
+  void RenewTreePriority() override;
+  void PostDelayedAnimationTaskOnImplThread(const base::Closure& task,
+                                            base::TimeDelta delay) override;
+  void DidActivateSyncTree() override;
+  void WillPrepareTiles() override;
+  void DidPrepareTiles() override;
+  void DidCompletePageScaleAnimationOnImplThread() override;
+  void OnDrawForOutputSurface() override;
+  // This should only be called by LayerTreeHostImpl::PostFrameTimingEvents.
+  void PostFrameTimingEventsOnImplThread(
+      scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events)
+      override;
+
+  // SchedulerClient implementation
+  void WillBeginImplFrame(const BeginFrameArgs& args) override;
+  void DidFinishImplFrame() override;
+  void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override;
+  DrawResult ScheduledActionDrawAndSwapIfPossible() override;
+  DrawResult ScheduledActionDrawAndSwapForced() override;
+  void ScheduledActionCommit() override;
+  void ScheduledActionActivateSyncTree() override;
+  void ScheduledActionBeginOutputSurfaceCreation() override;
+  void ScheduledActionPrepareTiles() override;
+  void ScheduledActionInvalidateOutputSurface() override;
+  void SendBeginFramesToChildren(const BeginFrameArgs& args) override;
+  void SendBeginMainFrameNotExpectedSoon() override;
+
+  DrawResult DrawAndSwapInternal(bool forced_draw);
+
+  bool IsImplThread() const;
+  bool IsMainThreadBlocked() const;
+
+  const int layer_tree_host_id_;
+
+  scoped_ptr<Scheduler> scheduler_;
+
+  // Set when the main thread is waiting on a pending tree activation.
+  bool next_commit_waits_for_activation_;
+
+  // Set when the main thread is waiting on a commit to complete or on a
+  // pending tree activation.
+  CompletionEvent* commit_completion_event_;
+
+  // Set when the next draw should post DidCommitAndDrawFrame to the main
+  // thread.
+  bool next_frame_is_newly_committed_frame_;
+
+  bool inside_draw_;
+  bool input_throttled_until_commit_;
+
+  TaskRunnerProvider* task_runner_provider_;
+
+  DelayedUniqueNotifier smoothness_priority_expiration_notifier_;
+
+  scoped_ptr<BeginFrameSource> external_begin_frame_source_;
+
+  RenderingStatsInstrumentation* rendering_stats_instrumentation_;
+
+  // Values used to keep track of frame durations. Used only in frame timing.
+  BeginFrameArgs last_begin_main_frame_args_;
+  BeginFrameArgs last_processed_begin_main_frame_args_;
+
+  scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl_;
+
+  ChannelImpl* channel_impl_;
+
+  // Use accessors instead of this variable directly.
+  BlockedMainCommitOnly main_thread_blocked_commit_vars_unsafe_;
+  BlockedMainCommitOnly& blocked_main_commit();
+
+  DISALLOW_COPY_AND_ASSIGN(ProxyImpl);
 };
 
 }  // namespace cc
diff --git a/cc/trees/proxy_main.cc b/cc/trees/proxy_main.cc
new file mode 100644
index 0000000..dd5ac1a
--- /dev/null
+++ b/cc/trees/proxy_main.cc
@@ -0,0 +1,465 @@
+// 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/trees/proxy_main.h"
+
+#include <algorithm>
+#include <string>
+
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/trace_event_synthetic_delay.h"
+#include "cc/debug/benchmark_instrumentation.h"
+#include "cc/debug/devtools_instrumentation.h"
+#include "cc/output/output_surface.h"
+#include "cc/output/swap_promise.h"
+#include "cc/trees/blocking_task_runner.h"
+#include "cc/trees/layer_tree_host.h"
+#include "cc/trees/scoped_abort_remaining_swap_promises.h"
+#include "cc/trees/threaded_channel.h"
+
+namespace cc {
+
+scoped_ptr<ProxyMain> ProxyMain::CreateThreaded(
+    LayerTreeHost* layer_tree_host,
+    TaskRunnerProvider* task_runner_provider,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source) {
+  scoped_ptr<ProxyMain> proxy_main(
+      new ProxyMain(layer_tree_host, task_runner_provider,
+                    std::move(external_begin_frame_source)));
+  proxy_main->SetChannel(
+      ThreadedChannel::Create(proxy_main.get(), task_runner_provider));
+  return proxy_main;
+}
+
+ProxyMain::ProxyMain(LayerTreeHost* layer_tree_host,
+                     TaskRunnerProvider* task_runner_provider,
+                     scoped_ptr<BeginFrameSource> external_begin_frame_source)
+    : layer_tree_host_(layer_tree_host),
+      task_runner_provider_(task_runner_provider),
+      layer_tree_host_id_(layer_tree_host->id()),
+      max_requested_pipeline_stage_(NO_PIPELINE_STAGE),
+      current_pipeline_stage_(NO_PIPELINE_STAGE),
+      final_pipeline_stage_(NO_PIPELINE_STAGE),
+      commit_waits_for_activation_(false),
+      started_(false),
+      defer_commits_(false),
+      external_begin_frame_source_(std::move(external_begin_frame_source)) {
+  TRACE_EVENT0("cc", "ProxyMain::ProxyMain");
+  DCHECK(task_runner_provider_);
+  DCHECK(IsMainThread());
+  DCHECK(!layer_tree_host_->settings().use_external_begin_frame_source ||
+         external_begin_frame_source_);
+}
+
+ProxyMain::~ProxyMain() {
+  TRACE_EVENT0("cc", "ProxyMain::~ProxyMain");
+  DCHECK(IsMainThread());
+  DCHECK(!started_);
+}
+
+void ProxyMain::SetChannel(scoped_ptr<ChannelMain> channel_main) {
+  DCHECK(!channel_main_);
+  channel_main_ = std::move(channel_main);
+}
+
+void ProxyMain::DidCompleteSwapBuffers() {
+  DCHECK(IsMainThread());
+  layer_tree_host_->DidCompleteSwapBuffers();
+}
+
+void ProxyMain::SetRendererCapabilities(
+    const RendererCapabilities& capabilities) {
+  DCHECK(IsMainThread());
+  renderer_capabilities_ = capabilities;
+}
+
+void ProxyMain::BeginMainFrameNotExpectedSoon() {
+  TRACE_EVENT0("cc", "ProxyMain::BeginMainFrameNotExpectedSoon");
+  DCHECK(IsMainThread());
+  layer_tree_host_->BeginMainFrameNotExpectedSoon();
+}
+
+void ProxyMain::DidCommitAndDrawFrame() {
+  DCHECK(IsMainThread());
+  layer_tree_host_->DidCommitAndDrawFrame();
+}
+
+void ProxyMain::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events) {
+  TRACE_EVENT0("cc", "ProxyMain::SetAnimationEvents");
+  DCHECK(IsMainThread());
+  layer_tree_host_->SetAnimationEvents(std::move(events));
+}
+
+void ProxyMain::DidLoseOutputSurface() {
+  TRACE_EVENT0("cc", "ProxyMain::DidLoseOutputSurface");
+  DCHECK(IsMainThread());
+  layer_tree_host_->DidLoseOutputSurface();
+}
+
+void ProxyMain::RequestNewOutputSurface() {
+  DCHECK(IsMainThread());
+  layer_tree_host_->RequestNewOutputSurface();
+}
+
+void ProxyMain::DidInitializeOutputSurface(
+    bool success,
+    const RendererCapabilities& capabilities) {
+  TRACE_EVENT0("cc", "ProxyMain::DidInitializeOutputSurface");
+  DCHECK(IsMainThread());
+
+  if (!success) {
+    layer_tree_host_->DidFailToInitializeOutputSurface();
+    return;
+  }
+  renderer_capabilities_ = capabilities;
+  layer_tree_host_->DidInitializeOutputSurface();
+}
+
+void ProxyMain::DidCompletePageScaleAnimation() {
+  DCHECK(IsMainThread());
+  layer_tree_host_->DidCompletePageScaleAnimation();
+}
+
+void ProxyMain::PostFrameTimingEventsOnMain(
+    scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+    scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) {
+  DCHECK(IsMainThread());
+  layer_tree_host_->RecordFrameTimingEvents(std::move(composite_events),
+                                            std::move(main_frame_events));
+}
+
+void ProxyMain::BeginMainFrame(
+    scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) {
+  benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task(
+      benchmark_instrumentation::kDoBeginFrame,
+      begin_main_frame_state->begin_frame_id);
+
+  base::TimeTicks begin_main_frame_start_time = base::TimeTicks::Now();
+
+  TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("cc.BeginMainFrame");
+  DCHECK(IsMainThread());
+  DCHECK_EQ(NO_PIPELINE_STAGE, current_pipeline_stage_);
+
+  if (defer_commits_) {
+    TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit",
+                         TRACE_EVENT_SCOPE_THREAD);
+    channel_main_->BeginMainFrameAbortedOnImpl(
+        CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT,
+        begin_main_frame_start_time);
+    return;
+  }
+
+  // If the commit finishes, LayerTreeHost will transfer its swap promises to
+  // LayerTreeImpl. The destructor of ScopedSwapPromiseChecker aborts the
+  // remaining swap promises.
+  ScopedAbortRemainingSwapPromises swap_promise_checker(layer_tree_host_);
+
+  final_pipeline_stage_ = max_requested_pipeline_stage_;
+  max_requested_pipeline_stage_ = NO_PIPELINE_STAGE;
+
+  if (!layer_tree_host_->visible()) {
+    TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD);
+    channel_main_->BeginMainFrameAbortedOnImpl(
+        CommitEarlyOutReason::ABORTED_NOT_VISIBLE, begin_main_frame_start_time);
+    return;
+  }
+
+  if (layer_tree_host_->output_surface_lost()) {
+    TRACE_EVENT_INSTANT0("cc", "EarlyOut_OutputSurfaceLost",
+                         TRACE_EVENT_SCOPE_THREAD);
+    channel_main_->BeginMainFrameAbortedOnImpl(
+        CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST,
+        begin_main_frame_start_time);
+    return;
+  }
+
+  current_pipeline_stage_ = ANIMATE_PIPELINE_STAGE;
+
+  layer_tree_host_->ApplyScrollAndScale(
+      begin_main_frame_state->scroll_info.get());
+
+  layer_tree_host_->WillBeginMainFrame();
+
+  layer_tree_host_->BeginMainFrame(begin_main_frame_state->begin_frame_args);
+  layer_tree_host_->AnimateLayers(
+      begin_main_frame_state->begin_frame_args.frame_time);
+
+  // Recreate all UI resources if there were evicted UI resources when the impl
+  // thread initiated the commit.
+  if (begin_main_frame_state->evicted_ui_resources)
+    layer_tree_host_->RecreateUIResources();
+
+  layer_tree_host_->RequestMainFrameUpdate();
+  TRACE_EVENT_SYNTHETIC_DELAY_END("cc.BeginMainFrame");
+
+  bool can_cancel_this_commit = final_pipeline_stage_ < COMMIT_PIPELINE_STAGE &&
+                                !begin_main_frame_state->evicted_ui_resources;
+
+  current_pipeline_stage_ = UPDATE_LAYERS_PIPELINE_STAGE;
+  bool should_update_layers =
+      final_pipeline_stage_ >= UPDATE_LAYERS_PIPELINE_STAGE;
+  bool updated = should_update_layers && layer_tree_host_->UpdateLayers();
+
+  layer_tree_host_->WillCommit();
+  devtools_instrumentation::ScopedCommitTrace commit_task(
+      layer_tree_host_->id());
+
+  current_pipeline_stage_ = COMMIT_PIPELINE_STAGE;
+  if (!updated && can_cancel_this_commit) {
+    TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoUpdates", TRACE_EVENT_SCOPE_THREAD);
+    channel_main_->BeginMainFrameAbortedOnImpl(
+        CommitEarlyOutReason::FINISHED_NO_UPDATES, begin_main_frame_start_time);
+
+    // Although the commit is internally aborted, this is because it has been
+    // detected to be a no-op.  From the perspective of an embedder, this commit
+    // went through, and input should no longer be throttled, etc.
+    current_pipeline_stage_ = NO_PIPELINE_STAGE;
+    layer_tree_host_->CommitComplete();
+    layer_tree_host_->DidBeginMainFrame();
+    layer_tree_host_->BreakSwapPromises(SwapPromise::COMMIT_NO_UPDATE);
+    return;
+  }
+
+  // Notify the impl thread that the main thread is ready to commit. This will
+  // begin the commit process, which is blocking from the main thread's
+  // point of view, but asynchronously performed on the impl thread,
+  // coordinated by the Scheduler.
+  {
+    TRACE_EVENT0("cc", "ProxyMain::BeginMainFrame::commit");
+
+    DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
+
+    // This CapturePostTasks should be destroyed before CommitComplete() is
+    // called since that goes out to the embedder, and we want the embedder
+    // to receive its callbacks before that.
+    BlockingTaskRunner::CapturePostTasks blocked(
+        task_runner_provider_->blocking_main_thread_task_runner());
+
+    bool hold_commit_for_activation = commit_waits_for_activation_;
+    commit_waits_for_activation_ = false;
+    CompletionEvent completion;
+    channel_main_->StartCommitOnImpl(&completion, layer_tree_host_,
+                                     begin_main_frame_start_time,
+                                     hold_commit_for_activation);
+    completion.Wait();
+  }
+
+  current_pipeline_stage_ = NO_PIPELINE_STAGE;
+  layer_tree_host_->CommitComplete();
+  layer_tree_host_->DidBeginMainFrame();
+}
+
+void ProxyMain::FinishAllRendering() {
+  DCHECK(IsMainThread());
+  DCHECK(!defer_commits_);
+
+  // Make sure all GL drawing is finished on the impl thread.
+  DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
+  CompletionEvent completion;
+  channel_main_->FinishAllRenderingOnImpl(&completion);
+  completion.Wait();
+}
+
+bool ProxyMain::IsStarted() const {
+  DCHECK(IsMainThread());
+  return started_;
+}
+
+bool ProxyMain::CommitToActiveTree() const {
+  // With ProxyMain, we use a pending tree and activate it once it's ready to
+  // draw to allow input to modify the active tree and draw during raster.
+  return false;
+}
+
+void ProxyMain::SetOutputSurface(OutputSurface* output_surface) {
+  channel_main_->InitializeOutputSurfaceOnImpl(output_surface);
+}
+
+void ProxyMain::SetVisible(bool visible) {
+  TRACE_EVENT1("cc", "ProxyMain::SetVisible", "visible", visible);
+  channel_main_->SetVisibleOnImpl(visible);
+}
+
+void ProxyMain::SetThrottleFrameProduction(bool throttle) {
+  TRACE_EVENT1("cc", "ProxyMain::SetThrottleFrameProduction", "throttle",
+               throttle);
+  channel_main_->SetThrottleFrameProductionOnImpl(throttle);
+}
+
+const RendererCapabilities& ProxyMain::GetRendererCapabilities() const {
+  DCHECK(IsMainThread());
+  DCHECK(!layer_tree_host_->output_surface_lost());
+  return renderer_capabilities_;
+}
+
+void ProxyMain::SetNeedsAnimate() {
+  DCHECK(IsMainThread());
+  if (SendCommitRequestToImplThreadIfNeeded(ANIMATE_PIPELINE_STAGE)) {
+    TRACE_EVENT_INSTANT0("cc", "ProxyMain::SetNeedsAnimate",
+                         TRACE_EVENT_SCOPE_THREAD);
+  }
+}
+
+void ProxyMain::SetNeedsUpdateLayers() {
+  DCHECK(IsMainThread());
+  // If we are currently animating, make sure we also update the layers.
+  if (current_pipeline_stage_ == ANIMATE_PIPELINE_STAGE) {
+    final_pipeline_stage_ =
+        std::max(final_pipeline_stage_, UPDATE_LAYERS_PIPELINE_STAGE);
+    return;
+  }
+  if (SendCommitRequestToImplThreadIfNeeded(UPDATE_LAYERS_PIPELINE_STAGE)) {
+    TRACE_EVENT_INSTANT0("cc", "ProxyMain::SetNeedsUpdateLayers",
+                         TRACE_EVENT_SCOPE_THREAD);
+  }
+}
+
+void ProxyMain::SetNeedsCommit() {
+  DCHECK(IsMainThread());
+  // If we are currently animating, make sure we don't skip the commit. Note
+  // that requesting a commit during the layer update stage means we need to
+  // schedule another full commit.
+  if (current_pipeline_stage_ == ANIMATE_PIPELINE_STAGE) {
+    final_pipeline_stage_ =
+        std::max(final_pipeline_stage_, COMMIT_PIPELINE_STAGE);
+    return;
+  }
+  if (SendCommitRequestToImplThreadIfNeeded(COMMIT_PIPELINE_STAGE)) {
+    TRACE_EVENT_INSTANT0("cc", "ProxyMain::SetNeedsCommit",
+                         TRACE_EVENT_SCOPE_THREAD);
+  }
+}
+
+void ProxyMain::SetNeedsRedraw(const gfx::Rect& damage_rect) {
+  TRACE_EVENT0("cc", "ProxyMain::SetNeedsRedraw");
+  DCHECK(IsMainThread());
+  channel_main_->SetNeedsRedrawOnImpl(damage_rect);
+}
+
+void ProxyMain::SetNextCommitWaitsForActivation() {
+  DCHECK(IsMainThread());
+  commit_waits_for_activation_ = true;
+}
+
+void ProxyMain::NotifyInputThrottledUntilCommit() {
+  DCHECK(IsMainThread());
+  channel_main_->SetInputThrottledUntilCommitOnImpl(true);
+}
+
+void ProxyMain::SetDeferCommits(bool defer_commits) {
+  DCHECK(IsMainThread());
+  if (defer_commits_ == defer_commits)
+    return;
+
+  defer_commits_ = defer_commits;
+  if (defer_commits_)
+    TRACE_EVENT_ASYNC_BEGIN0("cc", "ProxyMain::SetDeferCommits", this);
+  else
+    TRACE_EVENT_ASYNC_END0("cc", "ProxyMain::SetDeferCommits", this);
+
+  channel_main_->SetDeferCommitsOnImpl(defer_commits);
+}
+
+bool ProxyMain::CommitRequested() const {
+  DCHECK(IsMainThread());
+  // TODO(skyostil): Split this into something like CommitRequested() and
+  // CommitInProgress().
+  return current_pipeline_stage_ != NO_PIPELINE_STAGE ||
+         max_requested_pipeline_stage_ >= COMMIT_PIPELINE_STAGE;
+}
+
+bool ProxyMain::BeginMainFrameRequested() const {
+  DCHECK(IsMainThread());
+  return max_requested_pipeline_stage_ != NO_PIPELINE_STAGE;
+}
+
+void ProxyMain::MainThreadHasStoppedFlinging() {
+  DCHECK(IsMainThread());
+  channel_main_->MainThreadHasStoppedFlingingOnImpl();
+}
+
+void ProxyMain::Start() {
+  DCHECK(IsMainThread());
+  DCHECK(task_runner_provider_->HasImplThread());
+  DCHECK(channel_main_);
+
+  // Create LayerTreeHostImpl.
+  channel_main_->SynchronouslyInitializeImpl(
+      layer_tree_host_, std::move(external_begin_frame_source_));
+
+  started_ = true;
+}
+
+void ProxyMain::Stop() {
+  TRACE_EVENT0("cc", "ProxyMain::Stop");
+  DCHECK(IsMainThread());
+  DCHECK(started_);
+
+  channel_main_->SynchronouslyCloseImpl();
+
+  layer_tree_host_ = nullptr;
+  started_ = false;
+}
+
+bool ProxyMain::SupportsImplScrolling() const {
+  return true;
+}
+
+bool ProxyMain::MainFrameWillHappenForTesting() {
+  DCHECK(IsMainThread());
+  bool main_frame_will_happen = false;
+  {
+    DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
+    CompletionEvent completion;
+    channel_main_->MainFrameWillHappenOnImplForTesting(&completion,
+                                                       &main_frame_will_happen);
+    completion.Wait();
+  }
+  return main_frame_will_happen;
+}
+
+void ProxyMain::SetChildrenNeedBeginFrames(bool children_need_begin_frames) {
+  NOTREACHED() << "Only used by SingleThreadProxy";
+}
+
+void ProxyMain::SetAuthoritativeVSyncInterval(const base::TimeDelta& interval) {
+  NOTREACHED() << "Only used by SingleProxyMain";
+}
+
+void ProxyMain::ReleaseOutputSurface() {
+  DCHECK(IsMainThread());
+  DCHECK(layer_tree_host_->output_surface_lost());
+
+  DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
+  CompletionEvent completion;
+  channel_main_->ReleaseOutputSurfaceOnImpl(&completion);
+  completion.Wait();
+}
+
+void ProxyMain::UpdateTopControlsState(TopControlsState constraints,
+                                       TopControlsState current,
+                                       bool animate) {
+  DCHECK(IsMainThread());
+  channel_main_->UpdateTopControlsStateOnImpl(constraints, current, animate);
+}
+
+bool ProxyMain::SendCommitRequestToImplThreadIfNeeded(
+    CommitPipelineStage required_stage) {
+  DCHECK(IsMainThread());
+  DCHECK_NE(NO_PIPELINE_STAGE, required_stage);
+  bool already_posted = max_requested_pipeline_stage_ != NO_PIPELINE_STAGE;
+  max_requested_pipeline_stage_ =
+      std::max(max_requested_pipeline_stage_, required_stage);
+  if (already_posted)
+    return false;
+  channel_main_->SetNeedsCommitOnImpl();
+  return true;
+}
+
+bool ProxyMain::IsMainThread() const {
+  return task_runner_provider_->IsMainThread();
+}
+
+}  // namespace cc
diff --git a/cc/trees/proxy_main.h b/cc/trees/proxy_main.h
index fbe191d..edc2a22 100644
--- a/cc/trees/proxy_main.h
+++ b/cc/trees/proxy_main.h
@@ -5,56 +5,155 @@
 #ifndef CC_TREES_PROXY_MAIN_H_
 #define CC_TREES_PROXY_MAIN_H_
 
-#include "base/memory/weak_ptr.h"
+#include "base/macros.h"
 #include "cc/animation/animation_events.h"
 #include "cc/base/cc_export.h"
 #include "cc/debug/frame_timing_tracker.h"
+#include "cc/input/top_controls_state.h"
+#include "cc/output/output_surface.h"
 #include "cc/output/renderer_capabilities.h"
+#include "cc/trees/channel_main.h"
+#include "cc/trees/proxy.h"
 #include "cc/trees/proxy_common.h"
 
 namespace cc {
-class ThreadedChannel;
+class BeginFrameSource;
+class ChannelMain;
+class LayerTreeHost;
 
-// TODO(khushalsagar): The main side of ThreadProxy. It is currently defined as
-// an interface with the implementation provided by ThreadProxy and will be
-// made an independent class.
-// The methods added to this interface should only use the MainThreadOnly or
-// BlockedMainThread variables from ThreadProxy.
-// See crbug/527200.
-class CC_EXPORT ProxyMain {
+// This class aggregates all interactions that the impl side of the compositor
+// needs to have with the main side.
+// The class is created and lives on the main thread.
+class CC_EXPORT ProxyMain : public Proxy {
  public:
-  // TODO(khushalsagar): Make this ChannelMain*. When ProxyMain and
-  // ProxyImpl are split, ProxyImpl will be passed a reference to ChannelImpl
-  // at creation. Right now we just set it directly from ThreadedChannel
-  // when the impl side is initialized.
-  virtual void SetChannel(scoped_ptr<ThreadedChannel> threaded_channel) = 0;
+  static scoped_ptr<ProxyMain> CreateThreaded(
+      LayerTreeHost* layer_tree_host,
+      TaskRunnerProvider* task_runner_provider,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source);
 
- protected:
-  virtual ~ProxyMain() {}
+  ~ProxyMain() override;
 
- private:
-  friend class ThreadedChannel;
-  // Callback for main side commands received from the Channel.
-  virtual void DidCompleteSwapBuffers() = 0;
-  virtual void SetRendererCapabilitiesMainCopy(
-      const RendererCapabilities& capabilities) = 0;
-  virtual void BeginMainFrameNotExpectedSoon() = 0;
-  virtual void DidCommitAndDrawFrame() = 0;
-  virtual void SetAnimationEvents(scoped_ptr<AnimationEventsVector> queue) = 0;
-  virtual void DidLoseOutputSurface() = 0;
-  virtual void RequestNewOutputSurface() = 0;
+  // Commits between the main and impl threads are processed through a pipeline
+  // with the following stages. For efficiency we can early out at any stage if
+  // we decide that no further processing is necessary.
+  enum CommitPipelineStage {
+    NO_PIPELINE_STAGE,
+    ANIMATE_PIPELINE_STAGE,
+    UPDATE_LAYERS_PIPELINE_STAGE,
+    COMMIT_PIPELINE_STAGE,
+  };
+
+  // Virtual for testing.
+  virtual void DidCompleteSwapBuffers();
+  virtual void SetRendererCapabilities(
+      const RendererCapabilities& capabilities);
+  virtual void BeginMainFrameNotExpectedSoon();
+  virtual void DidCommitAndDrawFrame();
+  virtual void SetAnimationEvents(scoped_ptr<AnimationEventsVector> queue);
+  virtual void DidLoseOutputSurface();
+  virtual void RequestNewOutputSurface();
   virtual void DidInitializeOutputSurface(
       bool success,
-      const RendererCapabilities& capabilities) = 0;
-  virtual void DidCompletePageScaleAnimation() = 0;
+      const RendererCapabilities& capabilities);
+  virtual void DidCompletePageScaleAnimation();
   virtual void PostFrameTimingEventsOnMain(
       scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
-      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) = 0;
+      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events);
   virtual void BeginMainFrame(
-      scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) = 0;
+      scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state);
 
-  // TODO(khushalsagar): Rename as GetWeakPtr() once ThreadProxy is split.
-  virtual base::WeakPtr<ProxyMain> GetMainWeakPtr() = 0;
+  ChannelMain* channel_main() const { return channel_main_.get(); }
+  CommitPipelineStage max_requested_pipeline_stage() const {
+    return max_requested_pipeline_stage_;
+  }
+  CommitPipelineStage current_pipeline_stage() const {
+    return current_pipeline_stage_;
+  }
+  CommitPipelineStage final_pipeline_stage() const {
+    return final_pipeline_stage_;
+  }
+
+ protected:
+  ProxyMain(LayerTreeHost* layer_tree_host,
+            TaskRunnerProvider* task_runner_provider,
+            scoped_ptr<BeginFrameSource> external_begin_frame_source);
+
+ private:
+  friend class ProxyMainForTest;
+
+  // Proxy implementation.
+  void FinishAllRendering() override;
+  bool IsStarted() const override;
+  bool CommitToActiveTree() const override;
+  void SetOutputSurface(OutputSurface* output_surface) override;
+  void SetVisible(bool visible) override;
+  void SetThrottleFrameProduction(bool throttle) override;
+  const RendererCapabilities& GetRendererCapabilities() const override;
+  void SetNeedsAnimate() override;
+  void SetNeedsUpdateLayers() override;
+  void SetNeedsCommit() override;
+  void SetNeedsRedraw(const gfx::Rect& damage_rect) override;
+  void SetNextCommitWaitsForActivation() override;
+  void NotifyInputThrottledUntilCommit() override;
+  void SetDeferCommits(bool defer_commits) override;
+  bool CommitRequested() const override;
+  bool BeginMainFrameRequested() const override;
+  void MainThreadHasStoppedFlinging() override;
+  void Start() override;
+  void Stop() override;
+  bool SupportsImplScrolling() const override;
+  bool MainFrameWillHappenForTesting() override;
+  void SetChildrenNeedBeginFrames(bool children_need_begin_frames) override;
+  void SetAuthoritativeVSyncInterval(const base::TimeDelta& interval) override;
+  void ReleaseOutputSurface() override;
+  void UpdateTopControlsState(TopControlsState constraints,
+                              TopControlsState current,
+                              bool animate) override;
+
+  // This sets the channel used by ProxyMain to communicate with ProxyImpl.
+  void SetChannel(scoped_ptr<ChannelMain> channel_main);
+
+  // Returns |true| if the request was actually sent, |false| if one was
+  // already outstanding.
+  bool SendCommitRequestToImplThreadIfNeeded(
+      CommitPipelineStage required_stage);
+  bool IsMainThread() const;
+
+  LayerTreeHost* layer_tree_host_;
+
+  TaskRunnerProvider* task_runner_provider_;
+
+  const int layer_tree_host_id_;
+
+  // The furthest pipeline stage which has been requested for the next
+  // commit.
+  CommitPipelineStage max_requested_pipeline_stage_;
+  // The commit pipeline stage that is currently being processed.
+  CommitPipelineStage current_pipeline_stage_;
+  // The commit pipeline stage at which processing for the current commit
+  // will stop. Only valid while we are executing the pipeline (i.e.,
+  // |current_pipeline_stage| is set to a pipeline stage).
+  CommitPipelineStage final_pipeline_stage_;
+
+  bool commit_waits_for_activation_;
+
+  // Set when the Proxy is started using Proxy::Start() and reset when it is
+  // stopped using Proxy::Stop().
+  bool started_;
+
+  bool defer_commits_;
+
+  RendererCapabilities renderer_capabilities_;
+
+  // This holds a valid value only until ProxyImpl is created on the impl thread
+  // with InitializeImplOnImpl().
+  // TODO(khushalsagar): Remove the use of this temporary variable.
+  // See crbug/567930.
+  scoped_ptr<BeginFrameSource> external_begin_frame_source_;
+
+  scoped_ptr<ChannelMain> channel_main_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProxyMain);
 };
 
 }  // namespace cc
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
deleted file mode 100644
index 7e09d7a..0000000
--- a/cc/trees/thread_proxy.cc
+++ /dev/null
@@ -1,1190 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/trees/thread_proxy.h"
-
-#include <algorithm>
-#include <string>
-
-#include "base/auto_reset.h"
-#include "base/bind.h"
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "base/trace_event/trace_event_synthetic_delay.h"
-#include "cc/debug/benchmark_instrumentation.h"
-#include "cc/debug/devtools_instrumentation.h"
-#include "cc/input/input_handler.h"
-#include "cc/input/top_controls_manager.h"
-#include "cc/output/context_provider.h"
-#include "cc/output/output_surface.h"
-#include "cc/output/swap_promise.h"
-#include "cc/quads/draw_quad.h"
-#include "cc/scheduler/commit_earlyout_reason.h"
-#include "cc/scheduler/compositor_timing_history.h"
-#include "cc/scheduler/scheduler.h"
-#include "cc/trees/blocking_task_runner.h"
-#include "cc/trees/layer_tree_host.h"
-#include "cc/trees/layer_tree_impl.h"
-#include "cc/trees/scoped_abort_remaining_swap_promises.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-
-namespace cc {
-
-namespace {
-
-// Measured in seconds.
-const double kSmoothnessTakesPriorityExpirationDelay = 0.25;
-
-unsigned int nextBeginFrameId = 0;
-
-}  // namespace
-
-struct ThreadProxy::SchedulerStateRequest {
-  CompletionEvent completion;
-  scoped_ptr<base::Value> state;
-};
-
-scoped_ptr<Proxy> ThreadProxy::Create(
-    LayerTreeHost* layer_tree_host,
-    TaskRunnerProvider* task_runner_provider,
-    scoped_ptr<BeginFrameSource> external_begin_frame_source) {
-  return make_scoped_ptr(
-      new ThreadProxy(layer_tree_host, task_runner_provider,
-                      std::move(external_begin_frame_source)));
-}
-
-ThreadProxy::ThreadProxy(
-    LayerTreeHost* layer_tree_host,
-    TaskRunnerProvider* task_runner_provider,
-    scoped_ptr<BeginFrameSource> external_begin_frame_source)
-    : task_runner_provider_(task_runner_provider),
-      main_thread_only_vars_unsafe_(this, layer_tree_host),
-      compositor_thread_vars_unsafe_(
-          this,
-          layer_tree_host->id(),
-          layer_tree_host->rendering_stats_instrumentation(),
-          std::move(external_begin_frame_source)) {
-  TRACE_EVENT0("cc", "ThreadProxy::ThreadProxy");
-  DCHECK(task_runner_provider_);
-  DCHECK(task_runner_provider_->IsMainThread());
-  DCHECK(this->main().layer_tree_host);
-  // TODO(khushalsagar): Move this to LayerTreeHost#InitializeThreaded once
-  // ThreadProxy is split. LayerTreeHost creates the channel and passes it to
-  // ProxyMain#SetChannel.
-  SetChannel(ThreadedChannel::Create(this, task_runner_provider_));
-}
-
-ThreadProxy::MainThreadOnly::MainThreadOnly(ThreadProxy* proxy,
-                                            LayerTreeHost* layer_tree_host)
-    : layer_tree_host_id(layer_tree_host->id()),
-      layer_tree_host(layer_tree_host),
-      max_requested_pipeline_stage(NO_PIPELINE_STAGE),
-      current_pipeline_stage(NO_PIPELINE_STAGE),
-      final_pipeline_stage(NO_PIPELINE_STAGE),
-      commit_waits_for_activation(false),
-      started(false),
-      prepare_tiles_pending(false),
-      defer_commits(false),
-      weak_factory(proxy) {}
-
-ThreadProxy::MainThreadOnly::~MainThreadOnly() {}
-
-ThreadProxy::BlockedMainCommitOnly::BlockedMainCommitOnly()
-    : layer_tree_host(nullptr) {}
-
-ThreadProxy::BlockedMainCommitOnly::~BlockedMainCommitOnly() {}
-
-ThreadProxy::CompositorThreadOnly::CompositorThreadOnly(
-    ThreadProxy* proxy,
-    int layer_tree_host_id,
-    RenderingStatsInstrumentation* rendering_stats_instrumentation,
-    scoped_ptr<BeginFrameSource> external_begin_frame_source)
-    : layer_tree_host_id(layer_tree_host_id),
-      next_commit_waits_for_activation(false),
-      commit_completion_event(nullptr),
-      next_frame_is_newly_committed_frame(false),
-      inside_draw(false),
-      input_throttled_until_commit(false),
-      smoothness_priority_expiration_notifier(
-          proxy->task_runner_provider()
-              ->ImplThreadTaskRunner(),
-          base::Bind(&ThreadProxy::RenewTreePriority, base::Unretained(proxy)),
-          base::TimeDelta::FromMilliseconds(
-              kSmoothnessTakesPriorityExpirationDelay * 1000)),
-      external_begin_frame_source(std::move(external_begin_frame_source)),
-      rendering_stats_instrumentation(rendering_stats_instrumentation),
-      weak_factory(proxy) {}
-
-ThreadProxy::CompositorThreadOnly::~CompositorThreadOnly() {}
-
-ThreadProxy::~ThreadProxy() {
-  TRACE_EVENT0("cc", "ThreadProxy::~ThreadProxy");
-  DCHECK(task_runner_provider_->IsMainThread());
-  DCHECK(!main().started);
-}
-
-void ThreadProxy::SetChannel(scoped_ptr<ThreadedChannel> threaded_channel) {
-  threaded_channel_ = std::move(threaded_channel);
-  main().channel_main = threaded_channel_.get();
-}
-
-void ThreadProxy::FinishAllRendering() {
-  DCHECK(task_runner_provider_->IsMainThread());
-  DCHECK(!main().defer_commits);
-
-  // Make sure all GL drawing is finished on the impl thread.
-  DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
-  CompletionEvent completion;
-  main().channel_main->FinishAllRenderingOnImpl(&completion);
-  completion.Wait();
-}
-
-bool ThreadProxy::IsStarted() const {
-  DCHECK(task_runner_provider_->IsMainThread());
-  return main().started;
-}
-
-bool ThreadProxy::CommitToActiveTree() const {
-  // With ThreadProxy, we use a pending tree and activate it once it's ready to
-  // draw to allow input to modify the active tree and draw during raster.
-  return false;
-}
-
-void ThreadProxy::SetVisible(bool visible) {
-  TRACE_EVENT1("cc", "ThreadProxy::SetVisible", "visible", visible);
-  main().channel_main->SetVisibleOnImpl(visible);
-}
-
-void ThreadProxy::SetVisibleOnImpl(bool visible) {
-  TRACE_EVENT1("cc", "ThreadProxy::SetVisibleOnImplThread", "visible", visible);
-  impl().layer_tree_host_impl->SetVisible(visible);
-  impl().scheduler->SetVisible(visible);
-}
-
-void ThreadProxy::SetThrottleFrameProduction(bool throttle) {
-  TRACE_EVENT1("cc", "ThreadProxy::SetThrottleFrameProduction", "throttle",
-               throttle);
-  main().channel_main->SetThrottleFrameProductionOnImpl(throttle);
-}
-
-void ThreadProxy::SetThrottleFrameProductionOnImpl(bool throttle) {
-  TRACE_EVENT1("cc", "ThreadProxy::SetThrottleFrameProductionOnImplThread",
-               "throttle", throttle);
-  impl().scheduler->SetThrottleFrameProduction(throttle);
-}
-
-void ThreadProxy::DidLoseOutputSurface() {
-  TRACE_EVENT0("cc", "ThreadProxy::DidLoseOutputSurface");
-  DCHECK(task_runner_provider_->IsMainThread());
-  main().layer_tree_host->DidLoseOutputSurface();
-}
-
-void ThreadProxy::RequestNewOutputSurface() {
-  DCHECK(task_runner_provider_->IsMainThread());
-  main().layer_tree_host->RequestNewOutputSurface();
-}
-
-void ThreadProxy::SetOutputSurface(OutputSurface* output_surface) {
-  main().channel_main->InitializeOutputSurfaceOnImpl(output_surface);
-}
-
-void ThreadProxy::ReleaseOutputSurface() {
-  DCHECK(task_runner_provider_->IsMainThread());
-  DCHECK(main().layer_tree_host->output_surface_lost());
-
-  DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
-  CompletionEvent completion;
-  main().channel_main->ReleaseOutputSurfaceOnImpl(&completion);
-  completion.Wait();
-}
-
-void ThreadProxy::DidInitializeOutputSurface(
-    bool success,
-    const RendererCapabilities& capabilities) {
-  TRACE_EVENT0("cc", "ThreadProxy::DidInitializeOutputSurface");
-  DCHECK(task_runner_provider_->IsMainThread());
-
-  if (!success) {
-    main().layer_tree_host->DidFailToInitializeOutputSurface();
-    return;
-  }
-  main().renderer_capabilities_main_thread_copy = capabilities;
-  main().layer_tree_host->DidInitializeOutputSurface();
-}
-
-void ThreadProxy::SetRendererCapabilitiesMainCopy(
-    const RendererCapabilities& capabilities) {
-  main().renderer_capabilities_main_thread_copy = capabilities;
-}
-
-bool ThreadProxy::SendCommitRequestToImplThreadIfNeeded(
-    CommitPipelineStage required_stage) {
-  DCHECK(task_runner_provider_->IsMainThread());
-  DCHECK_NE(NO_PIPELINE_STAGE, required_stage);
-  bool already_posted =
-      main().max_requested_pipeline_stage != NO_PIPELINE_STAGE;
-  main().max_requested_pipeline_stage =
-      std::max(main().max_requested_pipeline_stage, required_stage);
-  if (already_posted)
-    return false;
-  main().channel_main->SetNeedsCommitOnImpl();
-  return true;
-}
-
-void ThreadProxy::SetNeedsCommitOnImpl() {
-  SetNeedsCommitOnImplThread();
-}
-
-void ThreadProxy::DidCompletePageScaleAnimation() {
-  DCHECK(task_runner_provider_->IsMainThread());
-  main().layer_tree_host->DidCompletePageScaleAnimation();
-}
-
-const RendererCapabilities& ThreadProxy::GetRendererCapabilities() const {
-  DCHECK(task_runner_provider_->IsMainThread());
-  DCHECK(!main().layer_tree_host->output_surface_lost());
-  return main().renderer_capabilities_main_thread_copy;
-}
-
-void ThreadProxy::SetNeedsAnimate() {
-  DCHECK(task_runner_provider_->IsMainThread());
-  if (SendCommitRequestToImplThreadIfNeeded(ANIMATE_PIPELINE_STAGE)) {
-    TRACE_EVENT_INSTANT0("cc", "ThreadProxy::SetNeedsAnimate",
-                         TRACE_EVENT_SCOPE_THREAD);
-  }
-}
-
-void ThreadProxy::SetNeedsUpdateLayers() {
-  DCHECK(task_runner_provider_->IsMainThread());
-  // If we are currently animating, make sure we also update the layers.
-  if (main().current_pipeline_stage == ANIMATE_PIPELINE_STAGE) {
-    main().final_pipeline_stage =
-        std::max(main().final_pipeline_stage, UPDATE_LAYERS_PIPELINE_STAGE);
-    return;
-  }
-  if (SendCommitRequestToImplThreadIfNeeded(UPDATE_LAYERS_PIPELINE_STAGE)) {
-    TRACE_EVENT_INSTANT0("cc", "ThreadProxy::SetNeedsUpdateLayers",
-                         TRACE_EVENT_SCOPE_THREAD);
-  }
-}
-
-void ThreadProxy::SetNeedsCommit() {
-  DCHECK(task_runner_provider_->IsMainThread());
-  // If we are currently animating, make sure we don't skip the commit. Note
-  // that requesting a commit during the layer update stage means we need to
-  // schedule another full commit.
-  if (main().current_pipeline_stage == ANIMATE_PIPELINE_STAGE) {
-    main().final_pipeline_stage =
-        std::max(main().final_pipeline_stage, COMMIT_PIPELINE_STAGE);
-    return;
-  }
-  if (SendCommitRequestToImplThreadIfNeeded(COMMIT_PIPELINE_STAGE)) {
-    TRACE_EVENT_INSTANT0("cc", "ThreadProxy::SetNeedsCommit",
-                         TRACE_EVENT_SCOPE_THREAD);
-  }
-}
-
-void ThreadProxy::UpdateRendererCapabilitiesOnImplThread() {
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().channel_impl->SetRendererCapabilitiesMainCopy(
-      impl()
-          .layer_tree_host_impl->GetRendererCapabilities()
-          .MainThreadCapabilities());
-}
-
-void ThreadProxy::DidLoseOutputSurfaceOnImplThread() {
-  TRACE_EVENT0("cc", "ThreadProxy::DidLoseOutputSurfaceOnImplThread");
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().channel_impl->DidLoseOutputSurface();
-  impl().scheduler->DidLoseOutputSurface();
-}
-
-void ThreadProxy::CommitVSyncParameters(base::TimeTicks timebase,
-                                        base::TimeDelta interval) {
-  impl().scheduler->CommitVSyncParameters(timebase, interval);
-}
-
-void ThreadProxy::SetEstimatedParentDrawTime(base::TimeDelta draw_time) {
-  impl().scheduler->SetEstimatedParentDrawTime(draw_time);
-}
-
-void ThreadProxy::DidSwapBuffersOnImplThread() {
-  impl().scheduler->DidSwapBuffers();
-}
-
-void ThreadProxy::DidSwapBuffersCompleteOnImplThread() {
-  TRACE_EVENT0("cc,benchmark",
-               "ThreadProxy::DidSwapBuffersCompleteOnImplThread");
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().scheduler->DidSwapBuffersComplete();
-  impl().channel_impl->DidCompleteSwapBuffers();
-}
-
-void ThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) {
-  impl().layer_tree_host_impl->WillBeginImplFrame(args);
-  if (impl().last_processed_begin_main_frame_args.IsValid()) {
-    // Last processed begin main frame args records the frame args that we sent
-    // to the main thread for the last frame that we've processed. If that is
-    // set, that means the current frame is one past the frame in which we've
-    // finished the processing.
-    impl().layer_tree_host_impl->RecordMainFrameTiming(
-        impl().last_processed_begin_main_frame_args, args);
-    impl().last_processed_begin_main_frame_args = BeginFrameArgs();
-  }
-}
-
-void ThreadProxy::OnResourcelessSoftareDrawStateChanged(
-    bool resourceless_draw) {
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().scheduler->SetResourcelessSoftareDraw(resourceless_draw);
-}
-
-void ThreadProxy::OnCanDrawStateChanged(bool can_draw) {
-  TRACE_EVENT1(
-      "cc", "ThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw);
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().scheduler->SetCanDraw(can_draw);
-}
-
-void ThreadProxy::NotifyReadyToActivate() {
-  TRACE_EVENT0("cc", "ThreadProxy::NotifyReadyToActivate");
-  impl().scheduler->NotifyReadyToActivate();
-}
-
-void ThreadProxy::NotifyReadyToDraw() {
-  TRACE_EVENT0("cc", "ThreadProxy::NotifyReadyToDraw");
-  impl().scheduler->NotifyReadyToDraw();
-}
-
-void ThreadProxy::SetNeedsCommitOnImplThread() {
-  TRACE_EVENT0("cc", "ThreadProxy::SetNeedsCommitOnImplThread");
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().scheduler->SetNeedsBeginMainFrame();
-}
-
-void ThreadProxy::SetVideoNeedsBeginFrames(bool needs_begin_frames) {
-  TRACE_EVENT1("cc", "ThreadProxy::SetVideoNeedsBeginFrames",
-               "needs_begin_frames", needs_begin_frames);
-  DCHECK(task_runner_provider_->IsImplThread());
-  // In tests the layer tree is destroyed after the scheduler is.
-  if (impl().scheduler)
-    impl().scheduler->SetVideoNeedsBeginFrames(needs_begin_frames);
-}
-
-void ThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
-    scoped_ptr<AnimationEventsVector> events) {
-  TRACE_EVENT0("cc",
-               "ThreadProxy::PostAnimationEventsToMainThreadOnImplThread");
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().channel_impl->SetAnimationEvents(std::move(events));
-}
-
-bool ThreadProxy::IsInsideDraw() { return impl().inside_draw; }
-
-void ThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) {
-  TRACE_EVENT0("cc", "ThreadProxy::SetNeedsRedraw");
-  DCHECK(task_runner_provider_->IsMainThread());
-  main().channel_main->SetNeedsRedrawOnImpl(damage_rect);
-}
-
-void ThreadProxy::SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) {
-  DCHECK(task_runner_provider_->IsImplThread());
-  SetNeedsRedrawRectOnImplThread(damage_rect);
-}
-
-void ThreadProxy::SetNextCommitWaitsForActivation() {
-  DCHECK(task_runner_provider_->IsMainThread());
-  main().commit_waits_for_activation = true;
-}
-
-void ThreadProxy::SetDeferCommits(bool defer_commits) {
-  DCHECK(task_runner_provider_->IsMainThread());
-  if (main().defer_commits == defer_commits)
-    return;
-
-  main().defer_commits = defer_commits;
-  if (main().defer_commits)
-    TRACE_EVENT_ASYNC_BEGIN0("cc", "ThreadProxy::SetDeferCommits", this);
-  else
-    TRACE_EVENT_ASYNC_END0("cc", "ThreadProxy::SetDeferCommits", this);
-
-  main().channel_main->SetDeferCommitsOnImpl(defer_commits);
-}
-
-void ThreadProxy::SetDeferCommitsOnImpl(bool defer_commits) const {
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().scheduler->SetDeferCommits(defer_commits);
-}
-
-bool ThreadProxy::CommitRequested() const {
-  DCHECK(task_runner_provider_->IsMainThread());
-  // TODO(skyostil): Split this into something like CommitRequested() and
-  // CommitInProgress().
-  return main().current_pipeline_stage != NO_PIPELINE_STAGE ||
-         main().max_requested_pipeline_stage >= COMMIT_PIPELINE_STAGE;
-}
-
-bool ThreadProxy::BeginMainFrameRequested() const {
-  DCHECK(task_runner_provider_->IsMainThread());
-  return main().max_requested_pipeline_stage != NO_PIPELINE_STAGE;
-}
-
-void ThreadProxy::SetNeedsRedrawOnImplThread() {
-  TRACE_EVENT0("cc", "ThreadProxy::SetNeedsRedrawOnImplThread");
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().scheduler->SetNeedsRedraw();
-}
-
-void ThreadProxy::SetNeedsOneBeginImplFrameOnImplThread() {
-  TRACE_EVENT0("cc", "ThreadProxy::SetNeedsOneBeginImplFrameOnImplThread");
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().scheduler->SetNeedsOneBeginImplFrame();
-}
-
-void ThreadProxy::SetNeedsPrepareTilesOnImplThread() {
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().scheduler->SetNeedsPrepareTiles();
-}
-
-void ThreadProxy::SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) {
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().layer_tree_host_impl->SetViewportDamage(damage_rect);
-  SetNeedsRedrawOnImplThread();
-}
-
-void ThreadProxy::MainThreadHasStoppedFlinging() {
-  DCHECK(task_runner_provider_->IsMainThread());
-  main().channel_main->MainThreadHasStoppedFlingingOnImpl();
-}
-
-void ThreadProxy::MainThreadHasStoppedFlingingOnImpl() {
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().layer_tree_host_impl->MainThreadHasStoppedFlinging();
-}
-
-void ThreadProxy::NotifyInputThrottledUntilCommit() {
-  DCHECK(task_runner_provider_->IsMainThread());
-  main().channel_main->SetInputThrottledUntilCommitOnImpl(true);
-}
-
-void ThreadProxy::SetInputThrottledUntilCommitOnImpl(bool is_throttled) {
-  DCHECK(task_runner_provider_->IsImplThread());
-  if (is_throttled == impl().input_throttled_until_commit)
-    return;
-  impl().input_throttled_until_commit = is_throttled;
-  RenewTreePriority();
-}
-
-ThreadProxy::MainThreadOnly& ThreadProxy::main() {
-  DCHECK(task_runner_provider_->IsMainThread());
-  return main_thread_only_vars_unsafe_;
-}
-const ThreadProxy::MainThreadOnly& ThreadProxy::main() const {
-  DCHECK(task_runner_provider_->IsMainThread());
-  return main_thread_only_vars_unsafe_;
-}
-
-ThreadProxy::BlockedMainCommitOnly& ThreadProxy::blocked_main_commit() {
-  DCHECK(impl().commit_completion_event);
-  DCHECK(task_runner_provider_->IsMainThreadBlocked());
-  return main_thread_blocked_commit_vars_unsafe_;
-}
-
-ThreadProxy::CompositorThreadOnly& ThreadProxy::impl() {
-  DCHECK(task_runner_provider_->IsImplThread());
-  return compositor_thread_vars_unsafe_;
-}
-
-const ThreadProxy::CompositorThreadOnly& ThreadProxy::impl() const {
-  DCHECK(task_runner_provider_->IsImplThread());
-  return compositor_thread_vars_unsafe_;
-}
-
-void ThreadProxy::Start() {
-  DCHECK(task_runner_provider_->IsMainThread());
-  DCHECK(task_runner_provider_->HasImplThread());
-
-  // Create LayerTreeHostImpl.
-  DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
-  CompletionEvent completion;
-  main().channel_main->InitializeImplOnImpl(&completion,
-                                            main().layer_tree_host);
-  completion.Wait();
-
-  main_thread_weak_ptr_ = main().weak_factory.GetWeakPtr();
-
-  main().started = true;
-}
-
-void ThreadProxy::Stop() {
-  TRACE_EVENT0("cc", "ThreadProxy::Stop");
-  DCHECK(task_runner_provider_->IsMainThread());
-  DCHECK(main().started);
-
-  // Synchronously finishes pending GL operations and deletes the impl.
-  // The two steps are done as separate post tasks, so that tasks posted
-  // by the GL implementation due to the Finish can be executed by the
-  // renderer before shutting it down.
-  {
-    DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
-    CompletionEvent completion;
-    main().channel_main->FinishGLOnImpl(&completion);
-    completion.Wait();
-  }
-  {
-    DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
-
-    CompletionEvent completion;
-    main().channel_main->LayerTreeHostClosedOnImpl(&completion);
-    completion.Wait();
-  }
-
-  main().weak_factory.InvalidateWeakPtrs();
-  main().layer_tree_host = nullptr;
-  main().started = false;
-}
-
-bool ThreadProxy::SupportsImplScrolling() const {
-  return true;
-}
-
-void ThreadProxy::FinishAllRenderingOnImpl(CompletionEvent* completion) {
-  TRACE_EVENT0("cc", "ThreadProxy::FinishAllRenderingOnImplThread");
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().layer_tree_host_impl->FinishAllRendering();
-  completion->Signal();
-}
-
-void ThreadProxy::ScheduledActionSendBeginMainFrame(
-    const BeginFrameArgs& args) {
-  unsigned int begin_frame_id = nextBeginFrameId++;
-  benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task(
-      benchmark_instrumentation::kSendBeginFrame, begin_frame_id);
-  scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state(
-      new BeginMainFrameAndCommitState);
-  begin_main_frame_state->begin_frame_id = begin_frame_id;
-  begin_main_frame_state->begin_frame_args = args;
-  begin_main_frame_state->scroll_info =
-      impl().layer_tree_host_impl->ProcessScrollDeltas();
-  begin_main_frame_state->memory_allocation_limit_bytes =
-      impl().layer_tree_host_impl->memory_allocation_limit_bytes();
-  begin_main_frame_state->evicted_ui_resources =
-      impl().layer_tree_host_impl->EvictedUIResourcesExist();
-  // TODO(vmpstr): This needs to be fixed if
-  // main_frame_before_activation_enabled is set, since we might run this code
-  // twice before recording a duration. crbug.com/469824
-  impl().last_begin_main_frame_args = begin_main_frame_state->begin_frame_args;
-  impl().channel_impl->BeginMainFrame(std::move(begin_main_frame_state));
-  devtools_instrumentation::DidRequestMainThreadFrame(
-      impl().layer_tree_host_id);
-}
-
-void ThreadProxy::SendBeginMainFrameNotExpectedSoon() {
-  impl().channel_impl->BeginMainFrameNotExpectedSoon();
-}
-
-void ThreadProxy::BeginMainFrame(
-    scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) {
-  benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task(
-      benchmark_instrumentation::kDoBeginFrame,
-      begin_main_frame_state->begin_frame_id);
-
-  base::TimeTicks begin_main_frame_start_time = base::TimeTicks::Now();
-
-  TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("cc.BeginMainFrame");
-  DCHECK(task_runner_provider_->IsMainThread());
-  DCHECK_EQ(NO_PIPELINE_STAGE, main().current_pipeline_stage);
-
-  if (main().defer_commits) {
-    TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit",
-                         TRACE_EVENT_SCOPE_THREAD);
-    main().channel_main->BeginMainFrameAbortedOnImpl(
-        CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT,
-        begin_main_frame_start_time);
-    return;
-  }
-
-  // If the commit finishes, LayerTreeHost will transfer its swap promises to
-  // LayerTreeImpl. The destructor of ScopedSwapPromiseChecker aborts the
-  // remaining swap promises.
-  ScopedAbortRemainingSwapPromises swap_promise_checker(main().layer_tree_host);
-
-  main().final_pipeline_stage = main().max_requested_pipeline_stage;
-  main().max_requested_pipeline_stage = NO_PIPELINE_STAGE;
-
-  if (!main().layer_tree_host->visible()) {
-    TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD);
-    main().channel_main->BeginMainFrameAbortedOnImpl(
-        CommitEarlyOutReason::ABORTED_NOT_VISIBLE, begin_main_frame_start_time);
-    return;
-  }
-
-  if (main().layer_tree_host->output_surface_lost()) {
-    TRACE_EVENT_INSTANT0(
-        "cc", "EarlyOut_OutputSurfaceLost", TRACE_EVENT_SCOPE_THREAD);
-    main().channel_main->BeginMainFrameAbortedOnImpl(
-        CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST,
-        begin_main_frame_start_time);
-    return;
-  }
-
-  main().current_pipeline_stage = ANIMATE_PIPELINE_STAGE;
-
-  main().layer_tree_host->ApplyScrollAndScale(
-      begin_main_frame_state->scroll_info.get());
-
-  main().layer_tree_host->WillBeginMainFrame();
-
-  main().layer_tree_host->BeginMainFrame(
-      begin_main_frame_state->begin_frame_args);
-  main().layer_tree_host->AnimateLayers(
-      begin_main_frame_state->begin_frame_args.frame_time);
-
-  // Recreate all UI resources if there were evicted UI resources when the impl
-  // thread initiated the commit.
-  if (begin_main_frame_state->evicted_ui_resources)
-    main().layer_tree_host->RecreateUIResources();
-
-  main().layer_tree_host->RequestMainFrameUpdate();
-  TRACE_EVENT_SYNTHETIC_DELAY_END("cc.BeginMainFrame");
-
-  bool can_cancel_this_commit =
-      main().final_pipeline_stage < COMMIT_PIPELINE_STAGE &&
-      !begin_main_frame_state->evicted_ui_resources;
-
-  main().current_pipeline_stage = UPDATE_LAYERS_PIPELINE_STAGE;
-  bool should_update_layers =
-      main().final_pipeline_stage >= UPDATE_LAYERS_PIPELINE_STAGE;
-  bool updated = should_update_layers && main().layer_tree_host->UpdateLayers();
-
-  main().layer_tree_host->WillCommit();
-  devtools_instrumentation::ScopedCommitTrace commit_task(
-      main().layer_tree_host->id());
-
-  main().current_pipeline_stage = COMMIT_PIPELINE_STAGE;
-  if (!updated && can_cancel_this_commit) {
-    TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoUpdates", TRACE_EVENT_SCOPE_THREAD);
-    main().channel_main->BeginMainFrameAbortedOnImpl(
-        CommitEarlyOutReason::FINISHED_NO_UPDATES, begin_main_frame_start_time);
-
-    // Although the commit is internally aborted, this is because it has been
-    // detected to be a no-op.  From the perspective of an embedder, this commit
-    // went through, and input should no longer be throttled, etc.
-    main().current_pipeline_stage = NO_PIPELINE_STAGE;
-    main().layer_tree_host->CommitComplete();
-    main().layer_tree_host->DidBeginMainFrame();
-    main().layer_tree_host->BreakSwapPromises(SwapPromise::COMMIT_NO_UPDATE);
-    return;
-  }
-
-  // Notify the impl thread that the main thread is ready to commit. This will
-  // begin the commit process, which is blocking from the main thread's
-  // point of view, but asynchronously performed on the impl thread,
-  // coordinated by the Scheduler.
-  {
-    TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrame::commit");
-
-    DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
-
-    // This CapturePostTasks should be destroyed before CommitComplete() is
-    // called since that goes out to the embedder, and we want the embedder
-    // to receive its callbacks before that.
-    BlockingTaskRunner::CapturePostTasks blocked(
-        task_runner_provider_->blocking_main_thread_task_runner());
-
-    CompletionEvent completion;
-    main().channel_main->StartCommitOnImpl(&completion, main().layer_tree_host,
-                                           begin_main_frame_start_time,
-                                           main().commit_waits_for_activation);
-    completion.Wait();
-    main().commit_waits_for_activation = false;
-  }
-
-  main().current_pipeline_stage = NO_PIPELINE_STAGE;
-  main().layer_tree_host->CommitComplete();
-  main().layer_tree_host->DidBeginMainFrame();
-}
-
-void ThreadProxy::BeginMainFrameNotExpectedSoon() {
-  TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrameNotExpectedSoon");
-  DCHECK(task_runner_provider_->IsMainThread());
-  main().layer_tree_host->BeginMainFrameNotExpectedSoon();
-}
-
-void ThreadProxy::StartCommitOnImpl(CompletionEvent* completion,
-                                    LayerTreeHost* layer_tree_host,
-                                    base::TimeTicks main_thread_start_time,
-                                    bool hold_commit_for_activation) {
-  TRACE_EVENT0("cc", "ThreadProxy::StartCommitOnImplThread");
-  DCHECK(!impl().commit_completion_event);
-  DCHECK(task_runner_provider_->IsImplThread() &&
-         task_runner_provider_->IsMainThreadBlocked());
-  DCHECK(impl().scheduler);
-  DCHECK(impl().scheduler->CommitPending());
-
-  if (hold_commit_for_activation) {
-    // This commit may be aborted. Store the value for
-    // hold_commit_for_activation so that whenever the next commit is started,
-    // the main thread will be unblocked only after pending tree activation.
-    impl().next_commit_waits_for_activation = hold_commit_for_activation;
-  }
-
-  if (!impl().layer_tree_host_impl) {
-    TRACE_EVENT_INSTANT0(
-        "cc", "EarlyOut_NoLayerTree", TRACE_EVENT_SCOPE_THREAD);
-    completion->Signal();
-    return;
-  }
-
-  // Ideally, we should inform to impl thread when BeginMainFrame is started.
-  // But, we can avoid a PostTask in here.
-  impl().scheduler->NotifyBeginMainFrameStarted(main_thread_start_time);
-  impl().commit_completion_event = completion;
-  DCHECK(!blocked_main_commit().layer_tree_host);
-  blocked_main_commit().layer_tree_host = layer_tree_host;
-  impl().scheduler->NotifyReadyToCommit();
-}
-
-void ThreadProxy::BeginMainFrameAbortedOnImpl(
-    CommitEarlyOutReason reason,
-    base::TimeTicks main_thread_start_time) {
-  TRACE_EVENT1("cc", "ThreadProxy::BeginMainFrameAbortedOnImplThread", "reason",
-               CommitEarlyOutReasonToString(reason));
-  DCHECK(task_runner_provider_->IsImplThread());
-  DCHECK(impl().scheduler);
-  DCHECK(impl().scheduler->CommitPending());
-  DCHECK(!impl().layer_tree_host_impl->pending_tree());
-
-  if (CommitEarlyOutHandledCommit(reason)) {
-    SetInputThrottledUntilCommitOnImpl(false);
-    impl().last_processed_begin_main_frame_args =
-        impl().last_begin_main_frame_args;
-  }
-  impl().layer_tree_host_impl->BeginMainFrameAborted(reason);
-  impl().scheduler->NotifyBeginMainFrameStarted(main_thread_start_time);
-  impl().scheduler->BeginMainFrameAborted(reason);
-}
-
-void ThreadProxy::ScheduledActionCommit() {
-  TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionCommit");
-  DCHECK(task_runner_provider_->IsImplThread());
-  DCHECK(task_runner_provider_->IsMainThreadBlocked());
-  DCHECK(impl().commit_completion_event);
-  DCHECK(blocked_main_commit().layer_tree_host);
-
-  impl().layer_tree_host_impl->BeginCommit();
-  blocked_main_commit().layer_tree_host->FinishCommitOnImplThread(
-      impl().layer_tree_host_impl.get());
-
-  // Remove the LayerTreeHost reference before the completion event is signaled
-  // and cleared. This is necessary since blocked_main_commit() allows access
-  // only while we have the completion event to ensure the main thread is
-  // blocked for a commit.
-  blocked_main_commit().layer_tree_host = nullptr;
-
-  if (impl().next_commit_waits_for_activation) {
-    // For some layer types in impl-side painting, the commit is held until
-    // the sync tree is activated.  It's also possible that the
-    // sync tree has already activated if there was no work to be done.
-    TRACE_EVENT_INSTANT0("cc", "HoldCommit", TRACE_EVENT_SCOPE_THREAD);
-  } else {
-    impl().commit_completion_event->Signal();
-    impl().commit_completion_event = nullptr;
-  }
-
-  impl().scheduler->DidCommit();
-
-  // Delay this step until afer the main thread has been released as it's
-  // often a good bit of work to update the tree and prepare the new frame.
-  impl().layer_tree_host_impl->CommitComplete();
-
-  SetInputThrottledUntilCommitOnImpl(false);
-
-  impl().next_frame_is_newly_committed_frame = true;
-}
-
-void ThreadProxy::ScheduledActionActivateSyncTree() {
-  TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionActivateSyncTree");
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().layer_tree_host_impl->ActivateSyncTree();
-}
-
-void ThreadProxy::ScheduledActionBeginOutputSurfaceCreation() {
-  TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionBeginOutputSurfaceCreation");
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().channel_impl->RequestNewOutputSurface();
-}
-
-DrawResult ThreadProxy::DrawSwapInternal(bool forced_draw) {
-  TRACE_EVENT_SYNTHETIC_DELAY("cc.DrawAndSwap");
-  DrawResult result;
-
-  DCHECK(task_runner_provider_->IsImplThread());
-  DCHECK(impl().layer_tree_host_impl.get());
-
-  base::AutoReset<bool> mark_inside(&impl().inside_draw, true);
-
-  if (impl().layer_tree_host_impl->pending_tree()) {
-    bool update_lcd_text = false;
-    impl().layer_tree_host_impl->pending_tree()->UpdateDrawProperties(
-        update_lcd_text);
-  }
-
-  // This method is called on a forced draw, regardless of whether we are able
-  // to produce a frame, as the calling site on main thread is blocked until its
-  // request completes, and we signal completion here. If CanDraw() is false, we
-  // will indicate success=false to the caller, but we must still signal
-  // completion to avoid deadlock.
-
-  // We guard PrepareToDraw() with CanDraw() because it always returns a valid
-  // frame, so can only be used when such a frame is possible. Since
-  // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
-  // CanDraw() as well.
-
-  LayerTreeHostImpl::FrameData frame;
-  bool draw_frame = false;
-
-  if (impl().layer_tree_host_impl->CanDraw()) {
-    result = impl().layer_tree_host_impl->PrepareToDraw(&frame);
-    draw_frame = forced_draw || result == DRAW_SUCCESS;
-  } else {
-    result = DRAW_ABORTED_CANT_DRAW;
-  }
-
-  if (draw_frame) {
-    impl().layer_tree_host_impl->DrawLayers(&frame);
-    result = DRAW_SUCCESS;
-  } else {
-    DCHECK_NE(DRAW_SUCCESS, result);
-  }
-  impl().layer_tree_host_impl->DidDrawAllLayers(frame);
-
-  bool start_ready_animations = draw_frame;
-  impl().layer_tree_host_impl->UpdateAnimationState(start_ready_animations);
-
-  if (draw_frame)
-    impl().layer_tree_host_impl->SwapBuffers(frame);
-
-  // Tell the main thread that the the newly-commited frame was drawn.
-  if (impl().next_frame_is_newly_committed_frame) {
-    impl().next_frame_is_newly_committed_frame = false;
-    impl().channel_impl->DidCommitAndDrawFrame();
-  }
-
-  DCHECK_NE(INVALID_RESULT, result);
-  return result;
-}
-
-void ThreadProxy::ScheduledActionPrepareTiles() {
-  TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionPrepareTiles");
-  impl().layer_tree_host_impl->PrepareTiles();
-}
-
-DrawResult ThreadProxy::ScheduledActionDrawAndSwapIfPossible() {
-  TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwap");
-
-  // SchedulerStateMachine::DidDrawIfPossibleCompleted isn't set up to
-  // handle DRAW_ABORTED_CANT_DRAW.  Moreover, the scheduler should
-  // never generate this call when it can't draw.
-  DCHECK(impl().layer_tree_host_impl->CanDraw());
-
-  bool forced_draw = false;
-  return DrawSwapInternal(forced_draw);
-}
-
-DrawResult ThreadProxy::ScheduledActionDrawAndSwapForced() {
-  TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwapForced");
-  bool forced_draw = true;
-  return DrawSwapInternal(forced_draw);
-}
-
-void ThreadProxy::ScheduledActionInvalidateOutputSurface() {
-  TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionInvalidateOutputSurface");
-  DCHECK(impl().layer_tree_host_impl->output_surface());
-  impl().layer_tree_host_impl->output_surface()->Invalidate();
-}
-
-void ThreadProxy::DidFinishImplFrame() {
-  impl().layer_tree_host_impl->DidFinishImplFrame();
-}
-
-void ThreadProxy::SendBeginFramesToChildren(const BeginFrameArgs& args) {
-  NOTREACHED() << "Only used by SingleThreadProxy";
-}
-
-void ThreadProxy::SetAuthoritativeVSyncInterval(
-    const base::TimeDelta& interval) {
-  NOTREACHED() << "Only used by SingleThreadProxy";
-}
-
-void ThreadProxy::DidCommitAndDrawFrame() {
-  DCHECK(task_runner_provider_->IsMainThread());
-  main().layer_tree_host->DidCommitAndDrawFrame();
-}
-
-void ThreadProxy::DidCompleteSwapBuffers() {
-  DCHECK(task_runner_provider_->IsMainThread());
-  main().layer_tree_host->DidCompleteSwapBuffers();
-}
-
-void ThreadProxy::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events) {
-  TRACE_EVENT0("cc", "ThreadProxy::SetAnimationEvents");
-  DCHECK(task_runner_provider_->IsMainThread());
-  main().layer_tree_host->SetAnimationEvents(std::move(events));
-}
-
-void ThreadProxy::InitializeImplOnImpl(CompletionEvent* completion,
-                                       LayerTreeHost* layer_tree_host) {
-  TRACE_EVENT0("cc", "ThreadProxy::InitializeImplOnImplThread");
-  DCHECK(task_runner_provider_->IsImplThread());
-  DCHECK(task_runner_provider_->IsMainThreadBlocked());
-  DCHECK(layer_tree_host);
-
-  // TODO(khushalsagar): ThreadedChannel will create ProxyImpl here and pass a
-  // reference to itself.
-  impl().channel_impl = threaded_channel_.get();
-
-  impl().layer_tree_host_impl = layer_tree_host->CreateLayerTreeHostImpl(this);
-
-  SchedulerSettings scheduler_settings(
-      layer_tree_host->settings().ToSchedulerSettings());
-
-  scoped_ptr<CompositorTimingHistory> compositor_timing_history(
-      new CompositorTimingHistory(CompositorTimingHistory::RENDERER_UMA,
-                                  impl().rendering_stats_instrumentation));
-
-  impl().scheduler =
-      Scheduler::Create(this, scheduler_settings, impl().layer_tree_host_id,
-                        task_runner_provider_->ImplThreadTaskRunner(),
-                        impl().external_begin_frame_source.get(),
-                        std::move(compositor_timing_history));
-
-  DCHECK_EQ(impl().scheduler->visible(),
-            impl().layer_tree_host_impl->visible());
-  impl_thread_weak_ptr_ = impl().weak_factory.GetWeakPtr();
-  completion->Signal();
-}
-
-void ThreadProxy::InitializeOutputSurfaceOnImpl(OutputSurface* output_surface) {
-  TRACE_EVENT0("cc", "ThreadProxy::InitializeOutputSurfaceOnImplThread");
-  DCHECK(task_runner_provider_->IsImplThread());
-
-  LayerTreeHostImpl* host_impl = impl().layer_tree_host_impl.get();
-  bool success = host_impl->InitializeRenderer(output_surface);
-  RendererCapabilities capabilities;
-  if (success) {
-    capabilities =
-        host_impl->GetRendererCapabilities().MainThreadCapabilities();
-  }
-
-  impl().channel_impl->DidInitializeOutputSurface(success, capabilities);
-
-  if (success)
-    impl().scheduler->DidCreateAndInitializeOutputSurface();
-}
-
-void ThreadProxy::ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) {
-  DCHECK(task_runner_provider_->IsImplThread());
-
-  // Unlike DidLoseOutputSurfaceOnImplThread, we don't need to call
-  // LayerTreeHost::DidLoseOutputSurface since it already knows.
-  impl().scheduler->DidLoseOutputSurface();
-  impl().layer_tree_host_impl->ReleaseOutputSurface();
-  completion->Signal();
-}
-
-void ThreadProxy::FinishGLOnImpl(CompletionEvent* completion) {
-  TRACE_EVENT0("cc", "ThreadProxy::FinishGLOnImplThread");
-  DCHECK(task_runner_provider_->IsImplThread());
-  if (impl().layer_tree_host_impl->output_surface()) {
-    ContextProvider* context_provider =
-        impl().layer_tree_host_impl->output_surface()->context_provider();
-    if (context_provider)
-      context_provider->ContextGL()->Finish();
-  }
-  completion->Signal();
-}
-
-void ThreadProxy::LayerTreeHostClosedOnImpl(CompletionEvent* completion) {
-  TRACE_EVENT0("cc", "ThreadProxy::LayerTreeHostClosedOnImplThread");
-  DCHECK(task_runner_provider_->IsImplThread());
-  DCHECK(task_runner_provider_->IsMainThreadBlocked());
-  impl().scheduler = nullptr;
-  impl().external_begin_frame_source = nullptr;
-  impl().layer_tree_host_impl = nullptr;
-  impl().weak_factory.InvalidateWeakPtrs();
-  // We need to explicitly shutdown the notifier to destroy any weakptrs it is
-  // holding while still on the compositor thread. This also ensures any
-  // callbacks holding a ThreadProxy pointer are cancelled.
-  impl().smoothness_priority_expiration_notifier.Shutdown();
-  completion->Signal();
-}
-
-bool ThreadProxy::MainFrameWillHappenForTesting() {
-  DCHECK(task_runner_provider_->IsMainThread());
-  bool main_frame_will_happen = false;
-  {
-    DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
-    CompletionEvent completion;
-    main().channel_main->MainFrameWillHappenOnImplForTesting(
-        &completion, &main_frame_will_happen);
-    completion.Wait();
-  }
-  return main_frame_will_happen;
-}
-
-void ThreadProxy::SetChildrenNeedBeginFrames(bool children_need_begin_frames) {
-  NOTREACHED() << "Only used by SingleThreadProxy";
-}
-
-void ThreadProxy::MainFrameWillHappenOnImplForTesting(
-    CompletionEvent* completion,
-    bool* main_frame_will_happen) {
-  DCHECK(task_runner_provider_->IsImplThread());
-  if (impl().layer_tree_host_impl->output_surface()) {
-    *main_frame_will_happen = impl().scheduler->MainFrameForTestingWillHappen();
-  } else {
-    *main_frame_will_happen = false;
-  }
-  completion->Signal();
-}
-
-void ThreadProxy::RenewTreePriority() {
-  DCHECK(task_runner_provider_->IsImplThread());
-  bool smoothness_takes_priority =
-      impl().layer_tree_host_impl->pinch_gesture_active() ||
-      impl().layer_tree_host_impl->page_scale_animation_active() ||
-      impl().layer_tree_host_impl->IsActivelyScrolling();
-
-  // Schedule expiration if smoothness currently takes priority.
-  if (smoothness_takes_priority)
-    impl().smoothness_priority_expiration_notifier.Schedule();
-
-  // We use the same priority for both trees by default.
-  TreePriority tree_priority = SAME_PRIORITY_FOR_BOTH_TREES;
-
-  // Smoothness takes priority if we have an expiration for it scheduled.
-  if (impl().smoothness_priority_expiration_notifier.HasPendingNotification())
-    tree_priority = SMOOTHNESS_TAKES_PRIORITY;
-
-  // New content always takes priority when there is an invalid viewport size or
-  // ui resources have been evicted.
-  if (impl().layer_tree_host_impl->active_tree()->ViewportSizeInvalid() ||
-      impl().layer_tree_host_impl->EvictedUIResourcesExist() ||
-      impl().input_throttled_until_commit) {
-    // Once we enter NEW_CONTENTS_TAKES_PRIORITY mode, visible tiles on active
-    // tree might be freed. We need to set RequiresHighResToDraw to ensure that
-    // high res tiles will be required to activate pending tree.
-    impl().layer_tree_host_impl->SetRequiresHighResToDraw();
-    tree_priority = NEW_CONTENT_TAKES_PRIORITY;
-  }
-
-  impl().layer_tree_host_impl->SetTreePriority(tree_priority);
-
-  // Only put the scheduler in impl latency prioritization mode if we don't
-  // have a scroll listener. This gives the scroll listener a better chance of
-  // handling scroll updates within the same frame. The tree itself is still
-  // kept in prefer smoothness mode to allow checkerboarding.
-  ScrollHandlerState scroll_handler_state =
-      impl().layer_tree_host_impl->scroll_affects_scroll_handler()
-          ? ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER
-          : ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER;
-  impl().scheduler->SetTreePrioritiesAndScrollState(tree_priority,
-                                                    scroll_handler_state);
-
-  // Notify the the client of this compositor via the output surface.
-  // TODO(epenner): Route this to compositor-thread instead of output-surface
-  // after GTFO refactor of compositor-thread (http://crbug/170828).
-  if (impl().layer_tree_host_impl->output_surface()) {
-    impl()
-        .layer_tree_host_impl->output_surface()
-        ->UpdateSmoothnessTakesPriority(tree_priority ==
-                                        SMOOTHNESS_TAKES_PRIORITY);
-  }
-}
-
-void ThreadProxy::PostDelayedAnimationTaskOnImplThread(
-    const base::Closure& task,
-    base::TimeDelta delay) {
-  task_runner_provider_->ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE,
-                                                                 task, delay);
-}
-
-void ThreadProxy::DidActivateSyncTree() {
-  TRACE_EVENT0("cc", "ThreadProxy::DidActivateSyncTreeOnImplThread");
-  DCHECK(task_runner_provider_->IsImplThread());
-
-  if (impl().next_commit_waits_for_activation) {
-    TRACE_EVENT_INSTANT0(
-        "cc", "ReleaseCommitbyActivation", TRACE_EVENT_SCOPE_THREAD);
-    DCHECK(impl().commit_completion_event);
-    impl().commit_completion_event->Signal();
-    impl().commit_completion_event = nullptr;
-    impl().next_commit_waits_for_activation = false;
-  }
-
-  impl().last_processed_begin_main_frame_args =
-      impl().last_begin_main_frame_args;
-}
-
-void ThreadProxy::WillPrepareTiles() {
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().scheduler->WillPrepareTiles();
-}
-
-void ThreadProxy::DidPrepareTiles() {
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().scheduler->DidPrepareTiles();
-}
-
-void ThreadProxy::DidCompletePageScaleAnimationOnImplThread() {
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().channel_impl->DidCompletePageScaleAnimation();
-}
-
-void ThreadProxy::OnDrawForOutputSurface() {
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().scheduler->OnDrawForOutputSurface();
-}
-
-void ThreadProxy::UpdateTopControlsState(TopControlsState constraints,
-                                         TopControlsState current,
-                                         bool animate) {
-  main().channel_main->UpdateTopControlsStateOnImpl(constraints, current,
-                                                    animate);
-}
-
-void ThreadProxy::UpdateTopControlsStateOnImpl(TopControlsState constraints,
-                                               TopControlsState current,
-                                               bool animate) {
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().layer_tree_host_impl->top_controls_manager()->UpdateTopControlsState(
-      constraints, current, animate);
-}
-
-void ThreadProxy::PostFrameTimingEventsOnImplThread(
-    scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
-    scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) {
-  DCHECK(task_runner_provider_->IsImplThread());
-  impl().channel_impl->PostFrameTimingEventsOnMain(
-      std::move(composite_events), std::move(main_frame_events));
-}
-
-void ThreadProxy::PostFrameTimingEventsOnMain(
-    scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
-    scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) {
-  DCHECK(task_runner_provider_->IsMainThread());
-  main().layer_tree_host->RecordFrameTimingEvents(std::move(composite_events),
-                                                  std::move(main_frame_events));
-}
-
-base::WeakPtr<ProxyMain> ThreadProxy::GetMainWeakPtr() {
-  return main_thread_weak_ptr_;
-}
-
-base::WeakPtr<ProxyImpl> ThreadProxy::GetImplWeakPtr() {
-  return impl_thread_weak_ptr_;
-}
-
-}  // namespace cc
diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h
deleted file mode 100644
index e10c57e6..0000000
--- a/cc/trees/thread_proxy.h
+++ /dev/null
@@ -1,333 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_TREES_THREAD_PROXY_H_
-#define CC_TREES_THREAD_PROXY_H_
-
-#include <string>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "cc/animation/animation_events.h"
-#include "cc/base/completion_event.h"
-#include "cc/base/delayed_unique_notifier.h"
-#include "cc/scheduler/commit_earlyout_reason.h"
-#include "cc/scheduler/scheduler.h"
-#include "cc/trees/layer_tree_host_impl.h"
-#include "cc/trees/proxy.h"
-#include "cc/trees/threaded_channel.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}
-
-namespace cc {
-
-class BeginFrameSource;
-class ChannelImpl;
-class ChannelMain;
-class ContextProvider;
-class InputHandlerClient;
-class LayerTreeHost;
-class ProxyImpl;
-class ProxyMain;
-class Scheduler;
-class ScopedThreadProxy;
-class ThreadedChannel;
-
-class CC_EXPORT ThreadProxy : public Proxy,
-                              public ProxyMain,
-                              public ProxyImpl,
-                              NON_EXPORTED_BASE(LayerTreeHostImplClient),
-                              NON_EXPORTED_BASE(SchedulerClient) {
- public:
-  static scoped_ptr<Proxy> Create(
-      LayerTreeHost* layer_tree_host,
-      TaskRunnerProvider* task_runner_provider,
-      scoped_ptr<BeginFrameSource> external_begin_frame_source);
-
-  ~ThreadProxy() override;
-
-  // Commits between the main and impl threads are processed through a pipeline
-  // with the following stages. For efficiency we can early out at any stage if
-  // we decide that no further processing is necessary.
-  enum CommitPipelineStage {
-    NO_PIPELINE_STAGE,
-    ANIMATE_PIPELINE_STAGE,
-    UPDATE_LAYERS_PIPELINE_STAGE,
-    COMMIT_PIPELINE_STAGE,
-  };
-
-  struct MainThreadOnly {
-    MainThreadOnly(ThreadProxy* proxy, LayerTreeHost* layer_tree_host);
-    ~MainThreadOnly();
-
-    const int layer_tree_host_id;
-
-    LayerTreeHost* layer_tree_host;
-
-    // The furthest pipeline stage which has been requested for the next
-    // commit.
-    CommitPipelineStage max_requested_pipeline_stage;
-    // The commit pipeline stage that is currently being processed.
-    CommitPipelineStage current_pipeline_stage;
-    // The commit pipeline stage at which processing for the current commit
-    // will stop. Only valid while we are executing the pipeline (i.e.,
-    // |current_pipeline_stage| is set to a pipeline stage).
-    CommitPipelineStage final_pipeline_stage;
-
-    bool commit_waits_for_activation;
-
-    bool started;
-    bool prepare_tiles_pending;
-    bool defer_commits;
-
-    RendererCapabilities renderer_capabilities_main_thread_copy;
-
-    // TODO(khushalsagar): Make this scoped_ptr<ChannelMain> when ProxyMain
-    // and ProxyImpl are split.
-    ChannelMain* channel_main;
-
-    base::WeakPtrFactory<ThreadProxy> weak_factory;
-  };
-
-  // Accessed on the impl thread when the main thread is blocked for a commit.
-  struct BlockedMainCommitOnly {
-    BlockedMainCommitOnly();
-    ~BlockedMainCommitOnly();
-    LayerTreeHost* layer_tree_host;
-  };
-
-  struct CompositorThreadOnly {
-    CompositorThreadOnly(
-        ThreadProxy* proxy,
-        int layer_tree_host_id,
-        RenderingStatsInstrumentation* rendering_stats_instrumentation,
-        scoped_ptr<BeginFrameSource> external_begin_frame_source);
-    ~CompositorThreadOnly();
-
-    const int layer_tree_host_id;
-
-    scoped_ptr<Scheduler> scheduler;
-
-    // Set when the main thread is waiting on a pending tree activation.
-    bool next_commit_waits_for_activation;
-
-    // Set when the main thread is waiting on a commit to complete or on a
-    // pending tree activation.
-    CompletionEvent* commit_completion_event;
-
-    // Set when the next draw should post DidCommitAndDrawFrame to the main
-    // thread.
-    bool next_frame_is_newly_committed_frame;
-
-    bool inside_draw;
-
-    bool input_throttled_until_commit;
-
-    // Whether a commit has been completed since the last time animations were
-    // ticked. If this happens, we need to animate again.
-    bool did_commit_after_animating;
-
-    DelayedUniqueNotifier smoothness_priority_expiration_notifier;
-
-    scoped_ptr<BeginFrameSource> external_begin_frame_source;
-
-    RenderingStatsInstrumentation* rendering_stats_instrumentation;
-
-    // Values used to keep track of frame durations. Used only in frame timing.
-    BeginFrameArgs last_begin_main_frame_args;
-    BeginFrameArgs last_processed_begin_main_frame_args;
-
-    scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl;
-
-    ChannelImpl* channel_impl;
-
-    base::WeakPtrFactory<ThreadProxy> weak_factory;
-  };
-
-  const MainThreadOnly& main() const;
-  const CompositorThreadOnly& impl() const;
-  TaskRunnerProvider* task_runner_provider() { return task_runner_provider_; }
-
-  // Proxy implementation
-  void FinishAllRendering() override;
-  bool IsStarted() const override;
-  bool CommitToActiveTree() const override;
-  void SetOutputSurface(OutputSurface* output_surface) override;
-  void SetVisible(bool visible) override;
-  void SetThrottleFrameProduction(bool throttle) override;
-  const RendererCapabilities& GetRendererCapabilities() const override;
-  void SetNeedsAnimate() override;
-  void SetNeedsUpdateLayers() override;
-  void SetNeedsCommit() override;
-  void SetNeedsRedraw(const gfx::Rect& damage_rect) override;
-  void SetNextCommitWaitsForActivation() override;
-  void NotifyInputThrottledUntilCommit() override;
-  void SetDeferCommits(bool defer_commits) override;
-  bool CommitRequested() const override;
-  bool BeginMainFrameRequested() const override;
-  void MainThreadHasStoppedFlinging() override;
-  void Start() override;
-  void Stop() override;
-  bool SupportsImplScrolling() const override;
-  bool MainFrameWillHappenForTesting() override;
-  void SetChildrenNeedBeginFrames(bool children_need_begin_frames) override;
-  void SetAuthoritativeVSyncInterval(const base::TimeDelta& interval) override;
-  void ReleaseOutputSurface() override;
-  void UpdateTopControlsState(TopControlsState constraints,
-                              TopControlsState current,
-                              bool animate) override;
-
-  // LayerTreeHostImplClient implementation
-  void UpdateRendererCapabilitiesOnImplThread() override;
-  void DidLoseOutputSurfaceOnImplThread() override;
-  void CommitVSyncParameters(base::TimeTicks timebase,
-                             base::TimeDelta interval) override;
-  void SetEstimatedParentDrawTime(base::TimeDelta draw_time) override;
-  void DidSwapBuffersOnImplThread() override;
-  void DidSwapBuffersCompleteOnImplThread() override;
-  void OnResourcelessSoftareDrawStateChanged(bool resourceless_draw) override;
-  void OnCanDrawStateChanged(bool can_draw) override;
-  void NotifyReadyToActivate() override;
-  void NotifyReadyToDraw() override;
-  // Please call these 3 functions through
-  // LayerTreeHostImpl's SetNeedsRedraw(), SetNeedsRedrawRect() and
-  // SetNeedsOneBeginImplFrame().
-  void SetNeedsRedrawOnImplThread() override;
-  void SetNeedsRedrawRectOnImplThread(const gfx::Rect& dirty_rect) override;
-  void SetNeedsOneBeginImplFrameOnImplThread() override;
-  void SetNeedsPrepareTilesOnImplThread() override;
-  void SetNeedsCommitOnImplThread() override;
-  void SetVideoNeedsBeginFrames(bool needs_begin_frames) override;
-  void PostAnimationEventsToMainThreadOnImplThread(
-      scoped_ptr<AnimationEventsVector> queue) override;
-  bool IsInsideDraw() override;
-  void RenewTreePriority() override;
-  void PostDelayedAnimationTaskOnImplThread(const base::Closure& task,
-                                            base::TimeDelta delay) override;
-  void DidActivateSyncTree() override;
-  void WillPrepareTiles() override;
-  void DidPrepareTiles() override;
-  void DidCompletePageScaleAnimationOnImplThread() override;
-  void OnDrawForOutputSurface() override;
-  // This should only be called by LayerTreeHostImpl::PostFrameTimingEvents.
-  void PostFrameTimingEventsOnImplThread(
-      scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
-      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events)
-      override;
-
-  // SchedulerClient implementation
-  void WillBeginImplFrame(const BeginFrameArgs& args) override;
-  void DidFinishImplFrame() override;
-  void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override;
-  DrawResult ScheduledActionDrawAndSwapIfPossible() override;
-  DrawResult ScheduledActionDrawAndSwapForced() override;
-  void ScheduledActionCommit() override;
-  void ScheduledActionActivateSyncTree() override;
-  void ScheduledActionBeginOutputSurfaceCreation() override;
-  void ScheduledActionPrepareTiles() override;
-  void ScheduledActionInvalidateOutputSurface() override;
-  void SendBeginFramesToChildren(const BeginFrameArgs& args) override;
-  void SendBeginMainFrameNotExpectedSoon() override;
-
-  // ProxyMain implementation
-  void SetChannel(scoped_ptr<ThreadedChannel> threaded_channel) override;
-
- protected:
-  ThreadProxy(LayerTreeHost* layer_tree_host,
-              TaskRunnerProvider* task_runner_provider,
-              scoped_ptr<BeginFrameSource> external_begin_frame_source);
-
- private:
-  friend class ThreadProxyForTest;
-
-  // ProxyMain implementation.
-  base::WeakPtr<ProxyMain> GetMainWeakPtr() override;
-  void DidCompleteSwapBuffers() override;
-  void SetRendererCapabilitiesMainCopy(
-      const RendererCapabilities& capabilities) override;
-  void BeginMainFrameNotExpectedSoon() override;
-  void DidCommitAndDrawFrame() override;
-  void SetAnimationEvents(scoped_ptr<AnimationEventsVector> queue) override;
-  void DidLoseOutputSurface() override;
-  void RequestNewOutputSurface() override;
-  void DidInitializeOutputSurface(
-      bool success,
-      const RendererCapabilities& capabilities) override;
-  void DidCompletePageScaleAnimation() override;
-  void PostFrameTimingEventsOnMain(
-      scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
-      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events)
-      override;
-  void BeginMainFrame(
-      scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) override;
-
-  // ProxyImpl implementation
-  base::WeakPtr<ProxyImpl> GetImplWeakPtr() override;
-  void SetThrottleFrameProductionOnImpl(bool throttle) override;
-  void UpdateTopControlsStateOnImpl(TopControlsState constraints,
-                                    TopControlsState current,
-                                    bool animate) override;
-  void InitializeOutputSurfaceOnImpl(OutputSurface* output_surface) override;
-  void MainThreadHasStoppedFlingingOnImpl() override;
-  void SetInputThrottledUntilCommitOnImpl(bool is_throttled) override;
-  void SetDeferCommitsOnImpl(bool defer_commits) const override;
-  void FinishAllRenderingOnImpl(CompletionEvent* completion) override;
-  void SetVisibleOnImpl(bool visible) override;
-  void ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) override;
-  void FinishGLOnImpl(CompletionEvent* completion) override;
-  void MainFrameWillHappenOnImplForTesting(
-      CompletionEvent* completion,
-      bool* main_frame_will_happen) override;
-  void SetNeedsCommitOnImpl() override;
-  void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) override;
-  void BeginMainFrameAbortedOnImpl(
-      CommitEarlyOutReason reason,
-      base::TimeTicks main_thread_start_time) override;
-  void StartCommitOnImpl(CompletionEvent* completion,
-                         LayerTreeHost* layer_tree_host,
-                         base::TimeTicks main_thread_start_time,
-                         bool hold_commit_for_activation) override;
-  void InitializeImplOnImpl(CompletionEvent* completion,
-                            LayerTreeHost* layer_tree_host) override;
-  void LayerTreeHostClosedOnImpl(CompletionEvent* completion) override;
-
-  // Returns |true| if the request was actually sent, |false| if one was
-  // already outstanding.
-  bool SendCommitRequestToImplThreadIfNeeded(
-      CommitPipelineStage required_stage);
-
-  // Called on impl thread.
-  struct SchedulerStateRequest;
-
-  DrawResult DrawSwapInternal(bool forced_draw);
-
-  TaskRunnerProvider* task_runner_provider_;
-
-  // Use accessors instead of this variable directly.
-  MainThreadOnly main_thread_only_vars_unsafe_;
-  MainThreadOnly& main();
-
-  // Use accessors instead of this variable directly.
-  BlockedMainCommitOnly main_thread_blocked_commit_vars_unsafe_;
-  BlockedMainCommitOnly& blocked_main_commit();
-
-  // Use accessors instead of this variable directly.
-  CompositorThreadOnly compositor_thread_vars_unsafe_;
-  CompositorThreadOnly& impl();
-
-  // TODO(khushalsagar): Remove this. Temporary variable to hold the channel.
-  scoped_ptr<ThreadedChannel> threaded_channel_;
-
-  base::WeakPtr<ThreadProxy> main_thread_weak_ptr_;
-  base::WeakPtr<ThreadProxy> impl_thread_weak_ptr_;
-
-  DISALLOW_COPY_AND_ASSIGN(ThreadProxy);
-};
-
-}  // namespace cc
-
-#endif  // CC_TREES_THREAD_PROXY_H_
diff --git a/cc/trees/threaded_channel.cc b/cc/trees/threaded_channel.cc
index 37ed58f7..3d2eb33 100644
--- a/cc/trees/threaded_channel.cc
+++ b/cc/trees/threaded_channel.cc
@@ -7,222 +7,312 @@
 #include "base/bind.h"
 #include "base/single_thread_task_runner.h"
 #include "base/trace_event/trace_event.h"
+#include "cc/trees/layer_tree_host.h"
 
 namespace cc {
 
-scoped_ptr<ThreadedChannel> ThreadedChannel::Create(
-    ThreadProxy* thread_proxy,
-    TaskRunnerProvider* task_runner_provider) {
-  return make_scoped_ptr(
-      new ThreadedChannel(thread_proxy, task_runner_provider));
+ThreadedChannel::ThreadedChannel(ProxyMain* proxy_main,
+                                 TaskRunnerProvider* task_runner_provider)
+    : task_runner_provider_(task_runner_provider),
+      main_thread_only_vars_unsafe_(proxy_main),
+      compositor_thread_vars_unsafe_(
+          main()
+              .proxy_main_weak_factory.GetWeakPtr()) {
+  DCHECK(IsMainThread());
 }
 
-ThreadedChannel::ThreadedChannel(ThreadProxy* thread_proxy,
-                                 TaskRunnerProvider* task_runner_provider)
-    : proxy_main_(thread_proxy),
-      proxy_impl_(thread_proxy),
-      task_runner_provider_(task_runner_provider) {}
+ThreadedChannel::~ThreadedChannel() {
+  TRACE_EVENT0("cc", "ThreadChannel::~ThreadChannel");
+  DCHECK(IsMainThread());
+  DCHECK(!IsInitialized());
+}
 
 void ThreadedChannel::SetThrottleFrameProductionOnImpl(bool throttle) {
+  DCHECK(IsMainThread());
   ImplThreadTaskRunner()->PostTask(
       FROM_HERE, base::Bind(&ProxyImpl::SetThrottleFrameProductionOnImpl,
-                            proxy_impl_->GetImplWeakPtr(), throttle));
+                            proxy_impl_weak_ptr_, throttle));
 }
 
 void ThreadedChannel::UpdateTopControlsStateOnImpl(TopControlsState constraints,
                                                    TopControlsState current,
                                                    bool animate) {
+  DCHECK(IsMainThread());
   ImplThreadTaskRunner()->PostTask(
       FROM_HERE,
-      base::Bind(&ProxyImpl::UpdateTopControlsStateOnImpl,
-                 proxy_impl_->GetImplWeakPtr(), constraints, current, animate));
+      base::Bind(&ProxyImpl::UpdateTopControlsStateOnImpl, proxy_impl_weak_ptr_,
+                 constraints, current, animate));
 }
 
 void ThreadedChannel::InitializeOutputSurfaceOnImpl(
     OutputSurface* output_surface) {
+  DCHECK(IsMainThread());
   ImplThreadTaskRunner()->PostTask(
       FROM_HERE, base::Bind(&ProxyImpl::InitializeOutputSurfaceOnImpl,
-                            proxy_impl_->GetImplWeakPtr(), output_surface));
+                            proxy_impl_weak_ptr_, output_surface));
 }
 
 void ThreadedChannel::MainThreadHasStoppedFlingingOnImpl() {
+  DCHECK(IsMainThread());
   ImplThreadTaskRunner()->PostTask(
       FROM_HERE, base::Bind(&ProxyImpl::MainThreadHasStoppedFlingingOnImpl,
-                            proxy_impl_->GetImplWeakPtr()));
+                            proxy_impl_weak_ptr_));
 }
 
 void ThreadedChannel::SetInputThrottledUntilCommitOnImpl(bool is_throttled) {
+  DCHECK(IsMainThread());
   ImplThreadTaskRunner()->PostTask(
       FROM_HERE, base::Bind(&ProxyImpl::SetInputThrottledUntilCommitOnImpl,
-                            proxy_impl_->GetImplWeakPtr(), is_throttled));
+                            proxy_impl_weak_ptr_, is_throttled));
 }
 
 void ThreadedChannel::SetDeferCommitsOnImpl(bool defer_commits) {
+  DCHECK(IsMainThread());
   ImplThreadTaskRunner()->PostTask(
       FROM_HERE, base::Bind(&ProxyImpl::SetDeferCommitsOnImpl,
-                            proxy_impl_->GetImplWeakPtr(), defer_commits));
-}
-
-void ThreadedChannel::FinishAllRenderingOnImpl(CompletionEvent* completion) {
-  ImplThreadTaskRunner()->PostTask(
-      FROM_HERE, base::Bind(&ProxyImpl::FinishAllRenderingOnImpl,
-                            proxy_impl_->GetImplWeakPtr(), completion));
+                            proxy_impl_weak_ptr_, defer_commits));
 }
 
 void ThreadedChannel::SetNeedsCommitOnImpl() {
-  ImplThreadTaskRunner()->PostTask(FROM_HERE,
-                                   base::Bind(&ProxyImpl::SetNeedsCommitOnImpl,
-                                              proxy_impl_->GetImplWeakPtr()));
+  DCHECK(IsMainThread());
+  ImplThreadTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&ProxyImpl::SetNeedsCommitOnImpl, proxy_impl_weak_ptr_));
 }
 
 void ThreadedChannel::BeginMainFrameAbortedOnImpl(
     CommitEarlyOutReason reason,
     base::TimeTicks main_thread_start_time) {
+  DCHECK(IsMainThread());
   ImplThreadTaskRunner()->PostTask(
-      FROM_HERE, base::Bind(&ProxyImpl::BeginMainFrameAbortedOnImpl,
-                            proxy_impl_->GetImplWeakPtr(), reason,
-                            main_thread_start_time));
+      FROM_HERE,
+      base::Bind(&ProxyImpl::BeginMainFrameAbortedOnImpl, proxy_impl_weak_ptr_,
+                 reason, main_thread_start_time));
 }
 
 void ThreadedChannel::SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) {
+  DCHECK(IsMainThread());
   ImplThreadTaskRunner()->PostTask(
       FROM_HERE, base::Bind(&ProxyImpl::SetNeedsRedrawOnImpl,
-                            proxy_impl_->GetImplWeakPtr(), damage_rect));
+                            proxy_impl_weak_ptr_, damage_rect));
+}
+
+void ThreadedChannel::SetVisibleOnImpl(bool visible) {
+  DCHECK(IsMainThread());
+  ImplThreadTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&ProxyImpl::SetVisibleOnImpl, proxy_impl_weak_ptr_, visible));
+}
+
+void ThreadedChannel::FinishAllRenderingOnImpl(CompletionEvent* completion) {
+  DCHECK(IsMainThread());
+  ImplThreadTaskRunner()->PostTask(
+      FROM_HERE, base::Bind(&ProxyImpl::FinishAllRenderingOnImpl,
+                            proxy_impl_weak_ptr_, completion));
+}
+
+void ThreadedChannel::ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) {
+  DCHECK(IsMainThread());
+  ImplThreadTaskRunner()->PostTask(
+      FROM_HERE, base::Bind(&ProxyImpl::ReleaseOutputSurfaceOnImpl,
+                            proxy_impl_weak_ptr_, completion));
+}
+
+void ThreadedChannel::MainFrameWillHappenOnImplForTesting(
+    CompletionEvent* completion,
+    bool* main_frame_will_happen) {
+  DCHECK(IsMainThread());
+  ImplThreadTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&ProxyImpl::MainFrameWillHappenOnImplForTesting,
+                 proxy_impl_weak_ptr_, completion, main_frame_will_happen));
 }
 
 void ThreadedChannel::StartCommitOnImpl(CompletionEvent* completion,
                                         LayerTreeHost* layer_tree_host,
                                         base::TimeTicks main_thread_start_time,
                                         bool hold_commit_for_activation) {
+  DCHECK(IsMainThread());
   ImplThreadTaskRunner()->PostTask(
-      FROM_HERE,
-      base::Bind(&ProxyImpl::StartCommitOnImpl, proxy_impl_->GetImplWeakPtr(),
-                 completion, layer_tree_host, main_thread_start_time,
-                 hold_commit_for_activation));
+      FROM_HERE, base::Bind(&ProxyImpl::StartCommitOnImpl, proxy_impl_weak_ptr_,
+                            completion, layer_tree_host, main_thread_start_time,
+                            hold_commit_for_activation));
 }
 
-void ThreadedChannel::InitializeImplOnImpl(CompletionEvent* completion,
-                                           LayerTreeHost* layer_tree_host) {
-  ImplThreadTaskRunner()->PostTask(
-      FROM_HERE,
-      base::Bind(&ProxyImpl::InitializeImplOnImpl,
-                 base::Unretained(proxy_impl_), completion, layer_tree_host));
+void ThreadedChannel::SynchronouslyInitializeImpl(
+    LayerTreeHost* layer_tree_host,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source) {
+  TRACE_EVENT0("cc", "ThreadChannel::SynchronouslyInitializeImpl");
+  DCHECK(IsMainThread());
+  {
+    DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
+    CompletionEvent completion;
+    ImplThreadTaskRunner()->PostTask(
+        FROM_HERE,
+        base::Bind(&ThreadedChannel::InitializeImplOnImpl,
+                   base::Unretained(this), &completion, layer_tree_host,
+                   base::Passed(&external_begin_frame_source)));
+    completion.Wait();
+  }
+  main().initialized = true;
 }
 
-void ThreadedChannel::LayerTreeHostClosedOnImpl(CompletionEvent* completion) {
-  ImplThreadTaskRunner()->PostTask(
-      FROM_HERE, base::Bind(&ProxyImpl::LayerTreeHostClosedOnImpl,
-                            proxy_impl_->GetImplWeakPtr(), completion));
-  proxy_impl_ = nullptr;
-}
+void ThreadedChannel::SynchronouslyCloseImpl() {
+  TRACE_EVENT0("cc", "ThreadChannel::~SynchronouslyCloseImpl");
+  DCHECK(IsMainThread());
 
-void ThreadedChannel::SetVisibleOnImpl(bool visible) {
-  ImplThreadTaskRunner()->PostTask(
-      FROM_HERE, base::Bind(&ProxyImpl::SetVisibleOnImpl,
-                            proxy_impl_->GetImplWeakPtr(), visible));
-}
-
-void ThreadedChannel::ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) {
-  ImplThreadTaskRunner()->PostTask(
-      FROM_HERE, base::Bind(&ProxyImpl::ReleaseOutputSurfaceOnImpl,
-                            proxy_impl_->GetImplWeakPtr(), completion));
-}
-
-void ThreadedChannel::FinishGLOnImpl(CompletionEvent* completion) {
-  ImplThreadTaskRunner()->PostTask(
-      FROM_HERE, base::Bind(&ProxyImpl::FinishGLOnImpl,
-                            proxy_impl_->GetImplWeakPtr(), completion));
-}
-
-void ThreadedChannel::MainFrameWillHappenOnImplForTesting(
-    CompletionEvent* completion,
-    bool* main_frame_will_happen) {
-  ImplThreadTaskRunner()->PostTask(
-      FROM_HERE, base::Bind(&ProxyImpl::MainFrameWillHappenOnImplForTesting,
-                            proxy_impl_->GetImplWeakPtr(), completion,
-                            main_frame_will_happen));
+  // Synchronously finishes pending GL operations and deletes the impl.
+  // The two steps are done as separate post tasks, so that tasks posted
+  // by the GL implementation due to the Finish can be executed by the
+  // renderer before shutting it down.
+  {
+    DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
+    CompletionEvent completion;
+    ImplThreadTaskRunner()->PostTask(
+        FROM_HERE, base::Bind(&ProxyImpl::FinishGLOnImpl, proxy_impl_weak_ptr_,
+                              &completion));
+    completion.Wait();
+  }
+  {
+    DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
+    CompletionEvent completion;
+    ImplThreadTaskRunner()->PostTask(
+        FROM_HERE, base::Bind(&ThreadedChannel::CloseImplOnImpl,
+                              base::Unretained(this), &completion));
+    completion.Wait();
+  }
+  main().proxy_main_weak_factory.InvalidateWeakPtrs();
+  main().initialized = false;
 }
 
 void ThreadedChannel::DidCompleteSwapBuffers() {
+  DCHECK(IsImplThread());
   MainThreadTaskRunner()->PostTask(
       FROM_HERE, base::Bind(&ProxyMain::DidCompleteSwapBuffers,
-                            proxy_main_->GetMainWeakPtr()));
+                            impl().proxy_main_weak_ptr));
 }
 
 void ThreadedChannel::SetRendererCapabilitiesMainCopy(
     const RendererCapabilities& capabilities) {
+  DCHECK(IsImplThread());
   MainThreadTaskRunner()->PostTask(
-      FROM_HERE, base::Bind(&ProxyMain::SetRendererCapabilitiesMainCopy,
-                            proxy_main_->GetMainWeakPtr(), capabilities));
+      FROM_HERE, base::Bind(&ProxyMain::SetRendererCapabilities,
+                            impl().proxy_main_weak_ptr, capabilities));
 }
 
 void ThreadedChannel::BeginMainFrameNotExpectedSoon() {
+  DCHECK(IsImplThread());
   MainThreadTaskRunner()->PostTask(
       FROM_HERE, base::Bind(&ProxyMain::BeginMainFrameNotExpectedSoon,
-                            proxy_main_->GetMainWeakPtr()));
+                            impl().proxy_main_weak_ptr));
 }
 
 void ThreadedChannel::DidCommitAndDrawFrame() {
+  DCHECK(IsImplThread());
   MainThreadTaskRunner()->PostTask(FROM_HERE,
                                    base::Bind(&ProxyMain::DidCommitAndDrawFrame,
-                                              proxy_main_->GetMainWeakPtr()));
+                                              impl().proxy_main_weak_ptr));
 }
 
 void ThreadedChannel::SetAnimationEvents(
     scoped_ptr<AnimationEventsVector> queue) {
+  DCHECK(IsImplThread());
   MainThreadTaskRunner()->PostTask(
-      FROM_HERE,
-      base::Bind(&ProxyMain::SetAnimationEvents, proxy_main_->GetMainWeakPtr(),
-                 base::Passed(&queue)));
+      FROM_HERE, base::Bind(&ProxyMain::SetAnimationEvents,
+                            impl().proxy_main_weak_ptr, base::Passed(&queue)));
 }
 
 void ThreadedChannel::DidLoseOutputSurface() {
-  MainThreadTaskRunner()->PostTask(FROM_HERE,
-                                   base::Bind(&ProxyMain::DidLoseOutputSurface,
-                                              proxy_main_->GetMainWeakPtr()));
+  DCHECK(IsImplThread());
+  MainThreadTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&ProxyMain::DidLoseOutputSurface, impl().proxy_main_weak_ptr));
 }
 
 void ThreadedChannel::RequestNewOutputSurface() {
+  DCHECK(IsImplThread());
   MainThreadTaskRunner()->PostTask(
       FROM_HERE, base::Bind(&ProxyMain::RequestNewOutputSurface,
-                            proxy_main_->GetMainWeakPtr()));
+                            impl().proxy_main_weak_ptr));
 }
 
 void ThreadedChannel::DidInitializeOutputSurface(
     bool success,
     const RendererCapabilities& capabilities) {
+  DCHECK(IsImplThread());
   MainThreadTaskRunner()->PostTask(
-      FROM_HERE,
-      base::Bind(&ProxyMain::DidInitializeOutputSurface,
-                 proxy_main_->GetMainWeakPtr(), success, capabilities));
+      FROM_HERE, base::Bind(&ProxyMain::DidInitializeOutputSurface,
+                            impl().proxy_main_weak_ptr, success, capabilities));
 }
 
 void ThreadedChannel::DidCompletePageScaleAnimation() {
+  DCHECK(IsImplThread());
   MainThreadTaskRunner()->PostTask(
       FROM_HERE, base::Bind(&ProxyMain::DidCompletePageScaleAnimation,
-                            proxy_main_->GetMainWeakPtr()));
+                            impl().proxy_main_weak_ptr));
 }
 
 void ThreadedChannel::PostFrameTimingEventsOnMain(
     scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
     scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) {
+  DCHECK(IsImplThread());
   MainThreadTaskRunner()->PostTask(
       FROM_HERE, base::Bind(&ProxyMain::PostFrameTimingEventsOnMain,
-                            proxy_main_->GetMainWeakPtr(),
+                            impl().proxy_main_weak_ptr,
                             base::Passed(std::move(composite_events)),
                             base::Passed(std::move(main_frame_events))));
 }
 
 void ThreadedChannel::BeginMainFrame(
     scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) {
+  DCHECK(IsImplThread());
   MainThreadTaskRunner()->PostTask(
       FROM_HERE,
-      base::Bind(&ProxyMain::BeginMainFrame, proxy_main_->GetMainWeakPtr(),
+      base::Bind(&ProxyMain::BeginMainFrame, impl().proxy_main_weak_ptr,
                  base::Passed(&begin_main_frame_state)));
 }
 
-ThreadedChannel::~ThreadedChannel() {
-  TRACE_EVENT0("cc", "ThreadChannel::~ThreadChannel");
+ProxyImpl* ThreadedChannel::GetProxyImplForTesting() const {
+  return impl().proxy_impl.get();
+}
+
+scoped_ptr<ProxyImpl> ThreadedChannel::CreateProxyImpl(
+    ChannelImpl* channel_impl,
+    LayerTreeHost* layer_tree_host,
+    TaskRunnerProvider* task_runner_provider,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source) {
+  DCHECK(IsImplThread());
+  return ProxyImpl::Create(channel_impl, layer_tree_host, task_runner_provider,
+                           std::move(external_begin_frame_source));
+}
+
+void ThreadedChannel::InitializeImplOnImpl(
+    CompletionEvent* completion,
+    LayerTreeHost* layer_tree_host,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source) {
+  DCHECK(IsImplThread());
+  impl().proxy_impl =
+      CreateProxyImpl(this, layer_tree_host, task_runner_provider_,
+                      std::move(external_begin_frame_source));
+  impl().proxy_impl_weak_factory = make_scoped_ptr(
+      new base::WeakPtrFactory<ProxyImpl>(impl().proxy_impl.get()));
+  proxy_impl_weak_ptr_ = impl().proxy_impl_weak_factory->GetWeakPtr();
+  completion->Signal();
+}
+
+void ThreadedChannel::CloseImplOnImpl(CompletionEvent* completion) {
+  DCHECK(IsImplThread());
+
+  // We must destroy the factory and ensure that the ProxyImpl weak pointers are
+  // invalidated before destroying proxy_impl.
+  impl().proxy_impl_weak_factory.reset();
+
+  impl().proxy_impl.reset();
+  completion->Signal();
+}
+
+bool ThreadedChannel::IsInitialized() const {
+  return main().initialized;
 }
 
 base::SingleThreadTaskRunner* ThreadedChannel::MainThreadTaskRunner() const {
@@ -233,4 +323,49 @@
   return task_runner_provider_->ImplThreadTaskRunner();
 }
 
+bool ThreadedChannel::IsMainThread() const {
+  return task_runner_provider_->IsMainThread();
+}
+
+bool ThreadedChannel::IsImplThread() const {
+  return task_runner_provider_->IsImplThread();
+}
+
+ThreadedChannel::MainThreadOnly& ThreadedChannel::main() {
+  DCHECK(task_runner_provider_->IsMainThread());
+  return main_thread_only_vars_unsafe_;
+}
+
+const ThreadedChannel::MainThreadOnly& ThreadedChannel::main() const {
+  DCHECK(task_runner_provider_->IsMainThread());
+  return main_thread_only_vars_unsafe_;
+}
+
+ThreadedChannel::CompositorThreadOnly& ThreadedChannel::impl() {
+  DCHECK(task_runner_provider_->IsImplThread());
+  return compositor_thread_vars_unsafe_;
+}
+
+const ThreadedChannel::CompositorThreadOnly& ThreadedChannel::impl() const {
+  DCHECK(task_runner_provider_->IsImplThread());
+  return compositor_thread_vars_unsafe_;
+}
+
+ThreadedChannel::MainThreadOnly::MainThreadOnly(ProxyMain* proxy_main)
+    : proxy_main_weak_factory(proxy_main), initialized(false) {}
+
+ThreadedChannel::MainThreadOnly::~MainThreadOnly() {}
+
+ThreadedChannel::CompositorThreadOnly::CompositorThreadOnly(
+    base::WeakPtr<ProxyMain> proxy_main_weak_ptr)
+    : proxy_main_weak_ptr(proxy_main_weak_ptr) {}
+
+ThreadedChannel::CompositorThreadOnly::~CompositorThreadOnly() {}
+
+scoped_ptr<ThreadedChannel> ThreadedChannel::Create(
+    ProxyMain* proxy_main,
+    TaskRunnerProvider* task_runner_provider) {
+  return make_scoped_ptr(new ThreadedChannel(proxy_main, task_runner_provider));
+}
+
 }  // namespace cc
diff --git a/cc/trees/threaded_channel.h b/cc/trees/threaded_channel.h
index ca7fc04..5d10f4af 100644
--- a/cc/trees/threaded_channel.h
+++ b/cc/trees/threaded_channel.h
@@ -7,13 +7,13 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
 #include "cc/base/cc_export.h"
 #include "cc/trees/channel_impl.h"
 #include "cc/trees/channel_main.h"
 #include "cc/trees/proxy_common.h"
 #include "cc/trees/proxy_impl.h"
 #include "cc/trees/proxy_main.h"
-#include "cc/trees/thread_proxy.h"
 
 namespace base {
 class SingleThreadTaskRunner;
@@ -22,9 +22,9 @@
 namespace cc {
 class ChannelImpl;
 class ChannelMain;
+class LayerTreeHost;
 class ProxyImpl;
 class ProxyMain;
-class ThreadProxy;
 
 // An implementation of ChannelMain and ChannelImpl that sends commands between
 // ProxyMain and ProxyImpl across thread boundaries.
@@ -39,8 +39,8 @@
 //        ProxyMain->Start()          |
 //               |              ThreadedChannel
 // ---------------------------------------------------------------------------
-//  ChannelMain::InitializeImpl ---PostTask---> ThreadedChannel::
-//                                                   InitializeImplOnImplThread
+//  ChannelMain::SynchronouslyInitializeImpl ---PostTask---> ThreadedChannel::
+//                                                    InitializeImplOnImpl
 //                                                          |
 //                                                   ProxyImpl::Create
 //                                                          |
@@ -56,20 +56,27 @@
 // ProxyMain->RequestNewOutputSurface()<----PostTask--------
 //              .
 //              .
-// ProxyMain->LayerTreeHostClosed
+// ProxyMain->Stop()
 //              |
 // ---------------------------------------------------------------------------
-// ChannelMain::SetLayerTreeClosedOnImpl---PostTask---> ProxyImpl->
-//                                                        SetLayerTreeClosed
+// ChannelMain::SynchronouslyCloseImpl ---PostTask---> ThreadedChannel::
+//                                                      CloseImplOnImpl
 // ----------------------------------------------------------------------------
+//
+// ThreadedChannel is created and destroyed on the main thread but can be
+// called from main or impl thread. It is safe for the Threadedchannel to be
+// called on the impl thread because:
+// 1) The only impl-threaded callers of ThreadedChannel are the ThreadedChannel
+// itself and ProxyImpl which is created and owned by the ThreadedChannel.
+// 2) ThreadedChannel blocks the main thread in
+// ThreadedChannel::SynchronouslyCloseImpl to wait for the impl-thread teardown
+// to complete, so there is no risk of any queued tasks calling it on the impl
+// thread after it has been deleted on the main thread.
 
 class CC_EXPORT ThreadedChannel : public ChannelMain, public ChannelImpl {
  public:
   static scoped_ptr<ThreadedChannel> Create(
-      // TODO(khushalsagar): Make this ProxyMain* and write the initialization
-      // sequence. Currently ThreadProxy implements both so we pass the pointer
-      // and set ProxyImpl.
-      ThreadProxy* thread_proxy,
+      ProxyMain* proxy_main,
       TaskRunnerProvider* task_runner_provider);
 
   ~ThreadedChannel() override;
@@ -93,7 +100,6 @@
   // Blocking calls to ProxyImpl
   void FinishAllRenderingOnImpl(CompletionEvent* completion) override;
   void ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) override;
-  void FinishGLOnImpl(CompletionEvent* completion) override;
   void MainFrameWillHappenOnImplForTesting(
       CompletionEvent* completion,
       bool* main_frame_will_happen) override;
@@ -101,9 +107,10 @@
                          LayerTreeHost* layer_tree_host,
                          base::TimeTicks main_thread_start_time,
                          bool hold_commit_for_activation) override;
-  void InitializeImplOnImpl(CompletionEvent* completion,
-                            LayerTreeHost* layer_tree_host) override;
-  void LayerTreeHostClosedOnImpl(CompletionEvent* completion) override;
+  void SynchronouslyInitializeImpl(
+      LayerTreeHost* layer_tree_host,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source) override;
+  void SynchronouslyCloseImpl() override;
 
   // ChannelImpl Implementation
   void DidCompleteSwapBuffers() override;
@@ -125,23 +132,84 @@
   void BeginMainFrame(
       scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) override;
 
+  // Should be called on impl thread only.
+  ProxyImpl* GetProxyImplForTesting() const;
+
  protected:
-  ThreadedChannel(ThreadProxy* thread_proxy,
+  ThreadedChannel(ProxyMain* proxy_main,
                   TaskRunnerProvider* task_runner_provider);
 
+  // Virtual for testing.
+  virtual scoped_ptr<ProxyImpl> CreateProxyImpl(
+      ChannelImpl* channel_impl,
+      LayerTreeHost* layer_tree_host,
+      TaskRunnerProvider* task_runner_provider,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source);
+
  private:
+  // The members of this struct should be accessed on the main thread only.
+  struct MainThreadOnly {
+    explicit MainThreadOnly(ProxyMain* proxy_main);
+    ~MainThreadOnly();
+
+    base::WeakPtrFactory<ProxyMain> proxy_main_weak_factory;
+    bool initialized;
+  };
+
+  // The members of this struct should be accessed on the impl thread only.
+  struct CompositorThreadOnly {
+    explicit CompositorThreadOnly(base::WeakPtr<ProxyMain> proxy_main_weak_ptr);
+    ~CompositorThreadOnly();
+
+    scoped_ptr<ProxyImpl> proxy_impl;
+
+    // We use a scoped_ptr for the weak ptr factory here since the factory is
+    // created after ProxyImpl is created in InitializeImplOnImpl. Since the
+    // weak ptrs are needed only by the ThreadedChannel to safely post tasks on
+    // ProxyImpl to be run on the impl thread, we avoid creating it in ProxyImpl
+    // and ensure that it is destroyed before ProxyImpl during the impl-thread
+    // tear down in CloseImplOnImpl.
+    scoped_ptr<base::WeakPtrFactory<ProxyImpl>> proxy_impl_weak_factory;
+
+    // Used on the impl thread to queue calls to ProxyMain to be run on the main
+    // thread. Since the weak pointer is invalidated after the impl-thread tear
+    // down in SynchronouslyCloseImpl, this ensures that any tasks posted to
+    // ProxyMain from the impl thread are abandoned after the impl side has been
+    // destroyed.
+    base::WeakPtr<ProxyMain> proxy_main_weak_ptr;
+  };
+
+  // Called on impl thread.
+  void InitializeImplOnImpl(
+      CompletionEvent* completion,
+      LayerTreeHost* layer_tree_host,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source);
+  void CloseImplOnImpl(CompletionEvent* completion);
+
+  bool IsInitialized() const;
+
   base::SingleThreadTaskRunner* MainThreadTaskRunner() const;
   base::SingleThreadTaskRunner* ImplThreadTaskRunner() const;
-
-  ProxyMain* proxy_main_;
-
-  ProxyImpl* proxy_impl_;
+  bool IsMainThread() const;
+  bool IsImplThread() const;
 
   TaskRunnerProvider* task_runner_provider_;
 
-  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+  MainThreadOnly& main();
+  const MainThreadOnly& main() const;
 
-  scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner_;
+  CompositorThreadOnly& impl();
+  const CompositorThreadOnly& impl() const;
+
+  // Use accessors instead of this variable directly.
+  MainThreadOnly main_thread_only_vars_unsafe_;
+
+  // Use accessors instead of this variable directly.
+  CompositorThreadOnly compositor_thread_vars_unsafe_;
+
+  // Used on the main thread to safely queue calls to ProxyImpl to be run on the
+  // impl thread.
+  base::WeakPtr<ProxyImpl> proxy_impl_weak_ptr_;
 
   DISALLOW_COPY_AND_ASSIGN(ThreadedChannel);
 };
diff --git a/cc/trees/threaded_channel_unittest.cc b/cc/trees/threaded_channel_unittest.cc
index 152ff59..17350d84 100644
--- a/cc/trees/threaded_channel_unittest.cc
+++ b/cc/trees/threaded_channel_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -13,13 +13,12 @@
 // The ThreadedChannel tests are run only for threaded and direct mode.
 class ThreadedChannelTest : public LayerTreeTest {
  protected:
-  ThreadedChannelTest() : thread_proxy_(nullptr), calls_received_(0) {}
+  ThreadedChannelTest() : calls_received_(0) {}
 
   ~ThreadedChannelTest() override {}
 
   void BeginTest() override {
     DCHECK(HasImplThread());
-    thread_proxy_ = static_cast<ThreadProxy*>(proxy());
     BeginChannelTest();
   };
   virtual void BeginChannelTest() {}
@@ -36,9 +35,6 @@
 
   void AfterTest() override {}
 
-  // TODO(khushalsagar): Remove this once ProxyImpl is added to the
-  // LayerTreeTest.
-  ThreadProxy* thread_proxy_;
   int calls_received_;
 
  private:
@@ -47,8 +43,6 @@
 
 class ThreadedChannelTestInitializationAndShutdown
     : public ThreadedChannelTest {
-  void InitializeImplOnImpl() override { calls_received_++; }
-
   void SetVisibleOnImpl(bool visible) override { calls_received_++; }
 
   void ReceivedRequestNewOutputSurface() override { calls_received_++; }
@@ -69,10 +63,9 @@
     EndTest();
   }
 
-  void WillCloseLayerTreeHostOnImpl() override { calls_received_++; }
   void FinishGLOnImpl() override { calls_received_++; }
 
-  void AfterTest() override { EXPECT_EQ(8, calls_received_); }
+  void AfterTest() override { EXPECT_EQ(6, calls_received_); }
 };
 
 MULTI_THREAD_DIRECT_RENDERER_TEST_F(
@@ -246,7 +239,7 @@
   void BeginChannelTest() override { PostOnImplThread(); }
 
   void StartTestOnImplThread() override {
-    thread_proxy_->SendBeginMainFrameNotExpectedSoon();
+    GetProxyImplForTest()->SendBeginMainFrameNotExpectedSoon();
   }
 
   void ReceivedBeginMainFrameNotExpectedSoon() override {
@@ -266,7 +259,7 @@
   void StartTestOnImplThread() override {
     scoped_ptr<AnimationEventsVector> events(
         make_scoped_ptr(new AnimationEventsVector));
-    thread_proxy_->PostAnimationEventsToMainThreadOnImplThread(
+    GetProxyImplForTest()->PostAnimationEventsToMainThreadOnImplThread(
         std::move(events));
   }
 
@@ -284,7 +277,7 @@
   void BeginChannelTest() override { PostOnImplThread(); }
 
   void StartTestOnImplThread() override {
-    thread_proxy_->DidLoseOutputSurfaceOnImplThread();
+    GetProxyImplForTest()->DidLoseOutputSurfaceOnImplThread();
   }
 
   void ReceivedDidLoseOutputSurface() override {
@@ -301,7 +294,7 @@
   void BeginChannelTest() override { PostOnImplThread(); }
 
   void StartTestOnImplThread() override {
-    thread_proxy_->DidCompletePageScaleAnimationOnImplThread();
+    GetProxyImplForTest()->DidCompletePageScaleAnimationOnImplThread();
   }
 
   void ReceivedDidCompletePageScaleAnimation() override {
diff --git a/chrome/VERSION b/chrome/VERSION
index 5a58ebfa..766590e 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=49
 MINOR=0
-BUILD=2586
+BUILD=2587
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java
index ad45b6dd..2f6227b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java
@@ -130,6 +130,7 @@
         // Start or stop Physical Web
         if (PhysicalWeb.featureIsEnabled()) {
             PhysicalWeb.startPhysicalWeb(application);
+            PhysicalWeb.uploadDeferredMetrics(application);
         } else {
             PhysicalWeb.stopPhysicalWeb(application);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
index f52eadee..e1de1a05 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -13,6 +13,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v4.view.ViewCompat;
+import android.support.v4.view.accessibility.AccessibilityEventCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
 import android.support.v4.widget.ExploreByTouchHelper;
 import android.util.AttributeSet;
@@ -1017,6 +1018,8 @@
     @Override
     public void invalidateAccessibilityProvider() {
         if (mNodeProvider != null) {
+            mNodeProvider.sendEventForVirtualView(mNodeProvider.getFocusedVirtualView(),
+                    AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
             mNodeProvider.invalidateRoot();
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java
index 6e00e54..02c6cd3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java
@@ -815,6 +815,15 @@
     }
 
     /**
+     * Called when the TabModelSelector has been initialized with an accurate tab count.
+     */
+    public void onTabStateInitialized() {
+        for (int i = 0; i < mSceneOverlays.size(); i++) {
+            mSceneOverlays.get(i).tabStateInitialized();
+        }
+    }
+
+    /**
      * Called when the current tabModel switched (e.g. standard -> incognito).
      *
      * @param incognito True if the new model is incognito.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java
index c37a9d9..7885266 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java
@@ -7,6 +7,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.os.Handler;
 import android.os.SystemClock;
 import android.view.MotionEvent;
 import android.view.View;
@@ -30,6 +31,7 @@
 import org.chromium.chrome.browser.dom_distiller.ReaderModeManagerDelegate;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
 import org.chromium.chrome.browser.fullscreen.FullscreenManager;
+import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.content.browser.SPenSupport;
@@ -245,6 +247,8 @@
         mContentContainer = androidContentContainer;
 
         if (mNextActiveLayout != null) startShowing(mNextActiveLayout, true);
+
+        updateLayoutForTabModelSelector();
     }
 
     /**
@@ -525,4 +529,30 @@
             return Orientation.PORTRAIT;
         }
     }
+
+    /**
+     * Updates the Layout for the state of the {@link TabModelSelector} after initialization.
+     * If the TabModelSelector is not yet initialized when this function is called, a
+     * {@link TabModelSelectorObserver} is created to listen for when it is ready.
+     */
+    private void updateLayoutForTabModelSelector() {
+        if (mTabModelSelector.isTabStateInitialized() && getActiveLayout() != null) {
+            getActiveLayout().onTabStateInitialized();
+        } else {
+            mTabModelSelector.addObserver(new EmptyTabModelSelectorObserver() {
+                @Override
+                public void onTabStateInitialized() {
+                    if (getActiveLayout() != null) getActiveLayout().onTabStateInitialized();
+
+                    final EmptyTabModelSelectorObserver observer = this;
+                    new Handler().post(new Runnable() {
+                        @Override
+                        public void run() {
+                            mTabModelSelector.removeObserver(observer);
+                        }
+                    });
+                }
+            });
+        }
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/SceneOverlay.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/SceneOverlay.java
index e1538bf..4054eb1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/SceneOverlay.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/SceneOverlay.java
@@ -65,6 +65,11 @@
     void tabTitleChanged(int tabId, String title);
 
     /**
+     * Called when the TabModelSelector has been initialized with an accurate tab count.
+     */
+    void tabStateInitialized();
+
+    /**
      * Called when the active {@link TabModel} switched (e.g. standard -> incognito).
      * @param incognito Whether or not the new active model is incognito.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
index 04b3383..40a07c4fc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
@@ -1028,6 +1028,9 @@
                 break;
             }
         }
+
+        // 8. Invalidate the accessibility provider in case the visible virtual views have changed.
+        mRenderHost.invalidateAccessibilityProvider();
     }
 
     private void computeTabInitialPositions() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
index 4586b755..b2f8d463 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
@@ -235,6 +235,11 @@
     }
 
     @Override
+    public void tabStateInitialized() {
+        updateModelSwitcherButton();
+    }
+
+    @Override
     public void tabModelSwitched(boolean incognito) {
         if (incognito == mIsIncognito) return;
         mIsIncognito = incognito;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
index de57765..dd7c76d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
@@ -36,6 +36,11 @@
     @VisibleForTesting
     static final String DISABLE_AUTO_DETECT_TRANSLATION_ONEBOX =
             "disable_auto_detect_translation_onebox";
+    static final String DISABLE_KEYBOARD_LANGUAGES_FOR_TRANSLATION =
+            "disable_keyboard_languages_for_translation";
+    static final String DISABLE_ACCEPT_LANGUAGES_FOR_TRANSLATION =
+            "disable_accept_languages_for_translation";
+    static final String ENABLE_ENGLISH_TARGET_TRANSLATION = "enable_english_target_translation";
 
     // Cached values to avoid repeated and redundant JNI operations.
     private static Boolean sEnabled;
@@ -43,6 +48,9 @@
     private static Integer sPeekPromoMaxCount;
     private static Boolean sDisableForceTranslationOnebox;
     private static Boolean sDisableAutoDetectTranslationOnebox;
+    private static Boolean sDisableAcceptLanguagesForTranslation;
+    private static Boolean sDisableKeyboardLanguagesForTranslation;
+    private static Boolean sEnableEnglishTaregetTranslation;
 
     /**
      * Don't instantiate.
@@ -155,6 +163,38 @@
         return sDisableAutoDetectTranslationOnebox.booleanValue();
     }
 
+    /**
+     * @return Whether considering accept-languages for translation is disabled.
+     */
+    static boolean disableAcceptLanguagesForTranslation() {
+        if (sDisableAcceptLanguagesForTranslation == null) {
+            sDisableAcceptLanguagesForTranslation = getBooleanParam(
+                    DISABLE_ACCEPT_LANGUAGES_FOR_TRANSLATION);
+        }
+        return sDisableAcceptLanguagesForTranslation.booleanValue();
+    }
+
+    /**
+     * @return Whether considering keyboards for translation is disabled.
+     */
+    static boolean disableKeyboardLanguagesForTranslation() {
+        if (sDisableKeyboardLanguagesForTranslation == null) {
+            sDisableKeyboardLanguagesForTranslation =
+                    getBooleanParam(DISABLE_KEYBOARD_LANGUAGES_FOR_TRANSLATION);
+        }
+        return sDisableKeyboardLanguagesForTranslation.booleanValue();
+    }
+
+    /**
+     * @return Whether English-target translation should be enabled (default is disabled for 'en').
+     */
+    static boolean enableEnglishTargetTranslation() {
+        if (sEnableEnglishTaregetTranslation == null) {
+            sEnableEnglishTaregetTranslation = getBooleanParam(ENABLE_ENGLISH_TARGET_TRANSLATION);
+        }
+        return sEnableEnglishTaregetTranslation.booleanValue();
+    }
+
     // --------------------------------------------------------------------------------------------
     // Helpers.
     // --------------------------------------------------------------------------------------------
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 53d60dd..742ea2b 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
@@ -190,7 +190,8 @@
         mTabModelObserver = new EmptyTabModelObserver() {
             @Override
             public void didSelectTab(Tab tab, TabSelectionType type, int lastId) {
-                if (!mIsPromotingToTab && tab.getId() != lastId) {
+                if (!mIsPromotingToTab && tab.getId() != lastId
+                        || mActivity.getTabModelSelector().isIncognitoSelected()) {
                     hideContextualSearch(StateChangeReason.UNKNOWN);
                 }
             }
@@ -333,6 +334,13 @@
     }
 
     /**
+     * Notifies that the base page has started loading a page.
+     */
+    public void onBasePageLoadStarted() {
+        mSelectionController.onBasePageLoadStarted();
+    }
+
+    /**
      * Hides the Contextual Search UX.
      * @param reason The {@link StateChangeReason} for hiding Contextual Search.
      */
@@ -346,24 +354,9 @@
 
     @Override
     public void onCloseContextualSearch(StateChangeReason reason) {
-        // If the user explicitly closes the panel after establishing a selection with long press,
-        // it should not reappear until a new selection is made. This prevents the panel from
-        // reappearing when a long press selection is modified after the user has taken action to
-        // get rid of the panel. See crbug.com/489461.
-        if (shouldPreventHandlingCurrentSelectionModification(reason)) {
-            mSelectionController.preventHandlingCurrentSelectionModification();
-        }
-
         if (mSearchPanel == null) return;
 
-        // NOTE(pedrosimonetti): hideContextualSearch() will also be called after swiping the
-        // Panel down in order to dismiss it. In this case, hideContextualSearch() will be called
-        // after completing the hide animation, and at that moment the Panel will not be showing
-        // anymore. Therefore, we need to always clear selection, regardless of when the Panel
-        // was still visible, in order to make sure the selection will be cleared appropriately.
-        if (mSelectionController.getSelectionType() == SelectionType.TAP) {
-            mSelectionController.clearSelection();
-        }
+        mSelectionController.onSearchEnded(reason);
 
         // Show the infobar container if it was visible before Contextual Search was shown.
         if (mWereInfoBarsHidden) {
@@ -400,20 +393,6 @@
     }
 
     /**
-     * Returns true if the StateChangeReason corresponds to an explicit action used to close
-     * the Contextual Search panel.
-     * @param reason The reason the panel is closing.
-     */
-    private boolean shouldPreventHandlingCurrentSelectionModification(StateChangeReason reason) {
-        return mSelectionController.getSelectionType() == SelectionType.LONG_PRESS
-                && (reason == StateChangeReason.BACK_PRESS
-                || reason == StateChangeReason.BASE_PAGE_SCROLL
-                || reason == StateChangeReason.SWIPE
-                || reason == StateChangeReason.FLING
-                || reason == StateChangeReason.CLOSE_BUTTON);
-    }
-
-    /**
      * Called when the system back button is pressed. Will hide the layout.
      */
     public boolean onBackPressed() {
@@ -829,10 +808,12 @@
         // 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();
-        if (context != null) {
-            for (String locale : UiUtils.getIMELocales(context)) {
-                uniqueLanguages.add(trimLocaleToLanguage(locale));
+        if (!ContextualSearchFieldTrial.disableKeyboardLanguagesForTranslation()) {
+            Context context = mActivity.getApplicationContext();
+            if (context != null) {
+                for (String locale : UiUtils.getIMELocales(context)) {
+                    uniqueLanguages.add(trimLocaleToLanguage(locale));
+                }
             }
         }
         return uniqueLanguages;
@@ -843,10 +824,12 @@
      * @return The {@link List} of languages the user understands or does not want translated.
      */
     private List<String> getAcceptLanguages() {
-        String acceptLanguages = getNativeAcceptLanguages();
         List<String> result = new ArrayList<String>();
-        for (String language : acceptLanguages.split(",")) {
-            result.add(language);
+        if (!ContextualSearchFieldTrial.disableAcceptLanguagesForTranslation()) {
+            String acceptLanguages = getNativeAcceptLanguages();
+            for (String language : acceptLanguages.split(",")) {
+                result.add(language);
+            }
         }
         return result;
     }
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 54d19a2e..fe9aac6f 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
@@ -458,7 +458,8 @@
         // 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 (targetLanguages.size() > 1
-                && TextUtils.equals(targetLanguages.get(0), Locale.ENGLISH.getLanguage())) {
+                && TextUtils.equals(targetLanguages.get(0), Locale.ENGLISH.getLanguage())
+                && !ContextualSearchFieldTrial.enableEnglishTargetTranslation()) {
             return targetLanguages.get(1);
         } else if (targetLanguages.size() > 0) {
             return targetLanguages.get(0);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
index a57241f..2f1d31a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
@@ -8,6 +8,7 @@
 
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content_public.browser.GestureStateListener;
@@ -109,6 +110,32 @@
     }
 
     /**
+     * Notifies that the base page has started loading a page.
+     */
+    void onBasePageLoadStarted() {
+        resetAllStates();
+    }
+
+    /**
+     * Notifies that the Contextual Search has ended.
+     * @param reason The reason for ending the Contextual Search.
+     */
+    void onSearchEnded(OverlayPanel.StateChangeReason reason) {
+        // If the user explicitly closes the panel after establishing a selection with long press,
+        // it should not reappear until a new selection is made. This prevents the panel from
+        // reappearing when a long press selection is modified after the user has taken action to
+        // get rid of the panel. See crbug.com/489461.
+        if (shouldPreventHandlingCurrentSelectionModification(reason)) {
+            preventHandlingCurrentSelectionModification();
+        }
+
+        // Long press selections should remain visible after ending a Contextual Search.
+        if (getSelectionType() == SelectionType.TAP) {
+            clearSelection();
+        }
+    }
+
+    /**
      * Returns a new {@code GestureStateListener} that will listen for events in the Base Page.
      * This listener will handle all Contextual Search-related interactions that go through the
      * listener.
@@ -118,15 +145,6 @@
     }
 
     /**
-     * Temporarily prevents the controller from handling selection modification events on the
-     * current selection. Handling will be re-enabled when a new selection is made through either a
-     * tap or long press.
-     */
-    public void preventHandlingCurrentSelectionModification() {
-        mShouldHandleSelectionModification = false;
-    }
-
-    /**
      * @return the type of the selection.
      */
     SelectionType getSelectionType() {
@@ -364,6 +382,33 @@
     }
 
     /**
+     * This method checks whether the selection modification should be handled. This method
+     * is needed to allow modifying selections that are occluded by the Panel.
+     * See crbug.com/489461.
+     *
+     * @param reason The reason the panel is closing.
+     * @return Whether the selection modification should be handled.
+     */
+    private boolean shouldPreventHandlingCurrentSelectionModification(
+            OverlayPanel.StateChangeReason reason) {
+        return getSelectionType() == SelectionType.LONG_PRESS
+                && (reason == OverlayPanel.StateChangeReason.BACK_PRESS
+                || reason == OverlayPanel.StateChangeReason.BASE_PAGE_SCROLL
+                || reason == OverlayPanel.StateChangeReason.SWIPE
+                || reason == OverlayPanel.StateChangeReason.FLING
+                || reason == OverlayPanel.StateChangeReason.CLOSE_BUTTON);
+    }
+
+    /**
+     * Temporarily prevents the controller from handling selection modification events on the
+     * current selection. Handling will be re-enabled when a new selection is made through either a
+     * tap or long press.
+     */
+    private void preventHandlingCurrentSelectionModification() {
+        mShouldHandleSelectionModification = false;
+    }
+
+    /**
      * @return whether a tap gesture has been detected, for testing.
      */
     @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTabHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTabHelper.java
index 4081bf2..35fcb9d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTabHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTabHelper.java
@@ -71,6 +71,11 @@
         // Add Contextual Search here in case it couldn't get added in onContentChanged() due to
         // being too early in initialization of Chrome (ContextualSearchManager being null).
         setContextualSearchHooks(mBaseContentViewCore);
+
+        ContextualSearchManager manager = getContextualSearchManager();
+        if (manager != null) {
+            manager.onBasePageLoadStarted();
+        }
     }
 
     @Override
@@ -100,12 +105,9 @@
 
     @Override
     public void onToggleFullscreenMode(Tab tab, boolean enable) {
-        ContentViewCore cvc = tab.getContentViewCore();
-        if (cvc != null) {
-            ContextualSearchManager manager = getContextualSearchManager(cvc);
-            if (manager != null) {
-                manager.hideContextualSearch(StateChangeReason.UNKNOWN);
-            }
+        ContextualSearchManager manager = getContextualSearchManager();
+        if (manager != null) {
+            manager.hideContextualSearch(StateChangeReason.UNKNOWN);
         }
     }
 
@@ -141,9 +143,9 @@
      */
     private void addContextualSearchHooks(ContentViewCore cvc) {
         if (mGestureStateListener == null) {
-            mGestureStateListener = getContextualSearchManager(cvc).getGestureStateListener();
+            mGestureStateListener = getContextualSearchManager().getGestureStateListener();
             cvc.addGestureStateListener(mGestureStateListener);
-            cvc.setContextualSearchClient(getContextualSearchManager(cvc));
+            cvc.setContextualSearchClient(getContextualSearchManager());
             TemplateUrlService.getInstance().addObserver(mTemplateUrlObserver);
         }
     }
@@ -167,20 +169,23 @@
      * @return whether Contextual Search is enabled and active in this tab.
      */
     private boolean isContextualSearchActive(ContentViewCore cvc) {
-        return !cvc.getWebContents().isIncognito() && getContextualSearchManager(cvc) != null
+        ContextualSearchManager manager = getContextualSearchManager();
+        if (manager == null) return false;
+
+        return !cvc.getWebContents().isIncognito()
             && !PrefServiceBridge.getInstance().isContextualSearchDisabled()
             && TemplateUrlService.getInstance().isDefaultSearchEngineGoogle()
             // Svelte and Accessibility devices are incompatible with the first-run flow and
             // Talkback has poor interaction with tap to search (see http://crbug.com/399708 and
             // http://crbug.com/396934).
             // TODO(jeremycho): Handle these cases.
-            && !getContextualSearchManager(cvc).isRunningInCompatibilityMode();
+            && !manager.isRunningInCompatibilityMode();
     }
 
     /**
      * @return the Contextual Search manager.
      */
-    private ContextualSearchManager getContextualSearchManager(ContentViewCore cvc) {
+    private ContextualSearchManager getContextualSearchManager() {
         Activity activity = mTab.getWindowAndroid().getActivity().get();
         if (activity instanceof ChromeActivity) {
             return ((ChromeActivity) activity).getContextualSearchManager();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index cd91a1b..e58462f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -277,8 +277,10 @@
     }
 
     private void recordClientPackageName() {
-        final String packageName = CustomTabsConnection.getInstance(getApplication())
+        String clientName = CustomTabsConnection.getInstance(getApplication())
                 .getClientPackageNameForSession(mSession);
+        if (TextUtils.isEmpty(clientName)) clientName = mIntentDataProvider.getClientPackageName();
+        final String packageName = clientName;
         if (TextUtils.isEmpty(packageName) || packageName.contains(getPackageName())) return;
         ThreadUtils.runOnUiThread(new Runnable() {
             @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentActivity.java
index 7cc578f4..0e06062 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentActivity.java
@@ -575,7 +575,7 @@
 
         mDocumentTab = DocumentTab.create(DocumentActivity.this, isIncognito(), getWindowAndroid(),
                 determineLastKnownUrl(), asyncParams != null ? asyncParams.getWebContents() : null,
-                tabState, isAffiliated);
+                tabState, isAffiliated, getTabCreationState(tabState != null, isAffiliated));
 
         if (asyncParams != null && asyncParams.getWebContents() != null) {
             Intent parentIntent = IntentUtils.safeGetParcelableExtra(getIntent(),
@@ -591,12 +591,7 @@
 
         getTabModelSelector().setTab(mDocumentTab);
 
-        TabCreationState creationState = isAffiliated
-                ? (SysUtils.isLowEndDevice() ? TabCreationState.FROZEN_FOR_LAZY_LOAD
-                        : TabCreationState.LIVE_IN_BACKGROUND)
-                        : TabCreationState.LIVE_IN_FOREGROUND;
-
-        if (!mDocumentTab.didRestoreState()
+        if (mDocumentTab.didFailToRestore()
                 || (asyncParams != null && asyncParams.getLoadUrlParams().getUrl() != null)) {
             if (!isCreatedWithWebContents) {
                 // Don't load tabs in the background on low end devices. We will call
@@ -619,10 +614,7 @@
             }
             mDocumentTab.setShouldPreserve(IntentUtils.safeGetBooleanExtra(getIntent(),
                     IntentHandler.EXTRA_PRESERVE_TASK, false));
-        } else {
-            creationState = TabCreationState.FROZEN_ON_RESTORE;
         }
-        mDocumentTab.initializeTabUma(creationState);
 
         ToolbarControlContainer controlContainer =
                 (ToolbarControlContainer) findViewById(R.id.control_container);
@@ -745,6 +737,19 @@
         return (TabDelegate) super.getTabCreator(incognito);
     }
 
+    /**
+     * This cannot return {@link TabCreationState#FROZEN_ON_RESTORE_FAILED} since the Tab has
+     * to be created first to even attempt restore.
+     */
+    private TabCreationState getTabCreationState(boolean hasTabState, boolean isAffiliated) {
+        if (hasTabState) return TabCreationState.FROZEN_ON_RESTORE;
+        if (isAffiliated) {
+            if (SysUtils.isLowEndDevice()) return TabCreationState.FROZEN_FOR_LAZY_LOAD;
+            return TabCreationState.LIVE_IN_BACKGROUND;
+        }
+        return TabCreationState.LIVE_IN_FOREGROUND;
+    }
+
     @Override
     public void createContextualSearchTab(String searchUrl) {
         AsyncTabCreationParams asyncParams =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentTab.java b/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentTab.java
index 8108442b..c18cb36 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentTab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentTab.java
@@ -4,8 +4,6 @@
 
 package org.chromium.chrome.browser.document;
 
-import android.app.Activity;
-
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeApplication;
 import org.chromium.chrome.browser.IntentHandler;
@@ -15,7 +13,6 @@
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
-import org.chromium.chrome.browser.tab.TabUma;
 import org.chromium.chrome.browser.tab.TabUma.TabCreationState;
 import org.chromium.chrome.browser.tab.TabWebContentsDelegateAndroid;
 import org.chromium.chrome.browser.tabmodel.TabModel;
@@ -28,8 +25,6 @@
  * A Tab child class with Chrome documents specific functionality.
  */
 public class DocumentTab extends Tab {
-    private boolean mDidRestoreState;
-
     /**
      * Standard constructor for the document tab.
      * @param activity The document activity that will hold on to this tab.
@@ -40,9 +35,9 @@
      * @param initiallyHidden Whether or not the {@link WebContents} should be initially hidden.
      */
     private DocumentTab(DocumentActivity activity, boolean incognito, WindowAndroid windowAndroid,
-            String url, int parentTabId, boolean initiallyHidden) {
+            String url, int parentTabId, boolean initiallyHidden, TabCreationState creationState) {
         super(ActivityDelegate.getTabIdFromIntent(activity.getIntent()), parentTabId, incognito,
-                activity, windowAndroid, TabLaunchType.FROM_EXTERNAL_APP, null, null);
+                activity, windowAndroid, TabLaunchType.FROM_EXTERNAL_APP, creationState, null);
         initialize(url, null, activity.getTabContentManager(), false, initiallyHidden);
     }
 
@@ -56,9 +51,10 @@
      * @param parentTabId The id of the parent tab.
      */
     private DocumentTab(DocumentActivity activity, boolean incognito,
-            WindowAndroid windowAndroid, String url, TabState tabState, int parentTabId) {
+            WindowAndroid windowAndroid, String url, TabState tabState, int parentTabId,
+            TabCreationState creationState) {
         super(ActivityDelegate.getTabIdFromIntent(activity.getIntent()), parentTabId, incognito,
-                activity, windowAndroid, TabLaunchType.FROM_RESTORE,  null, tabState);
+                activity, windowAndroid, TabLaunchType.FROM_RESTORE,  creationState, tabState);
         initialize(url, null, activity.getTabContentManager(), true, false);
     }
 
@@ -72,9 +68,11 @@
      * @param webContents An optional {@link WebContents} object to use.
      */
     private DocumentTab(DocumentActivity activity, boolean incognito,
-            WindowAndroid windowAndroid, String url, int parentTabId, WebContents webContents) {
+            WindowAndroid windowAndroid, String url, int parentTabId, WebContents webContents,
+            TabCreationState creationState) {
         super(ActivityDelegate.getTabIdFromIntent(activity.getIntent()), parentTabId, incognito,
-                activity, windowAndroid, TabLaunchType.FROM_LONGPRESS_FOREGROUND, null, null);
+                activity, windowAndroid, TabLaunchType.FROM_LONGPRESS_FOREGROUND,
+                creationState, null);
         initialize(url, webContents, activity.getTabContentManager(), false, false);
     }
 
@@ -105,7 +103,7 @@
                 return new DocumentTabWebContentsDelegateAndroid(DocumentTab.this, mActivity);
             }
         }, initiallyHidden);
-        if (unfreeze) mDidRestoreState = unfreezeContents();
+        if (unfreeze) unfreezeContents();
 
         getView().requestFocus();
     }
@@ -129,13 +127,6 @@
     }
 
     /**
-     * @return Whether or not the tab's state was restored.
-     */
-    public boolean didRestoreState() {
-        return mDidRestoreState;
-    }
-
-    /**
      * Create a DocumentTab.
      * @param activity The activity the tab will be residing in.
      * @param incognito Whether the tab is incognito.
@@ -147,31 +138,23 @@
      * @param initiallyHidden Whether or not the {@link WebContents} should be initially hidden.
      */
     static DocumentTab create(DocumentActivity activity, boolean incognito, WindowAndroid window,
-            String url, WebContents webContents, TabState tabState, boolean initiallyHidden) {
+            String url, WebContents webContents, TabState tabState, boolean initiallyHidden,
+            TabCreationState creationState) {
         int parentTabId = activity.getIntent().getIntExtra(
                 IntentHandler.EXTRA_PARENT_TAB_ID, Tab.INVALID_TAB_ID);
         if (webContents != null) {
             DocumentTab tab = new DocumentTab(
-                    activity, incognito, window, url, parentTabId, webContents);
+                    activity, incognito, window, url, parentTabId, webContents, creationState);
             webContents.resumeLoadingCreatedWebContents();
             return tab;
         }
 
         if (tabState == null) {
-            return new DocumentTab(activity, incognito, window, url, parentTabId, initiallyHidden);
+            return new DocumentTab(
+                    activity, incognito, window, url, parentTabId, initiallyHidden, creationState);
         } else {
-            return new DocumentTab(activity, incognito, window, "", tabState, parentTabId);
+            return new DocumentTab(
+                    activity, incognito, window, "", tabState, parentTabId, creationState);
         }
     }
-
-    /**
-     * A helper function to create TabUma and set it to the tab.
-     * @param creationState In what state the tab was created.
-     */
-    public void initializeTabUma(TabCreationState creationState) {
-        Activity activity = getWindowAndroid().getActivity().get();
-        if (!(activity instanceof ChromeActivity)) return;
-        setTabUma(new TabUma(this, creationState,
-                ((ChromeActivity) activity).getTabModelSelector().getModel(isIncognito())));
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/DomDistillerUIUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/DomDistillerUIUtils.java
index fc96514..79fe020 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/DomDistillerUIUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/DomDistillerUIUtils.java
@@ -99,13 +99,16 @@
     @CalledByNative
     public static void closePanel(boolean animate) {
         if (sManagerDelegate == null) return;
-        sManagerDelegate.closePanel(StateChangeReason.CLOSE_BUTTON, animate);
+        sManagerDelegate.closeReaderPanel(StateChangeReason.CLOSE_BUTTON, animate);
     }
 
     /**
      * Clear static references to objects.
+     * @param delegate The delegate requesting the destoy. This prevents different managers in
+     * document mode from accidentally clearing a reference it doesn't own.
      */
-    public static void destroy() {
+    public static void destroy(ReaderModeManagerDelegate delegate) {
+        if (delegate != sManagerDelegate) return;
         sManagerDelegate = null;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
index 8a5e118..f5a77d6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
@@ -106,7 +106,7 @@
         }
         mTabStatusMap.clear();
 
-        DomDistillerUIUtils.destroy();
+        DomDistillerUIUtils.destroy(this);
 
         mChromeActivity = null;
         mReaderModePanel = null;
@@ -295,12 +295,8 @@
         return tab.getWebContents();
     }
 
-    /**
-     * This is a proxy method for those with access to the ReaderModeManagerDelegate to close the
-     * panel.
-     */
     @Override
-    public void closePanel(StateChangeReason reason, boolean animate) {
+    public void closeReaderPanel(StateChangeReason reason, boolean animate) {
         if (mReaderModePanel == null) return;
         mReaderModePanel.closePanel(reason, animate);
     }
@@ -379,17 +375,6 @@
     }
 
     /**
-     * A wrapper for the close method of the Reader Mode panel that checks for null and can be
-     * overridden for testing.
-     * @param reason The reason the panel is closing.
-     * @param animate True if the panel should animate closed.
-     */
-    protected void closeReaderPanel(StateChangeReason reason, boolean animate) {
-        if (mReaderModePanel == null) return;
-        mReaderModePanel.closePanel(reason, animate);
-    }
-
-    /**
      * Orientation change event handler. Simply close the panel.
      */
     public void onOrientationChange() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManagerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManagerDelegate.java
index c2e8013..62fe19e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManagerDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManagerDelegate.java
@@ -46,11 +46,12 @@
     WebContents getBasePageWebContents();
 
     /**
-     * Close the Reader Mode panel.
+     * Close the Reader Mode panel. This method wrap's the ReaderModePanel's close function and
+     * checks for null.
      * @param reason The reason the panel is being closed.
      * @param animate If the panel should animate as it closes.
      */
-    void closePanel(StateChangeReason reason, boolean animate);
+    void closeReaderPanel(StateChangeReason reason, boolean animate);
 
     /**
      * @return The ChromeActivity that owns the manager.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateAlwaysPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateAlwaysPanel.java
index cd8d135..2efab79e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateAlwaysPanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateAlwaysPanel.java
@@ -24,12 +24,10 @@
     @Override
     public void createContent(Context context, InfoBarLayout layout) {
         layout.setMessage(context.getString(
-                R.string.translate_infobar_translation_done, mOptions.targetLanguage()));
-
+                R.string.translate_infobar_translation_done, mOptions.targetLanguageName()));
         if (!mOptions.triggeredFromMenu()) {
             createAlwaysToggle(layout, mOptions);
         }
-
         layout.setButtons(context.getString(R.string.translate_button_done),
                 context.getString(R.string.translate_show_original));
     }
@@ -49,7 +47,7 @@
     static void createAlwaysToggle(InfoBarLayout layout, TranslateOptions options) {
         InfoBarControlLayout controlLayout = layout.addControlLayout();
         String description = layout.getContext().getString(
-                R.string.translate_always_text, options.sourceLanguage());
+                R.string.translate_always_text, options.sourceLanguageName());
         controlLayout.addSwitch(0, description, R.id.translate_infobar_always_toggle,
                 options.alwaysTranslateLanguageState());
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBar.java
index 9ee2212..82bbb7f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBar.java
@@ -17,6 +17,8 @@
 import org.chromium.chrome.R;
 import org.chromium.ui.base.DeviceFormFactor;
 
+import java.util.ArrayList;
+
 /**
  * Java version of the translate infobar
  */
@@ -43,18 +45,25 @@
     private final boolean mShouldShowNeverBar;
 
     @CalledByNative
-    private static InfoBar show(int translateBarType, int sourceLanguageIndex,
-            int targetLanguageIndex, boolean autoTranslatePair, boolean showNeverInfobar,
-            boolean triggeredFromMenu, String[] languages) {
-        return new TranslateInfoBar(translateBarType, sourceLanguageIndex, targetLanguageIndex,
-                autoTranslatePair, showNeverInfobar, triggeredFromMenu, languages);
+    private static InfoBar show(int translateBarType, String sourceLanguageCode,
+            String targetLanguageCode, boolean autoTranslatePair, boolean showNeverInfobar,
+            boolean triggeredFromMenu, String[] languages, String[] codes) {
+        return new TranslateInfoBar(translateBarType, sourceLanguageCode, targetLanguageCode,
+                autoTranslatePair, showNeverInfobar, triggeredFromMenu, languages, codes);
     }
 
-    private TranslateInfoBar(int infoBarType, int sourceLanguageIndex, int targetLanguageIndex,
+    private TranslateInfoBar(int infoBarType, String sourceLanguageCode, String targetLanguageCode,
             boolean autoTranslatePair, boolean shouldShowNeverBar, boolean triggeredFromMenu,
-            String[] languages) {
+            String[] languages, String[] codes) {
         super(null, R.drawable.infobar_translate, null, null);
-        mOptions = new TranslateOptions(sourceLanguageIndex, targetLanguageIndex, languages,
+
+        assert languages.length == codes.length;
+        ArrayList<TranslateOptions.TranslateLanguagePair> languageList =
+                new ArrayList<TranslateOptions.TranslateLanguagePair>();
+        for (int i = 0; i < languages.length; ++i) {
+            languageList.add(new TranslateOptions.TranslateLanguagePair(codes[i], languages[i]));
+        }
+        mOptions = new TranslateOptions(sourceLanguageCode, targetLanguageCode, languageList,
                 autoTranslatePair, triggeredFromMenu);
         mInfoBarType = infoBarType;
         mShouldShowNeverBar = shouldShowNeverBar;
@@ -120,11 +129,11 @@
         switch (getInfoBarType()) {
             case BEFORE_TRANSLATE_INFOBAR:
                 String template = context.getString(R.string.translate_infobar_text);
-                return formatBeforeInfoBarMessage(template, mOptions.sourceLanguage(),
-                        mOptions.targetLanguage(), LANGUAGE_PANEL);
+                return formatBeforeInfoBarMessage(template, mOptions.sourceLanguageName(),
+                        mOptions.targetLanguageName(), LANGUAGE_PANEL);
             case AFTER_TRANSLATE_INFOBAR:
                 String translated = context.getString(
-                        R.string.translate_infobar_translation_done, mOptions.targetLanguage());
+                        R.string.translate_infobar_translation_done, mOptions.targetLanguageName());
                 if (needsAlwaysPanel()) {
                     String moreOptions = context.getString(R.string.more);
                     return formatAfterTranslateInfoBarMessage(translated, moreOptions,
@@ -133,8 +142,8 @@
                     return translated;
                 }
             case TRANSLATING_INFOBAR:
-                return context.getString(R.string.translate_infobar_translating,
-                        mOptions.targetLanguage());
+                return context.getString(
+                        R.string.translate_infobar_translating, mOptions.targetLanguageName());
             default:
                 return context.getString(R.string.translate_infobar_error);
         }
@@ -186,8 +195,7 @@
         layout.setMessage(getMessageText(context));
         layout.setButtons(getPrimaryButtonText(context), getSecondaryButtonText(context));
 
-        if (getInfoBarType() == AFTER_TRANSLATE_INFOBAR
-                && !needsAlwaysPanel()
+        if (getInfoBarType() == AFTER_TRANSLATE_INFOBAR && !needsAlwaysPanel()
                 && !mOptions.triggeredFromMenu()) {
             // Fully expanded version of the "Always Translate" InfoBar.
             TranslateAlwaysPanel.createAlwaysToggle(layout, mOptions);
@@ -225,8 +233,8 @@
         }
 
         if (mOptions.optionsChanged()) {
-            nativeApplyTranslateOptions(mNativeTranslateInfoBarPtr, mOptions.sourceLanguageIndex(),
-                    mOptions.targetLanguageIndex(), mOptions.alwaysTranslateLanguageState(),
+            nativeApplyTranslateOptions(mNativeTranslateInfoBarPtr, mOptions.sourceLanguageCode(),
+                    mOptions.targetLanguageCode(), mOptions.alwaysTranslateLanguageState(),
                     mOptions.neverTranslateLanguageState(), mOptions.neverTranslateDomainState());
         }
     }
@@ -338,6 +346,6 @@
     }
 
     private native void nativeApplyTranslateOptions(long nativeTranslateInfoBar,
-            int sourceLanguageIndex, int targetLanguageIndex, boolean alwaysTranslate,
+            String sourceLanguageCode, String targetLanguageCode, boolean alwaysTranslate,
             boolean neverTranslateLanguage, boolean neverTranslateSite);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateLanguagePanel.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateLanguagePanel.java
index c5726e4..e01b8116 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateLanguagePanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateLanguagePanel.java
@@ -22,7 +22,6 @@
 import org.chromium.chrome.R;
 
 import java.util.ArrayList;
-import java.util.List;
 
 /**
  * Language panel shown in the translate infobar.
@@ -92,8 +91,8 @@
     @Override
     public void onButtonClicked(boolean primary) {
         if (primary) {
-            mOptions.setSourceLanguage(mSessionOptions.sourceLanguageIndex());
-            mOptions.setTargetLanguage(mSessionOptions.targetLanguageIndex());
+            mOptions.setSourceLanguage(mSessionOptions.sourceLanguageCode());
+            mOptions.setTargetLanguage(mSessionOptions.targetLanguageCode());
         }
         mListener.onPanelClosed(ActionType.NONE);
     }
@@ -105,8 +104,8 @@
                 LANGUAGE_TYPE_TARGET);
 
         // Determine how wide each spinner needs to be to avoid truncating its children.
-        mSourceAdapter.addAll(createSpinnerLanguages(-1));
-        mTargetAdapter.addAll(createSpinnerLanguages(-1));
+        mSourceAdapter.addAll(createSpinnerLanguages(""));
+        mTargetAdapter.addAll(createSpinnerLanguages(""));
         mSourceAdapter.measureWidthRequiredForView();
         mTargetAdapter.measureWidthRequiredForView();
 
@@ -122,10 +121,8 @@
         mSourceAdapter.clear();
         mTargetAdapter.clear();
 
-        int sourceAvoidLanguage = mSessionOptions.targetLanguageIndex();
-        int targetAvoidLanguage = mSessionOptions.sourceLanguageIndex();
-        mSourceAdapter.addAll(createSpinnerLanguages(sourceAvoidLanguage));
-        mTargetAdapter.addAll(createSpinnerLanguages(targetAvoidLanguage));
+        mSourceAdapter.addAll(createSpinnerLanguages(mSessionOptions.targetLanguageCode()));
+        mTargetAdapter.addAll(createSpinnerLanguages(mSessionOptions.sourceLanguageCode()));
 
         int originalSourceSelection = mSourceSpinner.getSelectedItemPosition();
         int newSourceSelection = getSelectionPosition(LANGUAGE_TYPE_SOURCE);
@@ -141,14 +138,29 @@
     }
 
     private int getSelectionPosition(int languageType) {
-        int position = languageType == LANGUAGE_TYPE_SOURCE ? mSessionOptions.sourceLanguageIndex()
-                : mSessionOptions.targetLanguageIndex();
+        String position_code = languageType == LANGUAGE_TYPE_SOURCE
+                ? mSessionOptions.sourceLanguageCode()
+                : mSessionOptions.targetLanguageCode();
 
-        // Since the source and target languages cannot appear in both spinners, the index for the
-        // source language can be off by one if comes after the target language alphabetically (and
-        // vice versa).
-        int opposite = languageType == LANGUAGE_TYPE_SOURCE ? mSessionOptions.targetLanguageIndex()
-                : mSessionOptions.sourceLanguageIndex();
+        // Since the source and target languages cannot appear in both spinners,
+        // the index for the source language can be off by one if comes after the
+        // target language alphabetically (and vice versa).
+        String opposite_code = languageType == LANGUAGE_TYPE_SOURCE
+                ? mSessionOptions.targetLanguageCode()
+                : mSessionOptions.sourceLanguageCode();
+
+        int position = -1;
+        int opposite = -1;
+
+        for (int i = 0; i < mSessionOptions.allLanguages().size(); ++i) {
+            if (mSessionOptions.allLanguages().get(i).mLanguageCode.equals(position_code)) {
+                position = i;
+            }
+            if (mSessionOptions.allLanguages().get(i).mLanguageCode.equals(opposite_code)) {
+                opposite = i;
+            }
+            if (opposite > -1 && position > -1) break;
+        }
         if (opposite < position) position -= 1;
 
         return position;
@@ -157,11 +169,11 @@
     @Override
     public void onItemSelected(AdapterView<?> adapter, View view, int position, long id) {
         Spinner spinner = (Spinner) adapter;
-        int newId = ((SpinnerLanguageElement) spinner.getSelectedItem()).getLanguageId();
+        String newCode = ((SpinnerLanguageElement) spinner.getSelectedItem()).getLanguageCode();
         if (spinner == mSourceSpinner) {
-            mSessionOptions.setSourceLanguage(newId);
+            mSessionOptions.setSourceLanguage(newCode);
         } else {
-            mSessionOptions.setTargetLanguage(newId);
+            mSessionOptions.setTargetLanguage(newCode);
         }
         reloadSpinners();
     }
@@ -172,14 +184,15 @@
 
     /**
      * Determines what languages will be shown in the Spinner.
-     * @param avoidLanguage Index of the language to avoid.  Use -1 to display all languages.
+     * @param avoidCode ISO code of the language to avoid displaying.
+     * Use "" to display all languages.
      */
-    private ArrayList<SpinnerLanguageElement> createSpinnerLanguages(int avoidLanguage) {
+    private ArrayList<SpinnerLanguageElement> createSpinnerLanguages(String avoidCode) {
         ArrayList<SpinnerLanguageElement> result = new ArrayList<SpinnerLanguageElement>();
-        List<String> languages = mSessionOptions.allLanguages();
-        for (int i = 0; i <  languages.size(); ++i) {
-            if (i != avoidLanguage) {
-                result.add(new SpinnerLanguageElement(languages.get(i), i));
+        for (TranslateOptions.TranslateLanguagePair language : mSessionOptions.allLanguages()) {
+            if (!language.mLanguageCode.equals(avoidCode)) {
+                result.add(new SpinnerLanguageElement(
+                        language.mLanguageRepresentation, language.mLanguageCode));
             }
         }
         return result;
@@ -263,15 +276,15 @@
      */
     private static class SpinnerLanguageElement {
         private final String mLanguageName;
-        private final int mLanguageId;
+        private final String mLanguageCode;
 
-        public SpinnerLanguageElement(String languageName, int languageId) {
+        public SpinnerLanguageElement(String languageName, String languageCode) {
             mLanguageName = languageName;
-            mLanguageId = languageId;
+            mLanguageCode = languageCode;
         }
 
-        public int getLanguageId() {
-            return mLanguageId;
+        public String getLanguageCode() {
+            return mLanguageCode;
         }
 
         /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateNeverPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateNeverPanel.java
index 53d5435b..e1c7458 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateNeverPanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateNeverPanel.java
@@ -23,13 +23,12 @@
     @Override
     public void createContent(Context context, InfoBarLayout layout) {
         String changeLanguage = context.getString(
-                R.string.translate_never_translate_message_text, mOptions.sourceLanguage());
+                R.string.translate_never_translate_message_text, mOptions.sourceLanguageName());
         layout.setMessage(changeLanguage);
 
-        layout.setButtons(
-                context.getString(R.string.translate_never_translate_site),
+        layout.setButtons(context.getString(R.string.translate_never_translate_site),
                 context.getString(R.string.translate_never_translate_language,
-                        mOptions.sourceLanguage()));
+                        mOptions.sourceLanguageName()));
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateOptions.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateOptions.java
index 78b6e87..a687451a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateOptions.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateOptions.java
@@ -4,16 +4,54 @@
 
 package org.chromium.chrome.browser.infobar;
 
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
+import android.text.TextUtils;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
  * A class that keeps the state of the different translation options and
  * languages.
  */
 public class TranslateOptions {
+    /**
+     * A container for Language Code and it's translated representation
+     * For example for Spanish when viewed from a French locale, this will contain es, Espagnol
+     **/
+    public static class TranslateLanguagePair {
+        public final String mLanguageCode;
+        public final String mLanguageRepresentation;
+
+        public TranslateLanguagePair(String languageCode, String languageRepresentation) {
+            assert languageCode != null;
+            assert languageRepresentation != null;
+            mLanguageCode = languageCode;
+            mLanguageRepresentation = languageRepresentation;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof TranslateLanguagePair)) {
+                return false;
+            }
+            TranslateLanguagePair other = (TranslateLanguagePair) obj;
+            return this.mLanguageCode.equals(other.mLanguageCode)
+                    && this.mLanguageRepresentation.equals(other.mLanguageRepresentation);
+        }
+
+        @Override
+        public int hashCode() {
+            return (mLanguageCode + mLanguageRepresentation).hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return "mLanguageCode:" + mLanguageCode + " - mlanguageRepresentation "
+                    + mLanguageRepresentation;
+        }
+    }
 
     // This would be an enum but they are not good for mobile.
     // The checkBoundaries method below needs to be updated if new options are added.
@@ -21,44 +59,55 @@
     private static final int NEVER_DOMAIN = 1;
     private static final int ALWAYS_LANGUAGE = 2;
 
-    private final String[] mAllLanguages;
+    private String mSourceLanguageCode;
+    private String mTargetLanguageCode;
+
+    private final ArrayList<TranslateLanguagePair> mAllLanguages;
+
+    // language code to translated language name map
+    // Conceptually final
+    private Map<String, String> mCodeToRepresentation;
 
     // Will reflect the state before the object was ever modified
     private final boolean[] mOriginalOptions;
-    private final int mOriginalSourceLanguageIndex;
-    private final int mOriginalTargetLanguageIndex;
 
-    private final boolean[] mOptions;
-    private int mSourceLanguageIndex;
-    private int mTargetLanguageIndex;
+    private final String mOriginalSourceLanguageCode;
+    private final String mOriginalTargetLanguageCode;
     private final boolean mTriggeredFromMenu;
 
-    private TranslateOptions(int sourceLanguageCode, int targetLanguageCode, String[] allLanguages,
-            boolean neverLanguage, boolean neverDomain, boolean alwaysLanguage,
-            boolean triggeredFromMenu, boolean[] originalOptions) {
-        mAllLanguages = allLanguages;
-        mSourceLanguageIndex = sourceLanguageCode;
-        mTargetLanguageIndex = targetLanguageCode;
-        mTriggeredFromMenu = triggeredFromMenu;
+    private final boolean[] mOptions;
 
+    private TranslateOptions(String sourceLanguageCode, String targetLanguageCode,
+            ArrayList<TranslateLanguagePair> allLanguages, boolean neverLanguage,
+            boolean neverDomain, boolean alwaysLanguage, boolean triggeredFromMenu,
+            boolean[] originalOptions) {
         mOptions = new boolean[3];
         mOptions[NEVER_LANGUAGE] = neverLanguage;
         mOptions[NEVER_DOMAIN] = neverDomain;
         mOptions[ALWAYS_LANGUAGE] = alwaysLanguage;
 
-
         if (originalOptions == null) {
             mOriginalOptions = mOptions.clone();
         } else {
             mOriginalOptions = originalOptions.clone();
         }
 
-        mOriginalSourceLanguageIndex = mSourceLanguageIndex;
-        mOriginalTargetLanguageIndex = mTargetLanguageIndex;
+        mSourceLanguageCode = sourceLanguageCode;
+        mTargetLanguageCode = targetLanguageCode;
+        mOriginalSourceLanguageCode = mSourceLanguageCode;
+        mOriginalTargetLanguageCode = mTargetLanguageCode;
+        mTriggeredFromMenu = triggeredFromMenu;
+
+        mAllLanguages = allLanguages;
+        mCodeToRepresentation = new HashMap<String, String>();
+        for (TranslateLanguagePair language : allLanguages) {
+            mCodeToRepresentation.put(language.mLanguageCode, language.mLanguageRepresentation);
+        }
     }
 
-    public TranslateOptions(int sourceLanguageCode, int targetLanguageCode, String[] allLanguages,
-            boolean alwaysTranslate, boolean triggeredFromMenu) {
+    public TranslateOptions(String sourceLanguageCode, String targetLanguageCode,
+            ArrayList<TranslateLanguagePair> allLanguages, boolean alwaysTranslate,
+            boolean triggeredFromMenu) {
         this(sourceLanguageCode, targetLanguageCode, allLanguages, false, false, alwaysTranslate,
                 triggeredFromMenu, null);
     }
@@ -67,32 +116,31 @@
      * Copy constructor
      */
     public TranslateOptions(TranslateOptions other) {
-        this(other.mSourceLanguageIndex, other.mTargetLanguageIndex, other.mAllLanguages,
+        this(other.mSourceLanguageCode, other.mTargetLanguageCode, other.mAllLanguages,
                 other.mOptions[NEVER_LANGUAGE], other.mOptions[NEVER_DOMAIN],
-                other.mOptions[ALWAYS_LANGUAGE], other.mTriggeredFromMenu,
-                other.mOriginalOptions);
+                other.mOptions[ALWAYS_LANGUAGE], other.mTriggeredFromMenu, other.mOriginalOptions);
     }
 
-    public String sourceLanguage() {
-        if (checkLanguageBoundaries(mSourceLanguageIndex)) {
-            return mAllLanguages[mSourceLanguageIndex];
+    public String sourceLanguageName() {
+        if (isValidLanguageCode(mSourceLanguageCode)) {
+            return mCodeToRepresentation.get(mSourceLanguageCode);
         }
         return "";
     }
 
-    public String targetLanguage() {
-        if (checkLanguageBoundaries(mTargetLanguageIndex)) {
-            return mAllLanguages[mTargetLanguageIndex];
+    public String targetLanguageName() {
+        if (isValidLanguageCode(mTargetLanguageCode)) {
+            return mCodeToRepresentation.get(mTargetLanguageCode);
         }
         return "";
     }
 
-    public int sourceLanguageIndex() {
-        return checkLanguageBoundaries(mSourceLanguageIndex) ? mSourceLanguageIndex : 0;
+    public String sourceLanguageCode() {
+        return mSourceLanguageCode;
     }
 
-    public int targetLanguageIndex() {
-        return checkLanguageBoundaries(mTargetLanguageIndex) ? mTargetLanguageIndex : 0;
+    public String targetLanguageCode() {
+        return mTargetLanguageCode;
     }
 
     public boolean triggeredFromMenu() {
@@ -100,16 +148,15 @@
     }
 
     public boolean optionsChanged() {
-        return (mSourceLanguageIndex != mOriginalSourceLanguageIndex)
-                || (mTargetLanguageIndex != mOriginalTargetLanguageIndex)
+        return (!mSourceLanguageCode.equals(mOriginalSourceLanguageCode))
+                || (!mTargetLanguageCode.equals(mOriginalTargetLanguageCode))
                 || (mOptions[NEVER_LANGUAGE] != mOriginalOptions[NEVER_LANGUAGE])
                 || (mOptions[NEVER_DOMAIN] != mOriginalOptions[NEVER_DOMAIN])
                 || (mOptions[ALWAYS_LANGUAGE] != mOriginalOptions[ALWAYS_LANGUAGE]);
     }
 
-
-    public List<String> allLanguages() {
-        return Collections.unmodifiableList(Arrays.asList(mAllLanguages));
+    public List<TranslateLanguagePair> allLanguages() {
+        return mAllLanguages;
     }
 
     public boolean neverTranslateLanguageState() {
@@ -124,18 +171,18 @@
         return mOptions[NEVER_DOMAIN];
     }
 
-    public boolean setSourceLanguage(int languageIndex) {
-        boolean canSet = canSetLanguage(languageIndex, mTargetLanguageIndex);
+    public boolean setSourceLanguage(String languageCode) {
+        boolean canSet = canSetLanguage(languageCode, mTargetLanguageCode);
         if (canSet) {
-            mSourceLanguageIndex = languageIndex;
+            mSourceLanguageCode = languageCode;
         }
         return canSet;
     }
 
-    public boolean setTargetLanguage(int languageIndex) {
-        boolean canSet = canSetLanguage(mSourceLanguageIndex, languageIndex);
+    public boolean setTargetLanguage(String languageCode) {
+        boolean canSet = canSetLanguage(mSourceLanguageCode, languageCode);
         if (canSet) {
-            mTargetLanguageIndex = languageIndex;
+            mTargetLanguageCode = languageCode;
         }
         return canSet;
     }
@@ -183,17 +230,14 @@
         return true;
     }
 
-
-    private boolean checkLanguageBoundaries(int index) {
-        return index >= 0 && index < mAllLanguages.length;
+    private boolean isValidLanguageCode(String languageCode) {
+        return !TextUtils.isEmpty(languageCode) && mCodeToRepresentation.containsKey(languageCode);
     }
-
-    private boolean canSetLanguage(int sourceIndex, int targetIndex) {
-        if (sourceIndex == targetIndex) return false;
-        return checkLanguageBoundaries(sourceIndex) && checkLanguageBoundaries(targetIndex);
+    private boolean canSetLanguage(String sourceCode, String targetCode) {
+        return isValidLanguageCode(sourceCode) && isValidLanguageCode(targetCode)
+                && !sourceCode.equals(targetCode);
     }
 
-
     private static boolean checkElementBoundaries(int element) {
         return element >= NEVER_LANGUAGE && element <= ALWAYS_LANGUAGE;
     }
@@ -201,9 +245,9 @@
     @Override
     public String toString() {
         return new StringBuilder()
-                .append(sourceLanguage())
+                .append(sourceLanguageCode())
                 .append(" -> ")
-                .append(targetLanguage())
+                .append(targetLanguageCode())
                 .append(" - ")
                 .append("Never Language:")
                 .append(mOptions[NEVER_LANGUAGE])
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/net/qualityprovider/ExternalEstimateProviderAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/net/qualityprovider/ExternalEstimateProviderAndroid.java
index 363009b4..d5e8f2db 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/net/qualityprovider/ExternalEstimateProviderAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/net/qualityprovider/ExternalEstimateProviderAndroid.java
@@ -100,6 +100,12 @@
         return NO_VALUE;
     }
 
+    @CalledByNative
+    private static void onExit() {
+        sThreadCheck = null;
+        sExternalEstimateProviderAndroid = null;
+    }
+
     public native void nativeNotifyExternalEstimateProviderAndroidUpdate(
             long nativeExternalEstimateProviderAndroid);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java
index f20dff2..d73e246 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java
@@ -53,7 +53,7 @@
         int referer = getIntent().getIntExtra(UrlManager.REFERER_KEY, 0);
         if (savedInstanceState == null  // Ensure this is a newly-created activity
                 && referer == UrlManager.NOTIFICATION_REFERER) {
-            PhysicalWebUma.onNotificationPressed();
+            PhysicalWebUma.onNotificationPressed(this);
         }
         mDisplayRecorded = false;
 
@@ -75,7 +75,8 @@
         mPwsClient.resolve(urls, new PwsClient.ResolveScanCallback() {
             @Override
             public void onPwsResults(Collection<PwsResult> pwsResults) {
-                PhysicalWebUma.onPwsResponse(SystemClock.elapsedRealtime() - timestamp);
+                long duration = SystemClock.elapsedRealtime() - timestamp;
+                PhysicalWebUma.onPwsResponse(ListUrlsActivity.this, duration);
                 // filter out duplicate site URLs
                 Collection<String> siteUrls = new HashSet<>();
                 for (PwsResult pwsResult : pwsResults) {
@@ -97,7 +98,7 @@
                 //             taken place and the displayed URLs are significantly different.
                 if (!mDisplayRecorded) {
                     mDisplayRecorded = true;
-                    PhysicalWebUma.onUrlsDisplayed(mAdapter.getCount());
+                    PhysicalWebUma.onUrlsDisplayed(ListUrlsActivity.this, mAdapter.getCount());
                 }
             }
         });
@@ -118,7 +119,7 @@
      */
     @Override
     public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
-        PhysicalWebUma.onUrlSelected();
+        PhysicalWebUma.onUrlSelected(this);
         PwsResult pwsResult = mAdapter.getItem(position);
         Intent intent = createNavigateToUrlIntent(pwsResult);
         startActivity(intent);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java
index c4f99d4..5923cfea 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java
@@ -52,6 +52,15 @@
         clearUrlsAsync(application);
     }
 
+    /**
+     * Upload the collected UMA stats.
+     * This method should be called only when the native library is loaded.
+     * @param context A valid instance of Context.
+     */
+    public static void uploadDeferredMetrics(final Context context) {
+        PhysicalWebUma.uploadDeferredMetrics(context);
+    }
+
     private static void clearUrlsAsync(final Context context) {
         Runnable task = new Runnable() {
             @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebUma.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebUma.java
index da36676..0052e86 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebUma.java
@@ -4,20 +4,201 @@
 
 package org.chromium.chrome.browser.physicalweb;
 
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.AsyncTask;
+import android.preference.PreferenceManager;
+
+import org.chromium.base.Log;
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.metrics.RecordUserAction;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.concurrent.ThreadSafe;
+
 /**
  * Centralizes UMA data collection for the Physical Web feature.
- * TODO(cco3) Figure out how to implement these methods without the native library.
  */
-public final class PhysicalWebUma {
-    public static void onNotificationPressed() {
+@ThreadSafe
+class PhysicalWebUma {
+    private static final String TAG = "PhysicalWeb";
+    private static final String NOTIFICATION_PRESS_COUNT = "PhysicalWeb.NotificationPressed";
+    private static final String PWS_RESPONSE_TIMES = "PhysicalWeb.RoundTripTimeMilliseconds";
+    private static final String URL_SELECTED_COUNT = "PhysicalWeb.UrlSelected";
+    private static final String URLS_DISPLAYED_COUNTS = "PhysicalWeb.TotalBeaconsDetected";
+    private static boolean sUploadAllowed = false;
+
+    /**
+     * Records a notification press.
+     */
+    public static void onNotificationPressed(Context context) {
+        handleAction(context, NOTIFICATION_PRESS_COUNT);
     }
 
-    public static void onPwsResponse(long duration) {
+    /**
+     * Records a URL selection.
+     */
+    public static void onUrlSelected(Context context) {
+        handleAction(context, URL_SELECTED_COUNT);
     }
 
-    public static void onUrlsDisplayed(int numUrls) {
+    /**
+     * Records a response time from PWS.
+     * @param duration The length of time PWS took to respond.
+     */
+    public static void onPwsResponse(Context context, long duration) {
+        if (sUploadAllowed) {
+            RecordHistogram.recordTimesHistogram(PWS_RESPONSE_TIMES, duration,
+                                                 TimeUnit.MILLISECONDS);
+        } else {
+            storeValue(context, PWS_RESPONSE_TIMES, duration);
+        }
     }
 
-    public static void onUrlSelected() {
+    /**
+     * Records number of URLs displayed to a user.
+     * @param numUrls The number of URLs displayed to a user.
+     */
+    public static void onUrlsDisplayed(Context context, int numUrls) {
+        if (sUploadAllowed) {
+            RecordHistogram.recordCountHistogram(URLS_DISPLAYED_COUNTS, numUrls);
+        } else {
+            storeValue(context, URLS_DISPLAYED_COUNTS, numUrls);
+        }
+    }
+
+    /**
+     * Uploads metrics that we have deferred for uploading.
+     * Additionally, this method will cause future stat records not to be deferred and instead
+     * uploaded immediately.
+     */
+    public static void uploadDeferredMetrics(Context context) {
+        // If uploads have been explicitely requested, they are now allowed.
+        sUploadAllowed = true;
+
+        // Read the metrics.
+        UmaUploader uploader = new UmaUploader();
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        uploader.notificationPressCount = prefs.getInt(NOTIFICATION_PRESS_COUNT, 0);
+        uploader.urlSelectedCount = prefs.getInt(URL_SELECTED_COUNT, 0);
+        uploader.pwsResponseTimes = prefs.getString(PWS_RESPONSE_TIMES, "[]");
+        uploader.urlsDisplayedCounts = prefs.getString(URLS_DISPLAYED_COUNTS, "[]");
+
+        // If the metrics are empty, we are done.
+        if (uploader.isEmpty()) {
+            return;
+        }
+
+        // Clear out the stored deferred metrics that we are about to upload.
+        prefs.edit()
+                .remove(NOTIFICATION_PRESS_COUNT)
+                .remove(URL_SELECTED_COUNT)
+                .remove(PWS_RESPONSE_TIMES)
+                .remove(URLS_DISPLAYED_COUNTS)
+                .apply();
+
+        // Finally, upload the metrics.
+        AsyncTask.THREAD_POOL_EXECUTOR.execute(uploader);
+    }
+
+    private static void storeAction(Context context, String key) {
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        SharedPreferences.Editor prefsEditor = prefs.edit();
+        int count = prefs.getInt(key, 0);
+        prefsEditor.putInt(key, count + 1).apply();
+    }
+
+    private static void storeValue(Context context, String key, Object value) {
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        SharedPreferences.Editor prefsEditor = prefs.edit();
+        JSONArray values = null;
+        try {
+            values = new JSONArray(prefs.getString(key, "[]"));
+            values.put(value);
+        } catch (JSONException e) {
+            Log.e(TAG, "JSONException when storing " + key + " stats", e);
+            prefsEditor.remove(key).apply();
+            return;
+        }
+        prefsEditor.putString(key, values.toString()).apply();
+    }
+
+    private static void handleAction(Context context, String key) {
+        if (sUploadAllowed) {
+            RecordUserAction.record(key);
+        } else {
+            storeAction(context, key);
+        }
+    }
+
+    private static class UmaUploader implements Runnable {
+        public int notificationPressCount;
+        public int urlSelectedCount;
+        public String pwsResponseTimes;
+        public String urlsDisplayedCounts;
+
+        public boolean isEmpty() {
+            return notificationPressCount == 0
+                    && urlSelectedCount == 0
+                    && pwsResponseTimes.equals("[]")
+                    && urlsDisplayedCounts.equals("[]");
+        }
+
+        UmaUploader() {
+        }
+
+        @Override
+        public void run() {
+            uploadActions(notificationPressCount, NOTIFICATION_PRESS_COUNT);
+            uploadActions(urlSelectedCount, URL_SELECTED_COUNT);
+            uploadTimes(pwsResponseTimes, PWS_RESPONSE_TIMES, TimeUnit.MILLISECONDS);
+            uploadCounts(urlsDisplayedCounts, URLS_DISPLAYED_COUNTS);
+        }
+
+        private static void uploadActions(int count, String key) {
+            for (int i = 0; i < count; i++) {
+                RecordUserAction.record(key);
+            }
+        }
+
+        private static Object[] parseJsonArray(String jsonArrayStr, Class<?> itemType) {
+            try {
+                JSONArray values = new JSONArray(jsonArrayStr);
+                Object[] arr = new Object[values.length()];
+                for (int i = 0; i < values.length(); i++) {
+                    arr[i] = values.get(i);
+                    if (arr[i].getClass() != itemType) return null;
+                }
+                return arr;
+            } catch (JSONException e) {
+                return null;
+            }
+        }
+
+        private static void uploadTimes(String jsonTimesStr, final String key, final TimeUnit tu) {
+            Long[] times = (Long[]) parseJsonArray(jsonTimesStr, Long.class);
+            if (times == null) {
+                Log.e(TAG, "Error reporting " + key);
+                return;
+            }
+            for (Long time : times) {
+                RecordHistogram.recordTimesHistogram(key, time, TimeUnit.MILLISECONDS);
+            }
+        }
+
+        private static void uploadCounts(String jsonCountsStr, final String key) {
+            Integer[] counts = (Integer[]) parseJsonArray(jsonCountsStr, Long.class);
+            if (counts == null) {
+                Log.e(TAG, "Error reporting " + key);
+                return;
+            }
+            for (Integer count: counts) {
+                RecordHistogram.recordCountHistogram(key, count);
+            }
+        }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java
index dd40412..c040e79 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java
@@ -12,27 +12,39 @@
 import android.content.res.Resources;
 import android.support.v4.app.NotificationCompat;
 import android.support.v4.app.NotificationManagerCompat;
-import android.text.TextUtils;
 
+import org.chromium.base.Log;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.notifications.NotificationConstants;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 
 /**
- * This class stores URLs and surfaces notifications to the user.
+ * This class stores URLs which are discovered by scanning for Physical Web beacons, and updates a
+ * Notification as the set changes.
+ *
+ * There are two sets of URLs maintained:
+ * - Those which are currently nearby, as tracked by calls to addUrl/removeUrl
+ * - Those which have ever resolved through the Physical Web Service (e.g. are known to produce
+ *     good results).
+ *
+ * Whenever either list changes, we update the Physical Web Notification, based on the intersection
+ * of currently-nearby and known-resolved URLs.
  */
-public class UrlManager {
+class UrlManager {
     public static final String REFERER_KEY = "referer";
     public static final int NOTIFICATION_REFERER = 1;
     private static final String TAG = "PhysicalWeb";
     private static final String PREFS_NAME = "org.chromium.chrome.browser.physicalweb.URL_CACHE";
     private static final String PREFS_VERSION_KEY = "version";
-    private static final String PREFS_URLS_KEY = "urls";
-    private static final int PREFS_VERSION = 1;
+    private static final String PREFS_NEARBY_URLS_KEY = "nearby_urls";
+    private static final String PREFS_RESOLVED_URLS_KEY = "resolved_urls";
+    private static final String DEPRECATED_PREFS_URLS_KEY = "urls";
+    private static final int PREFS_VERSION = 2;
     private static UrlManager sInstance = null;
     private final Context mContext;
     private final NotificationManagerCompat mNotificationManager;
@@ -46,6 +58,7 @@
         mContext = context;
         mNotificationManager = NotificationManagerCompat.from(context);
         mPwsClient = new PwsClient();
+        initSharedPreferences();
     }
 
     /**
@@ -66,10 +79,12 @@
      * @param url The URL to add.
      */
     public void addUrl(String url) {
-        Set<String> urls = getCachedUrls();
+        Log.d(TAG, "URL found: " + url);
+        Set<String> urls = getCachedNearbyUrls();
         urls.add(url);
-        putCachedUrls(urls);
-        updateNotification(urls);
+        putCachedNearbyUrls(urls);
+        resolveUrl(url);
+        updateNotification();
     }
 
     /**
@@ -78,17 +93,25 @@
      * @param url The URL to remove.
      */
     public void removeUrl(String url) {
-        Set<String> urls = getCachedUrls();
+        Log.d(TAG, "URL lost: " + url);
+        Set<String> urls = getCachedNearbyUrls();
         urls.remove(url);
-        putCachedUrls(urls);
-        updateNotification(urls);
+        putCachedNearbyUrls(urls);
+        updateNotification();
     }
 
     /**
-     * Get the stored URLs.
+     * Get the list of URLs which are both nearby and resolved through PWS.
      */
     public Set<String> getUrls() {
-        return getCachedUrls();
+        Set<String> nearbyUrls = getCachedNearbyUrls();
+        Set<String> resolvedUrls = getCachedResolvedUrls();
+        Set<String> intersection = new HashSet<String>(nearbyUrls);
+        intersection.retainAll(resolvedUrls);
+        Log.d(TAG, "Get URLs With: " + nearbyUrls.size() + " nearby, "
+                      + resolvedUrls.size() + " resolved, and "
+                      + intersection.size() + " in intersection.");
+        return intersection;
     }
 
     /**
@@ -96,33 +119,76 @@
      */
     public void clearUrls() {
         Set<String> emptySet = Collections.emptySet();
-        putCachedUrls(emptySet);
-        updateNotification(emptySet);
+        putCachedNearbyUrls(emptySet);
+        putCachedResolvedUrls(emptySet);
+        updateNotification();
     }
 
-    private Set<String> getCachedUrls() {
-        // Check the version.
+    private void addResolvedUrl(String url) {
+        Log.d(TAG, "PWS resolved: " + url);
+        Set<String> urls = getCachedResolvedUrls();
+        urls.add(url);
+        putCachedResolvedUrls(urls);
+        updateNotification();
+    }
+
+    private void removeResolvedUrl(String url) {
+        Log.d(TAG, "PWS unresolved: " + url);
+        Set<String> urls = getCachedResolvedUrls();
+        urls.remove(url);
+        putCachedResolvedUrls(urls);
+        updateNotification();
+    }
+
+    private void initSharedPreferences() {
         SharedPreferences prefs = mContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
         int prefsVersion = prefs.getInt(PREFS_VERSION_KEY, 0);
-        if (prefsVersion != PREFS_VERSION) {
-            return new HashSet<String>();
+
+        // Check the version.
+        if (prefsVersion == PREFS_VERSION) {
+            return;
         }
 
-        // Restore the cached urls.
-        return prefs.getStringSet(PREFS_URLS_KEY, new HashSet<String>());
+        // Stored preferences are old, upgrade to the current version.
+        SharedPreferences.Editor editor = prefs.edit();
+        editor.remove(DEPRECATED_PREFS_URLS_KEY);
+        editor.putInt(PREFS_VERSION_KEY, PREFS_VERSION);
+        editor.apply();
+
+        clearUrls();
     }
 
-    private void putCachedUrls(Set<String> urls) {
+    private Set<String> getStringSetFromSharedPreferences(String preferenceName) {
+        // Check the version.
+        SharedPreferences prefs = mContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
+        return prefs.getStringSet(preferenceName, new HashSet<String>());
+    }
+
+    private void setStringSetInSharedPreferences(String preferenceName,
+                                                 Set<String> preferenceValue) {
         // Write the version.
         SharedPreferences prefs = mContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
         SharedPreferences.Editor editor = prefs.edit();
-        editor.putInt(PREFS_VERSION_KEY, PREFS_VERSION);
-
-        // Write the urls.
-        editor.putStringSet(PREFS_URLS_KEY, urls);
+        editor.putStringSet(preferenceName, preferenceValue);
         editor.apply();
     }
 
+    private Set<String> getCachedNearbyUrls() {
+        return getStringSetFromSharedPreferences(PREFS_NEARBY_URLS_KEY);
+    }
+
+    private void putCachedNearbyUrls(Set<String> urls) {
+        setStringSetInSharedPreferences(PREFS_NEARBY_URLS_KEY, urls);
+    }
+
+    private Set<String> getCachedResolvedUrls() {
+        return getStringSetFromSharedPreferences(PREFS_RESOLVED_URLS_KEY);
+    }
+
+    private void putCachedResolvedUrls(Set<String> urls) {
+        setStringSetInSharedPreferences(PREFS_RESOLVED_URLS_KEY, urls);
+    }
+
     private PendingIntent createListUrlsIntent() {
         Intent intent = new Intent(mContext, ListUrlsActivity.class);
         intent.putExtra(REFERER_KEY, NOTIFICATION_REFERER);
@@ -130,48 +196,40 @@
         return pendingIntent;
     }
 
-    private void updateNotification(Set<String> urls) {
+    private void resolveUrl(final String url) {
+        Set<String> urls = new HashSet<String>(Arrays.asList(url));
+        mPwsClient.resolve(urls, new PwsClient.ResolveScanCallback() {
+            @Override
+            public void onPwsResults(Collection<PwsResult> pwsResults) {
+                for (PwsResult pwsResult : pwsResults) {
+                    String requestUrl = pwsResult.requestUrl;
+                    if (url.equalsIgnoreCase(requestUrl)) {
+                        addResolvedUrl(url);
+                        return;
+                    }
+                }
+                removeResolvedUrl(url);
+            }
+        });
+    }
+
+    private void updateNotification() {
+        Set<String> urls = getUrls();
+
         if (urls.isEmpty()) {
             mNotificationManager.cancel(NotificationConstants.NOTIFICATION_ID_PHYSICAL_WEB);
             return;
         }
 
-        mPwsClient.resolve(urls, new PwsClient.ResolveScanCallback() {
-            @Override
-            public void onPwsResults(Collection<PwsResult> pwsResults) {
-                // filter out duplicate site URLs
-                Set<String> siteUrls = new HashSet<>();
-                for (PwsResult pwsResult : pwsResults) {
-                    String siteUrl = pwsResult.siteUrl;
-                    if (siteUrl != null && !siteUrls.contains(siteUrl)) {
-                        siteUrls.add(siteUrl);
-                    }
-                }
+        int urlCount = urls.size();
 
-                int urlCount = siteUrls.size();
+        Resources resources = mContext.getResources();
+        // TODO: Do not show how many are nearby
+        String title = resources.getQuantityString(
+                R.plurals.physical_web_notification_title, urlCount, urlCount);
+        String text = null;
 
-                if (urlCount == 0) {
-                    mNotificationManager.cancel(NotificationConstants.NOTIFICATION_ID_PHYSICAL_WEB);
-                } else {
-                    Resources resources = mContext.getResources();
-                    String title = resources.getQuantityString(
-                            R.plurals.physical_web_notification_title, urlCount, urlCount);
-                    String text = null;
-
-                    // when only one URL is found, display its title and description in the
-                    // notification (but avoid displaying a blank notification)
-                    if (urlCount == 1) {
-                        PwsResult onlyResult = pwsResults.iterator().next();
-                        if (!TextUtils.isEmpty(onlyResult.title)) {
-                            title = onlyResult.title;
-                            text = onlyResult.description;
-                        }
-                    }
-
-                    createNotification(title, text);
-                }
-            }
-        });
+        createNotification(title, text);
     }
 
     private void createNotification(String title, String text) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
index c5c1564..b2cd0bf5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
@@ -207,16 +207,16 @@
      */
     @CalledByNative
     public static String getAndroidPermissionForContentSetting(int contentSettingType) {
-        switch(contentSettingType) {
-            case ContentSettingsType.CONTENT_SETTINGS_TYPE_GEOLOCATION:
-                return android.Manifest.permission.ACCESS_FINE_LOCATION;
-            case ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
-                return android.Manifest.permission.RECORD_AUDIO;
-            case ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
-                return android.Manifest.permission.CAMERA;
-            default:
-                return null;
+        if (contentSettingType == ContentSettingsType.CONTENT_SETTINGS_TYPE_GEOLOCATION) {
+            return android.Manifest.permission.ACCESS_FINE_LOCATION;
         }
+        if (contentSettingType == ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) {
+            return android.Manifest.permission.RECORD_AUDIO;
+        }
+        if (contentSettingType == ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) {
+            return android.Manifest.permission.CAMERA;
+        }
+        return null;
     }
 
     public boolean isAcceptCookiesEnabled() {
@@ -511,6 +511,30 @@
     }
 
     /**
+     * @return whether there is a user set value for kNetworkPredictionEnabled.  This should only be
+     * used for preference migration.
+     */
+    public boolean networkPredictionEnabledHasUserSetting() {
+        return nativeNetworkPredictionEnabledHasUserSetting();
+    }
+
+    /**
+     * @return whether there is a user set value for kNetworkPredictionOptions.  This should only be
+     * used for preference migration.
+     */
+    public boolean networkPredictionOptionsHasUserSetting() {
+        return nativeNetworkPredictionOptionsHasUserSetting();
+    }
+
+    /**
+     * @return the user set value for kNetworkPredictionEnabled. This should only be used for
+     * preference migration.
+     */
+    public boolean getNetworkPredictionEnabledUserPrefValue() {
+        return nativeGetNetworkPredictionEnabledUserPrefValue();
+    }
+
+    /**
      * @return Network predictions preference.
      */
     public NetworkPredictionOptions getNetworkPredictionOptions() {
@@ -963,6 +987,9 @@
     private native void nativeSetSafeBrowsingEnabled(boolean enabled);
     private native boolean nativeGetSafeBrowsingManaged();
     private native boolean nativeGetNetworkPredictionManaged();
+    private native boolean nativeNetworkPredictionEnabledHasUserSetting();
+    private native boolean nativeNetworkPredictionOptionsHasUserSetting();
+    private native boolean nativeGetNetworkPredictionEnabledUserPrefValue();
     private native int nativeGetNetworkPredictionOptions();
     private native void nativeSetNetworkPredictionOptions(int option);
     private native void nativeSetResolveNavigationErrorEnabled(boolean enabled);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java
index c07127f6..d26de7c9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java
@@ -124,8 +124,7 @@
         // Report back what is selected.
         String name = "";
         if (mSelectedSearchEnginePosition > -1) {
-            TemplateUrl templateUrl = mSearchEngines.get(mSelectedSearchEnginePosition);
-            name = getSearchEngineNameAndDomain(mContext.getResources(), templateUrl);
+            name = mSearchEngines.get(mSelectedSearchEnginePosition).getShortName();
         }
         mCallback.currentSearchEngineDetermined(name);
     }
@@ -134,18 +133,6 @@
         return mSearchEngines.get(position).getIndex();
     }
 
-    /**
-     * @return The name of the search engine followed by the domain, e.g. "Google (google.co.uk)".
-     */
-    private static String getSearchEngineNameAndDomain(Resources res, TemplateUrl searchEngine) {
-        String title = searchEngine.getShortName();
-        if (!searchEngine.getKeyword().isEmpty()) {
-            title = res.getString(R.string.search_engine_name_and_domain, title,
-                    searchEngine.getKeyword());
-        }
-        return title;
-    }
-
     // BaseAdapter:
 
     @Override
@@ -156,7 +143,7 @@
     @Override
     public Object getItem(int pos) {
         TemplateUrl templateUrl = mSearchEngines.get(pos);
-        return getSearchEngineNameAndDomain(mContext.getResources(), templateUrl);
+        return templateUrl.getShortName();
     }
 
     @Override
@@ -191,7 +178,7 @@
         TextView description = (TextView) view.findViewById(R.id.description);
         TemplateUrl templateUrl = mSearchEngines.get(position);
         Resources resources = mContext.getResources();
-        description.setText(getSearchEngineNameAndDomain(resources, templateUrl));
+        description.setText(templateUrl.getShortName());
 
         // To improve the explore-by-touch experience, the radio button is hidden from accessibility
         // and instead, "checked" or "not checked" is read along with the search engine's name, e.g.
@@ -277,8 +264,7 @@
 
         // Report the change back.
         TemplateUrl templateUrl = mSearchEngines.get(mSelectedSearchEnginePosition);
-        mCallback.currentSearchEngineDetermined(getSearchEngineNameAndDomain(
-                mContext.getResources(), templateUrl));
+        mCallback.currentSearchEngineDetermined(templateUrl.getShortName());
 
         notifyDataSetChanged();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/BandwidthType.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/BandwidthType.java
new file mode 100644
index 0000000..ef6eb195
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/BandwidthType.java
@@ -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.
+
+package org.chromium.chrome.browser.preferences.privacy;
+
+/**
+ * Bandwidth options available based on network.
+ */
+public enum BandwidthType {
+
+    // Still using "prerender" in the strings for historical reasons: we don't want to break
+    // existing users' settings.
+    NEVER_PRERENDER      ("never_prefetch"),
+    PRERENDER_ON_WIFI    ("prefetch_on_wifi"),
+    ALWAYS_PRERENDER     ("always_prefetch");
+
+    public static final BandwidthType DEFAULT = PRERENDER_ON_WIFI;
+
+    private final String mTitle;
+
+    BandwidthType(String title) {
+        mTitle = title;
+    }
+
+    /**
+     * Returns the title of the bandwidthType.
+     * @return title
+     */
+    public String title() {
+        return mTitle;
+    }
+
+    /**
+     * Get the BandwidthType from the title.
+     * @param title
+     * @return BandwidthType
+     */
+    public static BandwidthType getBandwidthFromTitle(String title) {
+        for (BandwidthType b : BandwidthType.values()) {
+            if (b.mTitle.equals(title)) return b;
+        }
+        assert false;
+        return DEFAULT;
+    }
+}
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 a4540e60e..f16de915 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
@@ -64,6 +64,7 @@
         super.onCreate(savedInstanceState);
         PrivacyPreferencesManager privacyPrefManager =
                 PrivacyPreferencesManager.getInstance(getActivity());
+        privacyPrefManager.migrateNetworkPredictionPreferences();
         addPreferencesFromResource(R.xml.privacy_preferences);
         getActivity().setTitle(R.string.prefs_privacy);
         setHasOptionsMenu(true);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferencesManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferencesManager.java
index 48de3256..5107db1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferencesManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferencesManager.java
@@ -15,6 +15,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.device.DeviceClassManager;
+import org.chromium.chrome.browser.preferences.NetworkPredictionOptions;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 
 /**
@@ -24,8 +25,12 @@
 
     static final String PREF_CRASH_DUMP_UPLOAD = "crash_dump_upload";
     static final String PREF_CRASH_DUMP_UPLOAD_NO_CELLULAR = "crash_dump_upload_no_cellular";
+    private static final String PREF_NETWORK_PREDICTIONS = "network_predictions";
+    private static final String PREF_BANDWIDTH_OLD = "prefetch_bandwidth";
+    private static final String PREF_BANDWIDTH_NO_CELLULAR_OLD = "prefetch_bandwidth_no_cellular";
     private static final String PREF_METRICS_REPORTING = "metrics_reporting";
     private static final String PREF_CELLULAR_EXPERIMENT = "cellular_experiment";
+    private static final String ALLOW_PRERENDER_OLD = "allow_prefetch";
 
     private static PrivacyPreferencesManager sInstance;
 
@@ -63,6 +68,109 @@
                 mCrashDumpNeverUpload);
     }
 
+    /**
+     * Migrate and delete old preferences.  Note that migration has to happen in Android-specific
+     * code because we need to access ALLOW_PRERENDER sharedPreference.
+     * TODO(bnc) https://crbug.com/394845. This change is planned for M38. After a year or so, it
+     * would be worth considering removing this migration code (also removing accessors in
+     * PrefServiceBridge and pref_service_bridge), and reverting to default for users
+     * who had set preferences but have not used Chrome for a year. This change would be subject to
+     * privacy review.
+     */
+    public void migrateNetworkPredictionPreferences() {
+        PrefServiceBridge prefService = PrefServiceBridge.getInstance();
+
+        // See if PREF_NETWORK_PREDICTIONS is an old boolean value.
+        boolean predictionOptionIsBoolean = false;
+        try {
+            mSharedPreferences.getString(PREF_NETWORK_PREDICTIONS, "");
+        } catch (ClassCastException ex) {
+            predictionOptionIsBoolean = true;
+        }
+
+        // Nothing to do if the user or this migration code has already set the new
+        // preference.
+        if (!predictionOptionIsBoolean
+                && prefService.networkPredictionOptionsHasUserSetting()) {
+            return;
+        }
+
+        // Nothing to do if the old preferences are unset.
+        if (!predictionOptionIsBoolean
+                && !mSharedPreferences.contains(PREF_BANDWIDTH_OLD)
+                && !mSharedPreferences.contains(PREF_BANDWIDTH_NO_CELLULAR_OLD)) {
+            return;
+        }
+
+        // Migrate if the old preferences are at their default values.
+        // (Note that for PREF_BANDWIDTH*, if the setting is default, then there is no way to tell
+        // whether the user has set it.)
+        final String prefBandwidthDefault = BandwidthType.PRERENDER_ON_WIFI.title();
+        final String prefBandwidth =
+                mSharedPreferences.getString(PREF_BANDWIDTH_OLD, prefBandwidthDefault);
+        boolean prefBandwidthNoCellularDefault = true;
+        boolean prefBandwidthNoCellular = mSharedPreferences.getBoolean(
+                PREF_BANDWIDTH_NO_CELLULAR_OLD, prefBandwidthNoCellularDefault);
+
+        if (!(prefBandwidthDefault.equals(prefBandwidth))
+                || (prefBandwidthNoCellular != prefBandwidthNoCellularDefault)) {
+            NetworkPredictionOptions newValue = NetworkPredictionOptions.DEFAULT;
+            // Observe PREF_BANDWIDTH on mobile network capable devices.
+            if (isMobileNetworkCapable()) {
+                if (mSharedPreferences.contains(PREF_BANDWIDTH_OLD)) {
+                    BandwidthType prefetchBandwidthTypePref = BandwidthType.getBandwidthFromTitle(
+                            prefBandwidth);
+                    if (BandwidthType.NEVER_PRERENDER.equals(prefetchBandwidthTypePref)) {
+                        newValue = NetworkPredictionOptions.NETWORK_PREDICTION_NEVER;
+                    } else if (BandwidthType.PRERENDER_ON_WIFI.equals(prefetchBandwidthTypePref)) {
+                        newValue = NetworkPredictionOptions.NETWORK_PREDICTION_WIFI_ONLY;
+                    } else if (BandwidthType.ALWAYS_PRERENDER.equals(prefetchBandwidthTypePref)) {
+                        newValue = NetworkPredictionOptions.NETWORK_PREDICTION_ALWAYS;
+                    }
+                }
+            // Observe PREF_BANDWIDTH_NO_CELLULAR on devices without mobile network.
+            } else {
+                if (mSharedPreferences.contains(PREF_BANDWIDTH_NO_CELLULAR_OLD)) {
+                    if (prefBandwidthNoCellular) {
+                        newValue = NetworkPredictionOptions.NETWORK_PREDICTION_WIFI_ONLY;
+                    } else {
+                        newValue = NetworkPredictionOptions.NETWORK_PREDICTION_NEVER;
+                    }
+                }
+            }
+            // But disable after all if kNetworkPredictionEnabled was disabled by the user.
+            if (prefService.networkPredictionEnabledHasUserSetting()
+                    && !prefService.getNetworkPredictionEnabledUserPrefValue()) {
+                newValue = NetworkPredictionOptions.NETWORK_PREDICTION_NEVER;
+            }
+            // Save new value in Chrome PrefService.
+            prefService.setNetworkPredictionOptions(newValue);
+        }
+
+        // Delete old sharedPreferences.
+        SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit();
+        // Delete PREF_BANDWIDTH and PREF_BANDWIDTH_NO_CELLULAR: just migrated these options.
+        if (mSharedPreferences.contains(PREF_BANDWIDTH_OLD)) {
+            sharedPreferencesEditor.remove(PREF_BANDWIDTH_OLD);
+        }
+        if (mSharedPreferences.contains(PREF_BANDWIDTH_NO_CELLULAR_OLD)) {
+            sharedPreferencesEditor.remove(PREF_BANDWIDTH_NO_CELLULAR_OLD);
+        }
+        // Also delete ALLOW_PRERENDER, which was updated based on PREF_BANDWIDTH[_NO_CELLULAR] and
+        // network connectivity type, therefore does not carry additional information.
+        if (mSharedPreferences.contains(ALLOW_PRERENDER_OLD)) {
+            sharedPreferencesEditor.remove(ALLOW_PRERENDER_OLD);
+        }
+        // Delete bool PREF_NETWORK_PREDICTIONS so that string values can be stored. Note that this
+        // SharedPreference carries no information, because it used to be overwritten by
+        // kNetworkPredictionEnabled on startup, and now it is overwritten by
+        // kNetworkPredictionOptions on startup.
+        if (mSharedPreferences.contains(PREF_NETWORK_PREDICTIONS)) {
+            sharedPreferencesEditor.remove(PREF_NETWORK_PREDICTIONS);
+        }
+        sharedPreferencesEditor.apply();
+    }
+
     private NetworkInfo getActiveNetworkInfo() {
         ConnectivityManager connectivityManager =
                 (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
@@ -98,8 +206,9 @@
      * @return Whether prerendering should be allowed.
      */
     public boolean shouldPrerender() {
-        return DeviceClassManager.enablePrerendering()
-                && PrefServiceBridge.getInstance().canPredictNetworkActions();
+        if (!DeviceClassManager.enablePrerendering()) return false;
+        migrateNetworkPredictionPreferences();
+        return PrefServiceBridge.getInstance().canPredictNetworkActions();
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java b/chrome/android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java
index b93931e4..dad707fdc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java
@@ -47,18 +47,16 @@
     public static class TemplateUrl {
         private final int mIndex;
         private final String mShortName;
-        private final String mKeyword;
 
         @CalledByNative("TemplateUrl")
         public static TemplateUrl create(
-                int id, String shortName, String keyword) {
-            return new TemplateUrl(id, shortName, keyword);
+                int id, String shortName) {
+            return new TemplateUrl(id, shortName);
         }
 
-        public TemplateUrl(int index, String shortName, String keyword) {
+        public TemplateUrl(int index, String shortName) {
             mIndex = index;
             mShortName = shortName;
-            mKeyword = keyword;
         }
 
         public int getIndex() {
@@ -69,16 +67,11 @@
             return mShortName;
         }
 
-        public String getKeyword() {
-            return mKeyword;
-        }
-
         @Override
         public int hashCode() {
             final int prime = 31;
             int result = 1;
             result = prime * result + mIndex;
-            result = prime * result + ((mKeyword == null) ? 0 : mKeyword.hashCode());
             result = prime * result + ((mShortName == null) ? 0 : mShortName.hashCode());
             return result;
         }
@@ -88,8 +81,7 @@
             if (!(other instanceof TemplateUrl)) return false;
             TemplateUrl otherTemplateUrl = (TemplateUrl) other;
             return mIndex == otherTemplateUrl.mIndex
-                    && TextUtils.equals(mShortName, otherTemplateUrl.mShortName)
-                    && TextUtils.equals(mKeyword, otherTemplateUrl.mKeyword);
+                    && TextUtils.equals(mShortName, otherTemplateUrl.mShortName);
         }
     }
 
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 10097b49..ac75a281 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
@@ -68,6 +68,7 @@
 import org.chromium.chrome.browser.ssl.ConnectionSecurityLevel;
 import org.chromium.chrome.browser.ssl.SecurityStateModel;
 import org.chromium.chrome.browser.tab.TabUma.TabCreationState;
+import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
 import org.chromium.chrome.browser.tabmodel.TabModelImpl;
@@ -253,6 +254,11 @@
     private WebContentsState mFrozenContentsState;
 
     /**
+     * Whether the restoration from frozen state failed.
+     */
+    private boolean mFailedToRestore;
+
+    /**
      * URL load to be performed lazily when the Tab is next shown.
      */
     private LoadUrlParams mPendingLoadParams;
@@ -590,6 +596,7 @@
         MediaSessionTabHelper.createForTab(this);
 
         if (creationState != null) {
+            mTabUma = new TabUma(creationState);
             if (frozenState == null) {
                 assert type != TabLaunchType.FROM_RESTORE
                         && creationState != TabCreationState.FROZEN_ON_RESTORE;
@@ -598,11 +605,6 @@
                         && creationState == TabCreationState.FROZEN_ON_RESTORE;
             }
         }
-
-        if (mActivity != null && creationState != null) {
-            setTabUma(new TabUma(
-                    this, creationState, mActivity.getTabModelSelector().getModel(incognito)));
-        }
     }
 
     private void enableFullscreenAfterLoad() {
@@ -613,14 +615,6 @@
     }
 
     /**
-     * Sets the mTabUma object for stats reporting.
-     * @param tabUma TabUma object to use to report UMA stats.
-     */
-    protected void setTabUma(TabUma tabUma) {
-        mTabUma = tabUma;
-    }
-
-    /**
      * Restores member fields from the given TabState.
      * @param state TabState containing information about this Tab.
      */
@@ -1135,7 +1129,10 @@
 
             if (mContentViewCore != null) mContentViewCore.onShow();
 
-            if (mTabUma != null) mTabUma.onShow(type, getTimestampMillis());
+            if (mTabUma != null) {
+                mTabUma.onShow(type, getTimestampMillis(),
+                        computeMRURank(this, mActivity.getTabModelSelector().getModel(mIncognito)));
+            }
 
             // If the NativePage was frozen while in the background (see NativePageAssassin),
             // recreate the NativePage now.
@@ -1914,7 +1911,6 @@
             assert mFrozenContentsState != null;
             assert getContentViewCore() == null;
 
-            boolean forceNavigate = false;
             WebContents webContents =
                     mFrozenContentsState.restoreContentsFromByteBuffer(isHidden());
             if (webContents == null) {
@@ -1922,23 +1918,31 @@
                 // that can be done at this point. TODO(jcivelli) http://b/5910521 - we should show
                 // an error page instead of a blank page in that case (and the last loaded URL).
                 webContents = WebContentsFactory.createWebContents(isIncognito(), isHidden());
-                forceNavigate = true;
+                mTabUma = new TabUma(TabCreationState.FROZEN_ON_RESTORE_FAILED);
+                mFailedToRestore = true;
             }
 
             mFrozenContentsState = null;
             initContentViewCore(webContents);
 
-            if (forceNavigate) {
+            if (mFailedToRestore) {
                 String url = TextUtils.isEmpty(mUrl) ? UrlConstants.NTP_URL : mUrl;
                 loadUrl(new LoadUrlParams(url, PageTransition.GENERATED));
             }
-            return !forceNavigate;
+            return !mFailedToRestore;
         } finally {
             TraceEvent.end("Tab.unfreezeContents");
         }
     }
 
     /**
+     * @return Whether the unfreeze attempt from a saved tab state failed.
+     */
+    public boolean didFailToRestore() {
+        return mFailedToRestore;
+    }
+
+    /**
      * @return Whether or not the tab is hidden.
      */
     public boolean isHidden() {
@@ -2683,6 +2687,21 @@
     }
 
     /**
+     * @return The most recently used rank for this tab in the given TabModel.
+     */
+    private static int computeMRURank(Tab tab, TabModel model) {
+        final long tabLastShow = tab.getTabUma().getLastShownTimestamp();
+        int mruRank = 0;
+        for (int i = 0; i < model.getCount(); i++) {
+            Tab otherTab = model.getTabAt(i);
+            if (otherTab != tab && otherTab.getTabUma().getLastShownTimestamp() > tabLastShow) {
+                mruRank++;
+            }
+        }
+        return mruRank;
+    }
+
+    /**
      * Sets the Intent that can be fired to restart the Activity of this Tab's parent.
      * Should only be called if the Tab was launched via a different Activity.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUma.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUma.java
index 19d10df..dc283f7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUma.java
@@ -7,7 +7,6 @@
 import android.os.SystemClock;
 
 import org.chromium.base.metrics.RecordHistogram;
-import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
 import org.chromium.net.NetError;
 
@@ -56,9 +55,6 @@
     // Counter of tab shows (as per onShow()) for all tabs.
     private static long sAllTabsShowCount = 0;
 
-    private final Tab mTab;
-    private final TabModel mTabModel;
-
     /**
      * State in which the tab was created. This can be used in metric accounting - e.g. to
      * distinguish reasons for a tab to be restored upon first display.
@@ -67,13 +63,14 @@
         LIVE_IN_FOREGROUND,
         LIVE_IN_BACKGROUND,
         FROZEN_ON_RESTORE,
-        FROZEN_FOR_LAZY_LOAD
+        FROZEN_FOR_LAZY_LOAD,
+        FROZEN_ON_RESTORE_FAILED,
     }
 
     private final TabCreationState mTabCreationState;
 
     // Timestamp when this tab was last shown.
-    private long mLastShowMillis = -1;
+    private long mLastShownTimestamp = -1;
 
     // Timestamp of the beginning of the current tab restore.
     private long mRestoreStartedAtMillis = -1;
@@ -83,14 +80,10 @@
 
     /**
      * Constructs a new UMA tracker for a specific tab.
-     * @param tab The tab whose metrics we want to track.
      * @param creationState In what state the tab was created.
-     * @param model The tab model that contains this tab.
      */
-    public TabUma(Tab tab, TabCreationState creationState, TabModel model) {
-        mTab = tab;
+    public TabUma(TabCreationState creationState) {
         mTabCreationState = creationState;
-        mTabModel = model;
 
         mLastTabStateChangeMillis = System.currentTimeMillis();
         if (mTabCreationState == TabCreationState.LIVE_IN_FOREGROUND
@@ -99,6 +92,11 @@
         } else if (mTabCreationState == TabCreationState.LIVE_IN_BACKGROUND
                 || mTabCreationState == TabCreationState.FROZEN_FOR_LAZY_LOAD) {
             updateTabState(TAB_STATE_INACTIVE);
+        } else if (mTabCreationState == TabCreationState.FROZEN_ON_RESTORE_FAILED) {
+            // A previous TabUma should have reported an active tab state. Initialize but avoid
+            // recording this as a state change.
+            mLastTabState = TAB_STATE_ACTIVE;
+            updateTabState(TAB_STATE_ACTIVE);
         }
     }
 
@@ -187,29 +185,29 @@
      * @param selectionType determines how the tab was being shown
      * @param previousTimestampMillis time of the previous display or creation time for the tabs
      *                                opened in background and not yet displayed
+     * @param rank The MRU rank for this tab within the model.
      */
-    void onShow(TabSelectionType selectionType, long previousTimestampMillis) {
+    void onShow(TabSelectionType selectionType, long previousTimestampMillis, int rank) {
         long now = SystemClock.elapsedRealtime();
         // Do not collect the tab switching data for the first switch to a tab after the cold start
         // and for the tab switches that were not user-originated (e.g. the user closes the last
         // incognito tab and the current normal mode tab is shown).
-        if (mLastShowMillis != -1 && selectionType == TabSelectionType.FROM_USER) {
-            long age = now - mLastShowMillis;
-            int rank = computeMRURank(mTab, mTabModel);
+        if (mLastShownTimestamp != -1 && selectionType == TabSelectionType.FROM_USER) {
+            long age = now - mLastShownTimestamp;
             RecordHistogram.recordCountHistogram("Tab.SwitchedToForegroundAge", (int) age);
             RecordHistogram.recordCountHistogram("Tab.SwitchedToForegroundMRURank", rank);
         }
 
         increaseTabShowCount();
         boolean isOnBrowserStartup = sAllTabsShowCount == 1;
-        boolean performsLazyLoad =
-                mTabCreationState == TabCreationState.FROZEN_FOR_LAZY_LOAD && mLastShowMillis == -1;
+        boolean performsLazyLoad = mTabCreationState == TabCreationState.FROZEN_FOR_LAZY_LOAD
+                && mLastShownTimestamp == -1;
 
         int status;
         if (mRestoreStartedAtMillis == -1 && !performsLazyLoad) {
             // The tab is *not* being restored or loaded lazily on first display.
             status = TAB_STATUS_MEMORY_RESIDENT;
-        } else if (mLastShowMillis == -1) {
+        } else if (mLastShownTimestamp == -1) {
             // This is first display and the tab is being restored or loaded lazily.
             if (isOnBrowserStartup) {
                 status = TAB_STATUS_RELOAD_COLD_START_FG;
@@ -236,7 +234,7 @@
         }
 
         // Record Tab.BackgroundLoadStatus.
-        if (mLastShowMillis == -1) {
+        if (mLastShownTimestamp == -1) {
             if (mTabCreationState == TabCreationState.LIVE_IN_BACKGROUND) {
                 if (mRestoreStartedAtMillis == -1) {
                     RecordHistogram.recordEnumeratedHistogram("Tab.BackgroundLoadStatus",
@@ -254,7 +252,7 @@
 
         // Record "tab age upon first display" metrics. previousTimestampMillis is persisted through
         // cold starts.
-        if (mLastShowMillis == -1 && previousTimestampMillis > 0) {
+        if (mLastShownTimestamp == -1 && previousTimestampMillis > 0) {
             if (isOnBrowserStartup) {
                 RecordHistogram.recordCountHistogram("Tabs.ForegroundTabAgeAtStartup",
                         (int) millisecondsToMinutes(System.currentTimeMillis()
@@ -266,7 +264,7 @@
             }
         }
 
-        mLastShowMillis = now;
+        mLastShownTimestamp = now;
 
         updateTabState(TAB_STATE_ACTIVE);
     }
@@ -289,10 +287,10 @@
         // Record only tab restores that the user became aware of. If the restore is triggered
         // speculatively and completes before the user switches to the tab, then this case is
         // reflected in Tab.StatusWhenSwitchedBackToForeground metric.
-        if (mRestoreStartedAtMillis != -1 && mLastShowMillis >= mRestoreStartedAtMillis) {
+        if (mRestoreStartedAtMillis != -1 && mLastShownTimestamp >= mRestoreStartedAtMillis) {
             long now = SystemClock.elapsedRealtime();
             long restoreTime = now - mRestoreStartedAtMillis;
-            long perceivedRestoreTime = now - mLastShowMillis;
+            long perceivedRestoreTime = now - mLastShownTimestamp;
             recordTabRestoreResult(true, restoreTime, perceivedRestoreTime, -1);
         }
         mRestoreStartedAtMillis = -1;
@@ -300,7 +298,7 @@
 
     /** Called when the correspoding tab fails a page load. */
     void onLoadFailed(int errorCode) {
-        if (mRestoreStartedAtMillis != -1 && mLastShowMillis >= mRestoreStartedAtMillis) {
+        if (mRestoreStartedAtMillis != -1 && mLastShownTimestamp >= mRestoreStartedAtMillis) {
             // Load time is ignored for failed loads.
             recordTabRestoreResult(false, -1, -1, errorCode);
         }
@@ -316,6 +314,13 @@
         }
     }
 
+    /**
+     * @return The timestamp for when this tab was last shown.
+     */
+    long getLastShownTimestamp() {
+        return mLastShownTimestamp;
+    }
+
     private static void increaseTabShowCount() {
         sAllTabsShowCount++;
     }
@@ -323,19 +328,4 @@
     private static long millisecondsToMinutes(long msec) {
         return msec / 1000 / 60;
     }
-
-    /**
-     * @return The most recently used rank for this tab in [0 .. tabs.length - 1].
-     */
-    private static int computeMRURank(Tab tab, TabModel model) {
-        final long tabLastShow = tab.getTabUma().mLastShowMillis;
-        int mruRank = 0;
-        for (int i = 0; i < model.getCount(); i++) {
-            Tab otherTab = model.getTabAt(i);
-            if (otherTab != tab && otherTab.getTabUma().mLastShowMillis > tabLastShow) {
-                mruRank++;
-            }
-        }
-        return mruRank;
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/StorageDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/StorageDelegate.java
index d66e754..ce5ed3b2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/StorageDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/StorageDelegate.java
@@ -6,7 +6,6 @@
 
 import android.content.Context;
 import android.os.AsyncTask;
-import android.os.StrictMode;
 import android.util.SparseArray;
 
 import com.google.protobuf.nano.MessageNano;
@@ -28,6 +27,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.List;
+import java.util.concurrent.ExecutionException;
 
 /**
  * Contains functions for interacting with the file system.
@@ -44,6 +44,16 @@
     /** The buffer size to use when reading the DocumentTabModel file, set to 4k bytes. */
     private static final int BUF_SIZE = 0x1000;
 
+    /** Cached base state directory to prevent main-thread filesystem access in getStateDirectory().
+     */
+    private static AsyncTask<Void, Void, File> sBaseStateDirectoryFetchTask;
+
+    public StorageDelegate() {
+        // Warm up the state directory to prevent it from using filesystem on main thread in the
+        // future
+        preloadStateDirectory();
+    }
+
     /**
      * Reads the file containing the minimum info required to restore the state of the
      * {@link DocumentTabModel}.
@@ -104,17 +114,33 @@
         }
     }
 
+    private void preloadStateDirectory() {
+        if (sBaseStateDirectoryFetchTask != null) {
+            return;
+        }
+
+        sBaseStateDirectoryFetchTask = new AsyncTask<Void, Void, File>() {
+            @Override
+            protected File doInBackground(Void... params) {
+                return ApplicationStatus.getApplicationContext().getDir(
+                        STATE_DIRECTORY, Context.MODE_PRIVATE);
+            }
+        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    }
+
     /** @return The directory that stores the TabState files. */
     @Override
     public File getStateDirectory() {
-        // Temporarily allowing disk access while fixing. TODO: http://crbug.com/543201
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
         try {
-            return ApplicationStatus.getApplicationContext().getDir(
-                    STATE_DIRECTORY, Context.MODE_PRIVATE);
-        } finally {
-            StrictMode.setThreadPolicy(oldPolicy);
+            return sBaseStateDirectoryFetchTask.get();
+        } catch (InterruptedException e) {
+        } catch (ExecutionException e) {
         }
+
+        // If the AsyncTask failed for some reason, we have no choice but to fall back to
+        // main-thread disk access.
+        return ApplicationStatus.getApplicationContext().getDir(
+                STATE_DIRECTORY, Context.MODE_PRIVATE);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelListItem.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelListItem.java
index a6812fc..4a9a31a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelListItem.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelListItem.java
@@ -74,6 +74,7 @@
     private final GestureDetector mSwipeGestureDetector;
     private final int mDefaultHeight;
     private AccessibilityTabModelListView mCanScrollListener;
+    private boolean mCloseButtonClicked;
 
     /**
      * An interface that exposes actions taken on this item.  The registered listener will be
@@ -140,6 +141,7 @@
         @Override
         public void onAnimationCancel(Animator animation) {
             mIsCancelled = true;
+            mCloseButtonClicked = false;
         }
 
         @Override
@@ -172,6 +174,7 @@
         @Override
         public void onAnimationCancel(Animator animation) {
             mIsCancelled = true;
+            mCloseButtonClicked = false;
         }
 
         @Override
@@ -300,6 +303,7 @@
         if (v == AccessibilityTabModelListItem.this && !mListener.hasPendingClosure(tabId)) {
             mListener.tabSelected(tabId);
         } else if (v == mCloseButton) {
+            mCloseButtonClicked = true;
             if (mCanUndo) {
                 runBlinkOutAnimation();
             } else {
@@ -345,6 +349,18 @@
 
     private final TabObserver mTabObserver = new EmptyTabObserver() {
         @Override
+        public void onClosingStateChanged(Tab tab, boolean closing) {
+            // If the tab is closed through something other than interacting with the ListItem
+            // itself (e.g. the tab strip), we need to notify the listener of the change.
+            // See https://crbug.com/567863.
+            if (closing && !mCloseButtonClicked) {
+                if (mListener != null) {
+                    mListener.tabChanged(tab.getId());
+                }
+            }
+        }
+
+        @Override
         public void onFaviconUpdated(Tab tab, Bitmap icon) {
             updateFavicon();
             notifyTabUpdated(tab);
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 006c224e..bf42b9f5 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -203,9 +203,6 @@
       <message name="IDS_PREFS_SEARCH_ENGINE" desc="Title for Search Engine preferences. [CHAR-LIMIT=32]">
         Search engine
       </message>
-      <message name="IDS_SEARCH_ENGINE_NAME_AND_DOMAIN" desc="Label for a search engine, that includes its name and its domain, e.g. Google (google.co.uk).">
-        <ph name="SEARCH_ENGINE_NAME">%1$s<ex>Google</ex></ph> (<ph name="SEARCH_ENGINE_DOMAIN">%2$s<ex>google.co.uk</ex></ph>)
-      </message>
       <message name="IDS_SEARCH_ENGINE_LOCATION_ALLOWED" desc="The text of a link displayed when location permission for a particular search engine is allowed.">
         Location is allowed
       </message>
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/printing/PrintingControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/printing/PrintingControllerTest.java
index 2b0a86b..198795c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/printing/PrintingControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/printing/PrintingControllerTest.java
@@ -13,10 +13,10 @@
 import android.print.PrintDocumentAdapter;
 import android.print.PrintDocumentInfo;
 import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.TestFileUtil;
 import org.chromium.base.test.util.UrlUtils;
@@ -157,15 +157,14 @@
 
     /**
      * Test for http://crbug.com/528909
-     *
-     * Bug: http://crbug.com/532652
-     * @SmallTest
-     * @Feature({"Printing"})
      */
+    @SmallTest
+    @Feature({"Printing"})
     @CommandLineFlags.Add(
             {ContentSwitches.DISABLE_POPUP_BLOCKING, ChromeSwitches.DISABLE_DOCUMENT_MODE})
-    @DisabledTest
     public void testPrintClosedWindow() throws Throwable {
+        if (!ApiCompatibilityUtils.isPrintingSupported()) return;
+
         String html = "<html><head><title>printwindowclose</title></head><body><script>"
                 + "function printClosedWindow() {"
                 + "  w = window.open(); w.close();"
@@ -179,7 +178,7 @@
 
         TabTitleObserver mOnTitleUpdatedHelper = new TabTitleObserver(mTab, "completed");
         runJavaScriptCodeInCurrentTab("printClosedWindow();");
-        mOnTitleUpdatedHelper.waitForTitleUpdate(2);
+        mOnTitleUpdatedHelper.waitForTitleUpdate(5);
         assertEquals("JS did not finish running", "completed", mTab.getTitle());
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateOptionsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateOptionsTest.java
index 3e53baa..0197fdd6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateOptionsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateOptionsTest.java
@@ -10,21 +10,33 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.infobar.TranslateOptions;
 
+import java.util.ArrayList;
+
 /**
  * Test for TranslateOptions.
  */
 public class TranslateOptionsTest extends AndroidTestCase {
-    private static final String[] LANGUAGES = {"English", "Spanish", "French"};
     private static final boolean ALWAYS_TRANSLATE = true;
+    private ArrayList<TranslateOptions.TranslateLanguagePair> mLanguages = null;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mLanguages = new ArrayList<TranslateOptions.TranslateLanguagePair>();
+        mLanguages.add(new TranslateOptions.TranslateLanguagePair("en", "English"));
+        mLanguages.add(new TranslateOptions.TranslateLanguagePair("es", "Spanish"));
+        mLanguages.add(new TranslateOptions.TranslateLanguagePair("fr", "French"));
+    }
 
     @SmallTest
     @Feature({"Translate"})
     public void testNoChanges() {
-        TranslateOptions options = new TranslateOptions(0, 1, LANGUAGES, ALWAYS_TRANSLATE, false);
-        assertEquals("English", options.sourceLanguage());
-        assertEquals("Spanish", options.targetLanguage());
-        assertEquals(0, options.sourceLanguageIndex());
-        assertEquals(1, options.targetLanguageIndex());
+        TranslateOptions options =
+                new TranslateOptions("en", "es", mLanguages, ALWAYS_TRANSLATE, false);
+        assertEquals("English", options.sourceLanguageName());
+        assertEquals("Spanish", options.targetLanguageName());
+        assertEquals("en", options.sourceLanguageCode());
+        assertEquals("es", options.targetLanguageCode());
         assertFalse(options.neverTranslateLanguageState());
         assertTrue(options.alwaysTranslateLanguageState());
         assertFalse(options.neverTranslateDomainState());
@@ -34,48 +46,52 @@
     @SmallTest
     @Feature({"Translate"})
     public void testBasicLanguageChanges() {
-        TranslateOptions options = new TranslateOptions(0, 1, LANGUAGES, !ALWAYS_TRANSLATE, true);
-        options.setTargetLanguage(2);
-        options.setSourceLanguage(1);
-        assertEquals("Spanish", options.sourceLanguage());
-        assertEquals("French", options.targetLanguage());
-        assertEquals(1, options.sourceLanguageIndex());
-        assertEquals(2, options.targetLanguageIndex());
+        TranslateOptions options =
+                new TranslateOptions("en", "es", mLanguages, !ALWAYS_TRANSLATE, true);
+        options.setTargetLanguage("fr");
+        options.setSourceLanguage("en");
+        assertEquals("English", options.sourceLanguageName());
+        assertEquals("French", options.targetLanguageName());
+        assertEquals("en", options.sourceLanguageCode());
+        assertEquals("fr", options.targetLanguageCode());
         assertTrue(options.triggeredFromMenu());
+
         assertTrue(options.optionsChanged());
 
         // Switch back to the original
-        options.setSourceLanguage(0);
-        options.setTargetLanguage(1);
+        options.setSourceLanguage("en");
+        options.setTargetLanguage("es");
         assertFalse(options.optionsChanged());
     }
 
     @SmallTest
     @Feature({"Translate"})
     public void testInvalidLanguageChanges() {
-        TranslateOptions options = new TranslateOptions(0, 1, LANGUAGES, ALWAYS_TRANSLATE, false);
+        TranslateOptions options =
+                new TranslateOptions("en", "es", mLanguages, ALWAYS_TRANSLATE, false);
 
         // Same target language as source
-        assertFalse(options.setTargetLanguage(0));
+        assertFalse(options.setTargetLanguage("en"));
         assertFalse(options.optionsChanged());
 
-        // Target language out of range
-        assertFalse(options.setTargetLanguage(23));
+        // Target language does not exist
+        assertFalse(options.setTargetLanguage("aaa"));
         assertFalse(options.optionsChanged());
 
         // Same source and target
-        assertFalse(options.setSourceLanguage(1));
+        assertFalse(options.setSourceLanguage("es"));
         assertFalse(options.optionsChanged());
 
-        // Source language out of range
-        assertFalse(options.setSourceLanguage(23));
+        // Source language does not exist
+        assertFalse(options.setSourceLanguage("bbb"));
         assertFalse(options.optionsChanged());
     }
 
     @SmallTest
     @Feature({"Translate"})
     public void testBasicOptionsChanges() {
-        TranslateOptions options = new TranslateOptions(0, 1, LANGUAGES, !ALWAYS_TRANSLATE, false);
+        TranslateOptions options =
+                new TranslateOptions("en", "es", mLanguages, !ALWAYS_TRANSLATE, false);
         assertFalse(options.optionsChanged());
         options.toggleNeverTranslateDomainState(true);
         assertTrue(options.neverTranslateDomainState());
@@ -99,9 +115,11 @@
     @SmallTest
     @Feature({"Translate"})
     public void testInvalidOptionsChanges() {
-        TranslateOptions options = new TranslateOptions(0, 1, LANGUAGES, ALWAYS_TRANSLATE, false);
+        TranslateOptions options =
+                new TranslateOptions("en", "es", mLanguages, ALWAYS_TRANSLATE, false);
 
-        // Never translate language should not work, but never translate domain should
+        // Never translate language should not work, but never translate domain
+        // should
         assertFalse(options.toggleNeverTranslateLanguageState(true));
         assertTrue(options.toggleNeverTranslateDomainState(true));
         assertTrue(options.optionsChanged());
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 984fcfc5..2aba03e9 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
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.widget;
 
 import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_PHONE;
+import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_TABLET;
 
 import android.os.SystemClock;
 import android.test.suitebuilder.annotation.MediumTest;
@@ -19,6 +20,7 @@
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutTab;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModel;
@@ -26,6 +28,7 @@
 import org.chromium.chrome.test.ChromeTabbedActivityTestBase;
 import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.chrome.test.util.MenuUtils;
+import org.chromium.chrome.test.util.TabStripUtils;
 import org.chromium.chrome.test.util.browser.TabLoadObserver;
 import org.chromium.content.browser.test.util.CallbackHelper;
 import org.chromium.content.browser.test.util.Criteria;
@@ -407,4 +410,33 @@
         toggleTabSwitcher(true);
         assertEquals("Page 2", getTabTitleOfListItem(0));
     }
+
+    @Restriction(RESTRICTION_TYPE_TABLET)
+    @MediumTest
+    @Feature({"Accessibility"})
+    public void testCloseTabThroughTabStrip() throws InterruptedException, TimeoutException {
+        setupTabs();
+
+        getListItemAndDisableAnimations(0);
+        final CallbackHelper didReceiveClosureCommittedHelper = new CallbackHelper();
+        final TabModel model = getActivity().getCurrentTabModel();
+        model.addObserver(new EmptyTabModelObserver() {
+            @Override
+            public void tabClosureCommitted(Tab tab) {
+                didReceiveClosureCommittedHelper.notifyCalled();
+            }
+        });
+
+        StripLayoutTab tab = TabStripUtils.findStripLayoutTab(getActivity(), false,
+                model.getTabAt(0).getId());
+        TabStripUtils.clickCompositorButton(tab.getCloseButton(), this);
+        didReceiveClosureCommittedHelper.waitForCallback(0);
+
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                assertEquals("Tab not closed", 3, getList().getChildCount());
+            }
+        });
+    }
 }
diff --git a/chrome/app/chrome_watcher_client_unittest_win.cc b/chrome/app/chrome_watcher_client_unittest_win.cc
index e3549e9..e62e24a 100644
--- a/chrome/app/chrome_watcher_client_unittest_win.cc
+++ b/chrome/app/chrome_watcher_client_unittest_win.cc
@@ -20,6 +20,7 @@
 #include "base/threading/simple_thread.h"
 #include "base/time/time.h"
 #include "base/win/scoped_handle.h"
+#include "base/win/win_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/multiprocess_func_list.h"
 
@@ -170,12 +171,12 @@
     base::CommandLine ret = base::GetMultiProcessTestChildBaseCommandLine();
     ret.AppendSwitchASCII(switches::kTestChildProcess,
                           "ChromeWatcherClientTestProcess");
-    ret.AppendSwitchASCII(kEventHandle,
-                          base::UintToString(reinterpret_cast<unsigned int>(
-                              on_initialized_event)));
+    ret.AppendSwitchASCII(
+        kEventHandle,
+        base::UintToString(base::win::HandleToUint32(on_initialized_event)));
     ret.AppendSwitchASCII(
         kParentHandle,
-        base::UintToString(reinterpret_cast<unsigned int>(parent_handle)));
+        base::UintToString(base::win::HandleToUint32(parent_handle)));
 
     // Our child does not actually need the main thread ID, but we verify here
     // that the correct ID is being passed from the client.
diff --git a/chrome/app/chrome_watcher_command_line_win.cc b/chrome/app/chrome_watcher_command_line_win.cc
index 12b3e14..d5318a63 100644
--- a/chrome/app/chrome_watcher_command_line_win.cc
+++ b/chrome/app/chrome_watcher_command_line_win.cc
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "base/win/win_util.h"
 #include "chrome/common/chrome_switches.h"
 #include "content/public/common/content_switches.h"
 
@@ -24,7 +25,7 @@
                         HANDLE handle,
                         base::CommandLine* command_line) {
   command_line->AppendSwitchASCII(
-      switch_name, base::UintToString(reinterpret_cast<uint32_t>(handle)));
+      switch_name, base::UintToString(base::win::HandleToUint32(handle)));
 }
 
 uint32_t ReadUintSwitch(const base::CommandLine& command_line,
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 76a6618c..d4c6038e 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -2062,10 +2062,10 @@
   <message name="IDS_OPTIONS_POWER_SOURCE_PORT_LEFT_BACK" desc="The text identifying an external device, when that device is connected to a USB Type-C port on the left side of this device. In this case there are two ports on that side, so this text should refer to the back one on that side.">
     USB-C device (left side back port)
   </message>
-  <message name="IDS_OPTIONS_POWER_SOURCE_PORT_RIGHT_FRONT" desc="The text identifying an external device, when that device is connected to a USB Type-C port on the right side of this device. In this case there are two ports on that side, so this text should refer to the front one on that side.">">
+  <message name="IDS_OPTIONS_POWER_SOURCE_PORT_RIGHT_FRONT" desc="The text identifying an external device, when that device is connected to a USB Type-C port on the right side of this device. In this case there are two ports on that side, so this text should refer to the front one on that side.">
     USB-C device (right side front port)
   </message>
-  <message name="IDS_OPTIONS_POWER_SOURCE_PORT_RIGHT_BACK" desc="The text identifying an external device, when that device is connected to a USB Type-C port on the right side of this device. In this case there are two ports on that side, so this text should refer to the back one on that side.">">
+  <message name="IDS_OPTIONS_POWER_SOURCE_PORT_RIGHT_BACK" desc="The text identifying an external device, when that device is connected to a USB Type-C port on the right side of this device. In this case there are two ports on that side, so this text should refer to the back one on that side.">
     USB-C device (right side back port)
   </message>
   <message name="IDS_OPTIONS_POWER_SOURCE_PORT_BACK_LEFT" desc="The text identifying an external device, when that device is connected to a USB Type-C port on the back of this device. In this case there are two ports on the back, so this text should refer to the one on the left.">
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 0432431..06f03f7 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -449,9 +449,6 @@
         Chromium may use web services to improve your browsing experience.
       </message>
       <if expr="is_win">
-        <message name="IDS_OEM_MAIN_SHORTCUT_NAME" desc="Name of the desktop shortcut to start the application for OEM pre-installations.">
-          Web Browser
-        </message>
         <message name="IDS_SHORTCUT_TOOLTIP" desc="Text for the hover-on tooltip for the Chromium shortcuts.">
           Access the Internet
         </message>
@@ -655,6 +652,9 @@
         <message name="IDS_EXTENSION_INSTALLED_HEADING" desc="First line in the content area of the extension installed bubble. Instructs that the extension was installed.">
           <ph name="EXTENSION_NAME">$1<ex>Gmail Checker</ex></ph> has been added to Chromium.
         </message>
+        <message name="IDS_EXTENSION_INSTALLED_SYNC_PROMO_LINK_NEW" desc="Text of the link to sign in to Chromium from the extension installed bubble. This will be converted to a link, with additional text around it.">
+          sign in to Chromium
+        </message>
         <message name="IDS_EXTENSION_INSTALLED_SIGNIN_PROMO_LINK" desc="The first part of the sign-in promo paragraph. This part will be converted to a link and will get more text appended to it (see IDS_EXTENSION_INSTALLED_SIGNIN_PROMO). Keep this text short.">
           Sign in to Chromium
         </message>
diff --git a/chrome/app/close_handle_hook_win.cc b/chrome/app/close_handle_hook_win.cc
index a0dc2f4..28bfb3e8 100644
--- a/chrome/app/close_handle_hook_win.cc
+++ b/chrome/app/close_handle_hook_win.cc
@@ -143,8 +143,8 @@
 
   // Perform the patch.
 #pragma warning(push)
-#pragma warning(disable: 4311)
-  // These casts generate warnings because they are 32 bit specific.
+#pragma warning(disable : 4311 4302)
+  // These casts generate truncation warnings because they are 32 bit specific.
   *eat_entry = reinterpret_cast<DWORD>(new_function) -
                reinterpret_cast<DWORD>(module);
 #pragma warning(pop)
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 7f1c108..1325b5b 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4411,6 +4411,9 @@
         <message name="IDS_EXTENSION_INSTALLED_MANAGE_SHORTCUTS" desc="Text for the link in the InfoBubble that opens the chrome://extensions page with the Configure Commands UI visible.">
           Manage shortcuts
         </message>
+        <message name="IDS_EXTENSION_INSTALLED_SYNC_PROMO_NEW" desc="Text of the sync promo at the bottom of the extension installed bubble, prompting the user to sign in in order to sync extensions.">
+          To get your extensions on all your computers, <ph name="SIGN_IN_LINK">$1<ex>sign in to Chrome</ex></ph>.
+        </message>
         <message name="IDS_EXTENSION_INSTALLED_SIGNIN_PROMO" desc="The remaining text of the sign-in promo paragraph. Will be appended as a label to the string above. The triple single quotes are needed to preserve the space before the word 'to' (which is handy when the language (Chrome is being translated to) uses space as word separator).">
           ''' to get this extension, your history, and other Chrome settings on all your devices.'''
         </message>
@@ -6029,11 +6032,6 @@
       <message name="IDS_PASSWORD_MANAGER_SMART_LOCK_WELCOME" desc="A warm welcome message displayed once in the Save password bubble for users which are signed-in to Chrome.">
         Smart Lock helps you quickly sign in to apps and sites using passwords you have saved with Google.
       </message>
-      <if expr="is_android">
-        <message name="IDS_PASSWORD_MANAGER_SMART_LOCK_PAGE" desc="URL of the passwords dashboard.">
-          https://passwords.google.com/?hl=[GRITLANGCODE]
-        </message>
-      </if>
       <message name="IDS_FLAGS_SUGGESTIONS_WITH_SUB_STRING_MATCH_NAME" desc="Name of the flag for substring matching for Autofill suggestions.">
         Substring matching for Autofill suggestions
       </message>
@@ -6683,6 +6681,14 @@
       <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>
+      <if expr="is_win or is_linux">
+        <message name="IDS_FLAGS_ENABLE_INPUT_IME_API_NAME" desc="Name of the flag to enable che chrome.input.ime API.">
+          Enable Input IME API
+        </message>
+        <message name="IDS_FLAGS_ENABLE_INPUT_IME_API_DESCRIPTION" desc="Description of the flag to enable the chrome.input.ime API.">
+          Enable the use of chrome.input.ime API.
+        </message>
+      </if>
 
       <!-- WebRTC logs -->
       <message name="IDS_WEBRTC_LOGS_TITLE" desc="Title for the chrome://webrtc-logs page.">
@@ -9198,17 +9204,6 @@
        Unlock
       </message>
 
-      <!-- HTTP POST Warning -->
-      <message name="IDS_HTTP_POST_WARNING_TITLE" desc="Title for dialog that warns users about a navigation that results in a repost">
-        Confirm Form Resubmission
-      </message>
-      <message name="IDS_HTTP_POST_WARNING" desc="Re-navigation to page that leads to HTTP POST" formatter_data="android_java">
-        The page that you're looking for used information that you entered. Returning to that page might cause any action you took to be repeated. Do you want to continue?
-      </message>
-      <message name="IDS_HTTP_POST_WARNING_RESEND" desc="Resend button for post warning" formatter_data="android_java">
-        Continue
-      </message>
-
       <!-- Menus -->
       <if expr="is_macosx">
         <message name="IDS_MENU_EMPTY_SUBMENU" desc="Used when a submenu has no entries">
@@ -10011,15 +10006,6 @@
       </if>
 
       <!-- chrome://settings strings that are used by all platforms including Android -->
-      <message name="IDS_SETTINGS_TITLE" desc="Title for the settings tab.">
-        Settings
-      </message>
-      <message name="IDS_SETTINGS_HIDE_ADVANCED_SETTINGS" desc="Title for the link to hide advanced settings.">
-        Hide advanced settings...
-      </message>
-      <message name="IDS_SETTINGS_SHOW_ADVANCED_SETTINGS" desc="Title for the link to show advanced settings.">
-        Show advanced settings...
-      </message>
       <message name="IDS_OPTIONS_PASSWORDS_MANAGE_PASSWORDS_LINK" desc="The label of the 'Manage passwords' link">
         Manage passwords
       </message>
@@ -10223,11 +10209,6 @@
         Get themes
       </message>
 
-      <!-- Misc advanced option description strings. -->
-      <message name="IDS_NETWORK_PREDICTION_ENABLED_DESCRIPTION" desc="In the advanced options tab, the text next to the checkbox that enables prediction of network actions.  Actions include DNS prefetching, TCP and SSL preconnection, and prerendering of webpages.">
-        Prefetch resources to load pages more quickly
-      </message>
-
       <!-- Collected cookies window -->
       <message name="IDS_COLLECTED_COOKIES_DIALOG_TITLE" desc="The title of the collect cookies dialog">
         Cookies set by this page
@@ -11155,9 +11136,6 @@
       <message name="IDS_OPTIONS_FONTSETTINGS_CUSTOMIZE_FONTS_BUTTON" desc="The label of the 'Customize fonts' button">
         Customize fonts...
       </message>
-      <message name="IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON" desc="The label of the 'Configure proxy settings' button">
-        Change proxy settings...
-      </message>
       <message name="IDS_OPTIONS_CERTIFICATES_MANAGE_BUTTON" desc="The label of the 'Manage Certificates' button">
         Manage certificates...
       </message>
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index 5fe43fd..49c8c7c 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -450,9 +450,6 @@
         Google Chrome may use web services to improve your browsing experience.
       </message>
       <if expr="is_win">
-        <message name="IDS_OEM_MAIN_SHORTCUT_NAME" desc="Name of the desktop shortcut to start the application for OEM pre-installations.">
-          Web Browser
-        </message>
         <message name="IDS_SHORTCUT_TOOLTIP" desc="Text for the hover-on tooltip for the Google Chrome shortcuts.">
           Access the Internet
         </message>
@@ -656,6 +653,9 @@
         <message name="IDS_EXTENSION_INSTALLED_HEADING" desc="First line in the content area of the extension installed bubble. Instructs that the extension was installed.">
           <ph name="EXTENSION_NAME">$1<ex>Gmail Checker</ex></ph> has been added to Chrome.
         </message>
+        <message name="IDS_EXTENSION_INSTALLED_SYNC_PROMO_LINK_NEW" desc="Text of the link to sign in to Chrome from the extension installed bubble. This will be converted to a link, with additional text around it.">
+          sign in to Chrome
+        </message>
         <message name="IDS_EXTENSION_INSTALLED_SIGNIN_PROMO_LINK" desc="The first part of the sign-in promo paragraph. This part will be converted to a link and will get more text appended to it (see IDS_EXTENSION_INSTALLED_SIGNIN_PROMO). Keep this text short.">
           Sign in to Chrome
         </message>
diff --git a/chrome/app/media_router_strings.grdp b/chrome/app/media_router_strings.grdp
index 62fc3991..79808ce 100644
--- a/chrome/app/media_router_strings.grdp
+++ b/chrome/app/media_router_strings.grdp
@@ -13,6 +13,9 @@
   </message>
 
   <!-- Cast Modes -->
+  <message name="IDS_MEDIA_ROUTER_AUTO_CAST_MODE" desc="Title for auto cast mode that appears as the header of a list of devices. This represents the mode that will be initially shown, if the list of sinks supports more than one of the cast modes below. Note that auto mode is not a real cast mode and merely serves as a proxy for the other cast modes. This is NOT shown as a dropdown option.">
+    Cast to
+  </message>
   <message name="IDS_MEDIA_ROUTER_DEFAULT_CAST_MODE" desc="Title for the default cast mode, which is used when the host is cast enabled. This is shown as a dropdown option, and if selected, also appears as the header of a list of devices.">
     Cast <ph name="HOST_NAME">$1<ex>google.com</ex></ph>
   </message>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index ade3803..0068375 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -397,15 +397,6 @@
     chromeos::switches::kDataSaverPromptDemoMode },
 };
 
-const FeatureEntry::Choice kDownloadNotificationChoices[] = {
-  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
-  { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
-    switches::kEnableDownloadNotification,
-    "enabled" },
-  { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
-    switches::kEnableDownloadNotification,
-    "disabled" }
-};
 #endif
 
 const FeatureEntry::Choice kSupervisedUserSafeSitesChoices[] = {
@@ -803,11 +794,11 @@
      kOsDesktop,
      SINGLE_VALUE_TYPE(switches::kEnableDownloadResumption)},
 #if defined(OS_CHROMEOS)
-    {"enable-download-notification",
+    {"download-notification",
      IDS_FLAGS_DOWNLOAD_NOTIFICATION_NAME,
      IDS_FLAGS_DOWNLOAD_NOTIFICATION_DESCRIPTION,
      kOsCrOS,
-     MULTI_VALUE_TYPE(kDownloadNotificationChoices)},
+     SINGLE_DISABLE_VALUE_TYPE(switches::kDisableDownloadNotification)},
 #endif
 #if defined(ENABLE_PLUGINS)
     {"allow-nacl-socket-api",
@@ -1978,15 +1969,13 @@
      ENABLE_DISABLE_VALUE_TYPE(switches::kEnablePushApiBackgroundMode,
                                switches::kDisablePushApiBackgroundMode)},
 #endif  // defined(ENABLE_BACKGROUND)
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
-     // TODO(reillyg): Remove this flag when the permission granting UI is
-     // available. crbug.com/529950
-     {"enable-webusb-on-any-origin",
-      IDS_FLAGS_ENABLE_WEBUSB_ON_ANY_ORIGIN_NAME,
-      IDS_FLAGS_ENABLE_WEBUSB_ON_ANY_ORIGIN_DESCRIPTION,
-      kOsDesktop,
-      SINGLE_VALUE_TYPE(switches::kEnableWebUsbOnAnyOrigin)},
-#endif
+    // TODO(reillyg): Remove this flag when the permission granting UI is
+    // available. crbug.com/529950
+    {"enable-webusb-on-any-origin",
+     IDS_FLAGS_ENABLE_WEBUSB_ON_ANY_ORIGIN_NAME,
+     IDS_FLAGS_ENABLE_WEBUSB_ON_ANY_ORIGIN_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableWebUsbOnAnyOrigin)},
 #if defined(OS_CHROMEOS)
     {"cros-regions-mode",
      IDS_FLAGS_CROS_REGIONS_MODE_NAME,
@@ -2061,6 +2050,13 @@
       kOsDesktop,
       SINGLE_VALUE_TYPE(switches::kEnableMaterialDesignExtensions)},
 #endif
+#if defined(OS_WIN) || defined(OS_LINUX)
+     {"enable-input-ime-api", IDS_FLAGS_ENABLE_INPUT_IME_API_NAME,
+      IDS_FLAGS_ENABLE_INPUT_IME_API_DESCRIPTION,
+      kOsWin | kOsLinux,
+      ENABLE_DISABLE_VALUE_TYPE(switches::kEnableInputImeAPI,
+                                switches::kDisableInputImeAPI)},
+#endif // defined(OS_WIN) || defined(OS_LINUX)
     // 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/net/external_estimate_provider_android.cc b/chrome/browser/android/net/external_estimate_provider_android.cc
index 463c35c4a..d00f07a 100644
--- a/chrome/browser/android/net/external_estimate_provider_android.cc
+++ b/chrome/browser/android/net/external_estimate_provider_android.cc
@@ -7,6 +7,7 @@
 #include <stdint.h>
 
 #include "base/android/context_utils.h"
+#include "base/at_exit.h"
 #include "base/message_loop/message_loop.h"
 #include "content/public/browser/browser_thread.h"
 #include "jni/ExternalEstimateProviderAndroid_jni.h"
@@ -14,6 +15,14 @@
 namespace chrome {
 namespace android {
 
+namespace {
+// An exit manager is needed to clear up Java statics when unit testing.
+void OnExit(void* /*dummy*/) {
+  Java_ExternalEstimateProviderAndroid_onExit(
+      base::android::AttachCurrentThread());
+}
+}
+
 ExternalEstimateProviderAndroid::ExternalEstimateProviderAndroid()
     : task_runner_(nullptr), delegate_(nullptr), weak_factory_(this) {
   if (base::MessageLoop::current())
@@ -24,6 +33,7 @@
       Java_ExternalEstimateProviderAndroid_create(
           env, base::android::GetApplicationContext(),
           reinterpret_cast<intptr_t>(this)));
+  base::AtExitManager::RegisterCallback(OnExit, nullptr);
   DCHECK(!j_external_estimate_provider_.is_null());
   no_value_ = Java_ExternalEstimateProviderAndroid_getNoValue(env);
   net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
diff --git a/chrome/browser/android/net/external_estimate_provider_android_unittest.cc b/chrome/browser/android/net/external_estimate_provider_android_unittest.cc
index 1c80b093..4c1de55 100644
--- a/chrome/browser/android/net/external_estimate_provider_android_unittest.cc
+++ b/chrome/browser/android/net/external_estimate_provider_android_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <stdint.h>
 
+#include "base/at_exit.h"
 #include "base/test/histogram_tester.h"
 #include "base/time/time.h"
 #include "net/base/network_quality_estimator.h"
@@ -16,6 +17,7 @@
 // Tests if the |ExternalEstimateProviderAndroid| APIs return false without the
 // downstream implementation.
 TEST(ExternalEstimateProviderAndroidTest, BasicsTest) {
+  base::ShadowingAtExitManager at_exit_manager;
   chrome::android::ExternalEstimateProviderAndroid external_estimate_provider;
 
   base::TimeDelta rtt;
@@ -71,6 +73,7 @@
 // Tests if the |ExternalEstimateProviderAndroid| notifies
 // |NetworkQualityEstimator|.
 TEST(ExternalEstimateProviderAndroidTest, DelegateTest) {
+  base::ShadowingAtExitManager at_exit_manager;
   base::HistogramTester histogram_tester;
   scoped_ptr<TestExternalEstimateProviderAndroid> external_estimate_provider;
   external_estimate_provider.reset(new TestExternalEstimateProviderAndroid());
diff --git a/chrome/browser/android/offline_pages/offline_page_mhtml_archiver.cc b/chrome/browser/android/offline_pages/offline_page_mhtml_archiver.cc
index 2f0cc9d9..10f5f2b2 100644
--- a/chrome/browser/android/offline_pages/offline_page_mhtml_archiver.cc
+++ b/chrome/browser/android/offline_pages/offline_page_mhtml_archiver.cc
@@ -8,7 +8,6 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
 #include "base/sha1.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
diff --git a/chrome/browser/android/offline_pages/offline_page_mhtml_archiver_unittest.cc b/chrome/browser/android/offline_pages/offline_page_mhtml_archiver_unittest.cc
index 549ce146..2191c74 100644
--- a/chrome/browser/android/offline_pages/offline_page_mhtml_archiver_unittest.cc
+++ b/chrome/browser/android/offline_pages/offline_page_mhtml_archiver_unittest.cc
@@ -9,9 +9,9 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/test_simple_task_runner.h"
 #include "base/thread_task_runner_handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -117,8 +117,8 @@
   base::FilePath last_file_path_;
   int64 last_file_size_;
 
-  base::MessageLoop message_loop_;
-  scoped_ptr<base::RunLoop> run_loop_;
+  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+  base::ThreadTaskRunnerHandle task_runner_handle_;
 
   DISALLOW_COPY_AND_ASSIGN(OfflinePageMHTMLArchiverTest);
 };
@@ -127,7 +127,9 @@
     : last_archiver_(nullptr),
       last_result_(OfflinePageArchiver::ArchiverResult::
                        ERROR_ARCHIVE_CREATION_FAILED),
-      last_file_size_(0L) {
+      last_file_size_(0L),
+      task_runner_(new base::TestSimpleTaskRunner),
+      task_runner_handle_(task_runner_) {
 }
 
 OfflinePageMHTMLArchiverTest::~OfflinePageMHTMLArchiverTest() {
@@ -145,8 +147,6 @@
     const GURL& url,
     const base::FilePath& file_path,
     int64 file_size) {
-  if (run_loop_)
-    run_loop_->Quit();
   last_url_ = url;
   last_archiver_ = archiver;
   last_result_ = result;
@@ -155,8 +155,7 @@
 }
 
 void OfflinePageMHTMLArchiverTest::PumpLoop() {
-  run_loop_.reset(new base::RunLoop());
-  run_loop_->Run();
+  task_runner_->RunUntilIdle();
 }
 
 // Tests that creation of an archiver fails when web contents is missing.
diff --git a/chrome/browser/android/preferences/pref_service_bridge.cc b/chrome/browser/android/preferences/pref_service_bridge.cc
index 5b5f4b5..4e60129c6 100644
--- a/chrome/browser/android/preferences/pref_service_bridge.cc
+++ b/chrome/browser/android/preferences/pref_service_bridge.cc
@@ -803,6 +803,31 @@
   GetPrefService()->SetInteger(prefs::kNetworkPredictionOptions, option);
 }
 
+static jboolean NetworkPredictionEnabledHasUserSetting(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
+  return GetPrefService()->GetUserPrefValue(
+      prefs::kNetworkPredictionEnabled) != NULL;
+}
+
+static jboolean NetworkPredictionOptionsHasUserSetting(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
+  return GetPrefService()->GetUserPrefValue(
+      prefs::kNetworkPredictionOptions) != NULL;
+}
+
+static jboolean GetNetworkPredictionEnabledUserPrefValue(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
+  const base::Value* network_prediction_enabled =
+      GetPrefService()->GetUserPrefValue(prefs::kNetworkPredictionEnabled);
+  DCHECK(network_prediction_enabled);
+  bool value = false;
+  DCHECK(network_prediction_enabled->GetAsBoolean(&value));
+  return value;
+}
+
 static void SetResolveNavigationErrorEnabled(JNIEnv* env,
                                              const JavaParamRef<jobject>& obj,
                                              jboolean enabled) {
diff --git a/chrome/browser/apps/app_browsertest.cc b/chrome/browser/apps/app_browsertest.cc
index c62cf7b..68adec3d 100644
--- a/chrome/browser/apps/app_browsertest.cc
+++ b/chrome/browser/apps/app_browsertest.cc
@@ -975,7 +975,6 @@
   void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
                                   const extensions::Extension* extension,
                                   bool is_update,
-                                  bool from_ephemeral,
                                   const std::string& old_name) override {
     EXPECT_FALSE(seen_);
     seen_ = true;
diff --git a/chrome/browser/apps/ephemeral_app_browsertest.cc b/chrome/browser/apps/ephemeral_app_browsertest.cc
deleted file mode 100644
index 2204ba6..0000000
--- a/chrome/browser/apps/ephemeral_app_browsertest.cc
+++ /dev/null
@@ -1,1051 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/apps/ephemeral_app_browsertest.h"
-
-#include <vector>
-
-#include "apps/app_restore_service.h"
-#include "apps/saved_files_service.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/scoped_observer.h"
-#include "base/stl_util.h"
-#include "chrome/browser/apps/app_browsertest_util.h"
-#include "chrome/browser/apps/ephemeral_app_service.h"
-#include "chrome/browser/extensions/api/file_system/file_system_api.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_sync_data.h"
-#include "chrome/browser/extensions/extension_sync_service.h"
-#include "chrome/browser/extensions/extension_util.h"
-#include "chrome/browser/notifications/notifier_state_tracker.h"
-#include "chrome/browser/notifications/notifier_state_tracker_factory.h"
-#include "content/public/browser/power_save_blocker.h"
-#include "content/public/test/browser_test.h"
-#include "content/public/test/test_utils.h"
-#include "extensions/browser/api/power/power_api.h"
-#include "extensions/browser/app_sorting.h"
-#include "extensions/browser/event_router.h"
-#include "extensions/browser/extension_prefs.h"
-#include "extensions/browser/extension_registry.h"
-#include "extensions/browser/extension_registry_observer.h"
-#include "extensions/browser/extension_system.h"
-#include "extensions/browser/extension_util.h"
-#include "extensions/browser/process_manager.h"
-#include "extensions/browser/test_extension_registry_observer.h"
-#include "extensions/browser/uninstall_reason.h"
-#include "extensions/common/api/alarms.h"
-#include "extensions/common/extension.h"
-#include "extensions/test/extension_test_message_listener.h"
-#include "extensions/test/result_catcher.h"
-#include "sync/api/fake_sync_change_processor.h"
-#include "sync/api/sync_change_processor_wrapper_for_test.h"
-#include "sync/api/sync_error_factory_mock.h"
-#include "ui/app_list/app_list_switches.h"
-#include "ui/message_center/message_center.h"
-#include "ui/message_center/notifier_settings.h"
-
-using extensions::AppSorting;
-using extensions::Event;
-using extensions::EventRouter;
-using extensions::Extension;
-using extensions::ExtensionPrefs;
-using extensions::ExtensionRegistry;
-using extensions::ExtensionRegistryObserver;
-using extensions::ExtensionSyncData;
-using extensions::ExtensionSystem;
-using extensions::Manifest;
-using extensions::ResultCatcher;
-
-namespace {
-
-namespace alarms = extensions::api::alarms;
-
-const char kPowerTestApp[] = "ephemeral_apps/power";
-
-// Enabling sync causes these tests to be flaky on Windows. Disable sync so that
-// everything else can be tested. See crbug.com/401028
-#if defined(OS_WIN)
-const bool kEnableSync = false;
-#else
-const bool kEnableSync = true;
-#endif
-
-typedef std::vector<message_center::Notifier*> NotifierList;
-
-bool IsNotifierInList(const message_center::NotifierId& notifier_id,
-                      const NotifierList& notifiers) {
-  for (NotifierList::const_iterator it = notifiers.begin();
-       it != notifiers.end(); ++it) {
-    const message_center::Notifier* notifier = *it;
-    if (notifier->notifier_id == notifier_id)
-      return true;
-  }
-
-  return false;
-}
-
-// Saves some parameters from the extension installed notification in order
-// to verify them in tests.
-class InstallObserver : public ExtensionRegistryObserver {
- public:
-  struct InstallParameters {
-    std::string id;
-    bool is_update;
-    bool from_ephemeral;
-
-    InstallParameters(
-        const std::string& id,
-        bool is_update,
-        bool from_ephemeral)
-          : id(id), is_update(is_update), from_ephemeral(from_ephemeral) {}
-  };
-
-  explicit InstallObserver(Profile* profile) : registry_observer_(this) {
-    registry_observer_.Add(ExtensionRegistry::Get(profile));
-  }
-
-  ~InstallObserver() override {}
-
-  const InstallParameters& Last() {
-    CHECK(!install_params_.empty());
-    return install_params_.back();
-  }
-
- private:
-  void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
-                                  const Extension* extension,
-                                  bool is_update,
-                                  bool from_ephemeral,
-                                  const std::string& old_name) override {
-    install_params_.push_back(
-        InstallParameters(extension->id(), is_update, from_ephemeral));
-  }
-
-  std::vector<InstallParameters> install_params_;
-  ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
-      registry_observer_;
-};
-
-// Instead of actually changing the system power settings, tests will just
-// issue requests to this mock.
-class PowerSettingsMock {
- public:
-  PowerSettingsMock() : keep_awake_count_(0) {}
-
-  void request_keep_awake() { ++keep_awake_count_; }
-
-  void release_keep_awake() {
-    --keep_awake_count_;
-    ASSERT_GE(keep_awake_count_, 0);
-  }
-
-  int keep_awake_count() const { return keep_awake_count_; }
-
- private:
-  int keep_awake_count_;
-
-  DISALLOW_COPY_AND_ASSIGN(PowerSettingsMock);
-};
-
-// Stub implementation of content::PowerSaveBlocker that updates the
-// PowerSettingsMock.
-class PowerSaveBlockerStub : public content::PowerSaveBlocker {
- public:
-  explicit PowerSaveBlockerStub(PowerSettingsMock* power_settings)
-      : power_settings_(power_settings) {
-    power_settings_->request_keep_awake();
-  }
-
-  ~PowerSaveBlockerStub() override { power_settings_->release_keep_awake(); }
-
-  static scoped_ptr<PowerSaveBlocker> Create(PowerSettingsMock* power_settings,
-                                             PowerSaveBlockerType type,
-                                             Reason reason,
-                                             const std::string& description) {
-    return scoped_ptr<PowerSaveBlocker>(
-        new PowerSaveBlockerStub(power_settings));
-  }
-
- private:
-  PowerSettingsMock* power_settings_;  // Not owned.
-
-  DISALLOW_COPY_AND_ASSIGN(PowerSaveBlockerStub);
-};
-
-}  // namespace
-
-
-// EphemeralAppTestBase:
-
-const char EphemeralAppTestBase::kMessagingReceiverApp[] =
-    "ephemeral_apps/messaging_receiver";
-const char EphemeralAppTestBase::kMessagingReceiverAppV2[] =
-    "ephemeral_apps/messaging_receiver2";
-const char EphemeralAppTestBase::kDispatchEventTestApp[] =
-    "ephemeral_apps/dispatch_event";
-const char EphemeralAppTestBase::kNotificationsTestApp[] =
-    "ephemeral_apps/notification_settings";
-const char EphemeralAppTestBase::kFileSystemTestApp[] =
-    "ephemeral_apps/filesystem_retain_entries";
-
-EphemeralAppTestBase::EphemeralAppTestBase() {}
-
-EphemeralAppTestBase::~EphemeralAppTestBase() {}
-
-void EphemeralAppTestBase::SetUpCommandLine(base::CommandLine* command_line) {
-  // Skip PlatformAppBrowserTest, which sets different values for the switches
-  // below.
-  ExtensionBrowserTest::SetUpCommandLine(command_line);
-
-  // Make event pages get suspended immediately.
-  extensions::ProcessManager::SetEventPageIdleTimeForTesting(1);
-  extensions::ProcessManager::SetEventPageSuspendingTimeForTesting(1);
-
-  // Enable ephemeral apps, which are gated by the experimental app launcher
-  // flag.
-  command_line->AppendSwitch(app_list::switches::kEnableExperimentalAppList);
-}
-
-void EphemeralAppTestBase::SetUpOnMainThread() {
-  PlatformAppBrowserTest::SetUpOnMainThread();
-
-  // Disable ephemeral apps immediately after they stop running in tests.
-  EphemeralAppService::Get(profile())->set_disable_delay_for_test(0);
-}
-
-base::FilePath EphemeralAppTestBase::GetTestPath(const char* test_path) {
-  return test_data_dir_.AppendASCII("platform_apps").AppendASCII(test_path);
-}
-
-const Extension* EphemeralAppTestBase::InstallEphemeralApp(
-    const char* test_path, Manifest::Location manifest_location) {
-  const Extension* extension = InstallEphemeralAppWithSourceAndFlags(
-      GetTestPath(test_path), 1, manifest_location, Extension::NO_FLAGS);
-  EXPECT_TRUE(extension);
-  if (extension)
-    EXPECT_TRUE(extensions::util::IsEphemeralApp(extension->id(), profile()));
-  return extension;
-}
-
-const Extension* EphemeralAppTestBase::InstallEphemeralApp(
-    const char* test_path) {
-  return InstallEphemeralApp(test_path, Manifest::INTERNAL);
-}
-
-const Extension* EphemeralAppTestBase::InstallAndLaunchEphemeralApp(
-    const char* test_path) {
-  ExtensionTestMessageListener launched_listener("launched", false);
-  const Extension* extension = InstallEphemeralApp(test_path);
-  EXPECT_TRUE(extension);
-  if (!extension)
-    return NULL;
-
-  LaunchPlatformApp(extension);
-  bool wait_result = launched_listener.WaitUntilSatisfied();
-  EXPECT_TRUE(wait_result);
-  if (!wait_result)
-    return NULL;
-
-  return extension;
-}
-
-const Extension* EphemeralAppTestBase::UpdateEphemeralApp(
-    const std::string& app_id,
-    const base::FilePath& test_dir,
-    const base::FilePath& pem_path) {
-  // Pack a new version of the app.
-  base::ScopedTempDir temp_dir;
-  EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
-
-  base::FilePath crx_path = temp_dir.path().AppendASCII("temp.crx");
-  if (!base::DeleteFile(crx_path, false)) {
-    ADD_FAILURE() << "Failed to delete existing crx: " << crx_path.value();
-    return NULL;
-  }
-
-  base::FilePath app_v2_path = PackExtensionWithOptions(
-      test_dir, crx_path, pem_path, base::FilePath());
-  EXPECT_FALSE(app_v2_path.empty());
-
-  // Update the ephemeral app and wait for the update to finish.
-  extensions::CrxInstaller* crx_installer = NULL;
-  content::WindowedNotificationObserver windowed_observer(
-      extensions::NOTIFICATION_CRX_INSTALLER_DONE,
-      content::Source<extensions::CrxInstaller>(crx_installer));
-  ExtensionService* service =
-      ExtensionSystem::Get(profile())->extension_service();
-  EXPECT_TRUE(service->UpdateExtension(
-      extensions::CRXFileInfo(app_id, app_v2_path), true, &crx_installer));
-  windowed_observer.Wait();
-
-  return ExtensionRegistry::Get(profile())
-      ->GetExtensionById(app_id, ExtensionRegistry::EVERYTHING);
-}
-
-void EphemeralAppTestBase::PromoteEphemeralApp(
-    const extensions::Extension* app) {
-  ExtensionService* extension_service =
-      ExtensionSystem::Get(profile())->extension_service();
-  ASSERT_TRUE(extension_service);
-  extension_service->PromoteEphemeralApp(app, false);
-}
-
-void EphemeralAppTestBase::DisableEphemeralApp(
-    const Extension* app,
-    Extension::DisableReason disable_reason) {
-  ExtensionSystem::Get(profile())->extension_service()->DisableExtension(
-      app->id(), disable_reason);
-
-  ASSERT_TRUE(ExtensionRegistry::Get(profile())->disabled_extensions().Contains(
-      app->id()));
-}
-
-void EphemeralAppTestBase::CloseApp(const std::string& app_id) {
-  EXPECT_EQ(1U, GetAppWindowCountForApp(app_id));
-  extensions::AppWindow* app_window = GetFirstAppWindowForApp(app_id);
-  ASSERT_TRUE(app_window);
-  CloseAppWindow(app_window);
-}
-
-void EphemeralAppTestBase::CloseAppWaitForUnload(const std::string& app_id) {
-  // Ephemeral apps are unloaded from extension system after they stop running.
-  extensions::TestExtensionRegistryObserver observer(
-      ExtensionRegistry::Get(profile()), app_id);
-  CloseApp(app_id);
-  observer.WaitForExtensionUnloaded();
-}
-
-void EphemeralAppTestBase::EvictApp(const std::string& app_id) {
-  // Uninstall the app, which is what happens when ephemeral apps get evicted
-  // from the cache.
-  extensions::TestExtensionRegistryObserver observer(
-      ExtensionRegistry::Get(profile()), app_id);
-
-  ExtensionService* service =
-      ExtensionSystem::Get(profile())->extension_service();
-  ASSERT_TRUE(service);
-  service->UninstallExtension(
-      app_id,
-      extensions::UNINSTALL_REASON_ORPHANED_EPHEMERAL_EXTENSION,
-      base::Bind(&base::DoNothing),
-      NULL);
-
-  observer.WaitForExtensionUninstalled();
-}
-
-// EphemeralAppBrowserTest:
-
-class EphemeralAppBrowserTest : public EphemeralAppTestBase {
- protected:
-  bool LaunchAppAndRunTest(const Extension* app, const char* test_name) {
-    // Ephemeral apps are unloaded after they are closed. Ensure they are
-    // enabled before launch.
-    ExtensionService* service =
-        ExtensionSystem::Get(profile())->extension_service();
-    service->EnableExtension(app->id());
-
-    ExtensionTestMessageListener launched_listener("launched", true);
-    LaunchPlatformApp(app);
-    if (!launched_listener.WaitUntilSatisfied()) {
-      message_ = "Failed to receive launched message from test";
-      return false;
-    }
-
-    ResultCatcher catcher;
-    launched_listener.Reply(test_name);
-
-    bool result = catcher.GetNextResult();
-    message_ = catcher.message();
-
-    CloseAppWaitForUnload(app->id());
-    return result;
-  }
-
-  // Verify that the event page of the app has not been loaded.
-  void VerifyAppNotLoaded(const std::string& app_id) {
-    EXPECT_FALSE(extensions::ProcessManager::Get(profile())
-                     ->GetBackgroundHostForExtension(app_id));
-  }
-
-  // Verify properties of ephemeral apps.
-  void VerifyEphemeralApp(const std::string& app_id) {
-    EXPECT_TRUE(extensions::util::IsEphemeralApp(app_id, profile()));
-
-    // Ephemeral apps should not be synced.
-    scoped_ptr<ExtensionSyncData> sync_change = GetLastSyncChangeForApp(app_id);
-    EXPECT_FALSE(sync_change.get());
-
-    // Ephemeral apps should not be assigned ordinals.
-    AppSorting* app_sorting = ExtensionSystem::Get(profile())->app_sorting();
-    EXPECT_FALSE(app_sorting->GetAppLaunchOrdinal(app_id).IsValid());
-    EXPECT_FALSE(app_sorting->GetPageOrdinal(app_id).IsValid());
-  }
-
-  // Verify that after ephemeral apps stop running, they reside in extension
-  // system in a disabled and unloaded state.
-  void VerifyInactiveEphemeralApp(const std::string& app_id) {
-    EXPECT_TRUE(
-        ExtensionRegistry::Get(profile())->disabled_extensions().Contains(
-            app_id));
-
-    ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
-    EXPECT_TRUE(prefs->IsExtensionDisabled(app_id));
-    EXPECT_NE(0,
-              prefs->GetDisableReasons(app_id) &
-                  Extension::DISABLE_INACTIVE_EPHEMERAL_APP);
-  }
-
-  // Verify the state of an app that has been promoted from an ephemeral to a
-  // fully installed app.
-  void VerifyPromotedApp(const std::string& app_id,
-                         ExtensionRegistry::IncludeFlag expected_set) {
-    const Extension* app = ExtensionRegistry::Get(profile())
-                               ->GetExtensionById(app_id, expected_set);
-    ASSERT_TRUE(app) << "App not found in expected set: " << expected_set;
-
-    // The app should not be ephemeral.
-    ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
-    ASSERT_TRUE(prefs);
-    EXPECT_FALSE(prefs->IsEphemeralApp(app_id));
-    EXPECT_EQ(0,
-              prefs->GetDisableReasons(app_id) &
-                  Extension::DISABLE_INACTIVE_EPHEMERAL_APP);
-
-    // Check sort ordinals.
-    AppSorting* app_sorting = ExtensionSystem::Get(profile())->app_sorting();
-    EXPECT_TRUE(app_sorting->GetAppLaunchOrdinal(app_id).IsValid());
-    EXPECT_TRUE(app_sorting->GetPageOrdinal(app_id).IsValid());
-  }
-
-  // Dispatch a fake alarm event to the app.
-  void DispatchAlarmEvent(EventRouter* event_router,
-                          const std::string& app_id) {
-    alarms::Alarm dummy_alarm;
-    dummy_alarm.name = "test_alarm";
-
-    scoped_ptr<base::ListValue> args(new base::ListValue());
-    args->Append(dummy_alarm.ToValue().release());
-    scoped_ptr<Event> event(new Event(extensions::events::ALARMS_ON_ALARM,
-                                      alarms::OnAlarm::kEventName,
-                                      args.Pass()));
-
-    event_router->DispatchEventToExtension(app_id, event.Pass());
-  }
-
-  // Simulates the scenario where an app is installed, via the normal
-  // installation route, on top of an ephemeral app. This can occur due to race
-  // conditions.
-  const Extension* ReplaceEphemeralApp(const std::string& app_id,
-                                       const char* test_path,
-                                       int expected_enabled_change) {
-    return UpdateExtensionWaitForIdle(
-        app_id, GetTestPath(test_path), expected_enabled_change);
-  }
-
-  void PromoteEphemeralAppAndVerify(
-      const Extension* app,
-      ExtensionRegistry::IncludeFlag expected_set,
-      bool expect_sync_enabled) {
-    ASSERT_TRUE(app);
-
-    // Ephemeral apps should not be synced.
-    scoped_ptr<ExtensionSyncData> sync_change =
-        GetLastSyncChangeForApp(app->id());
-    EXPECT_FALSE(sync_change.get());
-
-    // Promote the app to a regular installed app.
-    InstallObserver installed_observer(profile());
-    PromoteEphemeralApp(app);
-    VerifyPromotedApp(app->id(), expected_set);
-
-    // Check the notification parameters.
-    const InstallObserver::InstallParameters& params =
-        installed_observer.Last();
-    EXPECT_EQ(app->id(), params.id);
-    EXPECT_TRUE(params.is_update);
-    EXPECT_TRUE(params.from_ephemeral);
-
-    // The installation should now be synced.
-    sync_change = GetLastSyncChangeForApp(app->id());
-    VerifySyncChange(sync_change.get(), expect_sync_enabled);
-  }
-
-  void PromoteEphemeralAppAndVerify(
-      const Extension* app,
-      ExtensionRegistry::IncludeFlag expected_set) {
-    PromoteEphemeralAppAndVerify(app, expected_set,
-                                 expected_set == ExtensionRegistry::ENABLED);
-  }
-
-  void PromoteEphemeralAppFromSyncAndVerify(
-      const Extension* app,
-      bool enable_from_sync,
-      ExtensionRegistry::IncludeFlag expected_set) {
-    ASSERT_TRUE(app);
-
-    // Simulate an install from sync.
-    int disable_reasons = enable_from_sync ? 0 : Extension::DISABLE_USER_ACTION;
-    const syncer::StringOrdinal kAppLaunchOrdinal("x");
-    const syncer::StringOrdinal kPageOrdinal("y");
-    ExtensionSyncData app_sync_data(
-        *app,
-        enable_from_sync,
-        disable_reasons,
-        false /* incognito enabled */,
-        false /* remote install */,
-        extensions::ExtensionSyncData::BOOLEAN_UNSET,
-        kAppLaunchOrdinal,
-        kPageOrdinal,
-        extensions::LAUNCH_TYPE_REGULAR);
-
-    std::string app_id = app->id();
-    app = NULL;
-
-    ExtensionSyncService::Get(profile())->ProcessSyncChanges(
-        FROM_HERE,
-        syncer::SyncChangeList(
-            1, app_sync_data.GetSyncChange(syncer::SyncChange::ACTION_ADD)));
-
-    // Verify the installation.
-    VerifyPromotedApp(app_id, expected_set);
-
-    // The sort ordinals from sync should not be overridden.
-    AppSorting* app_sorting = ExtensionSystem::Get(profile())->app_sorting();
-    EXPECT_TRUE(
-        app_sorting->GetAppLaunchOrdinal(app_id).Equals(kAppLaunchOrdinal));
-    EXPECT_TRUE(app_sorting->GetPageOrdinal(app_id).Equals(kPageOrdinal));
-  }
-
-  void InitSyncService() {
-    if (!kEnableSync)
-      return;
-
-    ExtensionSyncService* sync_service = ExtensionSyncService::Get(profile());
-    sync_service->MergeDataAndStartSyncing(
-        syncer::APPS,
-        syncer::SyncDataList(),
-        scoped_ptr<syncer::SyncChangeProcessor>(
-            new syncer::SyncChangeProcessorWrapperForTest(
-                &mock_sync_processor_)),
-        scoped_ptr<syncer::SyncErrorFactory>(
-            new syncer::SyncErrorFactoryMock()));
-  }
-
-  scoped_ptr<ExtensionSyncData> GetLastSyncChangeForApp(const std::string& id) {
-    scoped_ptr<ExtensionSyncData> sync_data;
-    for (syncer::SyncChangeList::iterator it =
-             mock_sync_processor_.changes().begin();
-         it != mock_sync_processor_.changes().end(); ++it) {
-      scoped_ptr<ExtensionSyncData> data(
-          ExtensionSyncData::CreateFromSyncChange(*it));
-      if (data.get() && data->id() == id)
-        sync_data.reset(data.release());
-    }
-
-    return sync_data.Pass();
-  }
-
-  void VerifySyncChange(const ExtensionSyncData* sync_change,
-                        bool expect_enabled) {
-    if (!kEnableSync)
-      return;
-
-    ASSERT_TRUE(sync_change);
-    EXPECT_TRUE(sync_change->page_ordinal().IsValid());
-    EXPECT_TRUE(sync_change->app_launch_ordinal().IsValid());
-    EXPECT_FALSE(sync_change->uninstalled());
-    EXPECT_EQ(expect_enabled, sync_change->enabled());
-  }
-
-  void TestInstallEvent(bool close_app) {
-    ExtensionTestMessageListener first_msg_listener(false);
-    const Extension* app = InstallAndLaunchEphemeralApp(kDispatchEventTestApp);
-    ASSERT_TRUE(app);
-
-    // When an ephemeral app is first added, it should not receive the
-    // onInstalled event, hence the first message received from the test should
-    // be "launched" and not "installed".
-    ASSERT_TRUE(first_msg_listener.WaitUntilSatisfied());
-    EXPECT_EQ(std::string("launched"), first_msg_listener.message());
-
-    if (close_app)
-      CloseAppWaitForUnload(app->id());
-
-    // When installed permanently, the app should receive the onInstalled event.
-    ExtensionTestMessageListener install_listener("installed", false);
-    PromoteEphemeralApp(app);
-    ASSERT_TRUE(install_listener.WaitUntilSatisfied());
-  }
-
- private:
-  syncer::FakeSyncChangeProcessor mock_sync_processor_;
-};
-
-// Verify that ephemeral apps can be launched and receive system events when
-// they are running. Once they are inactive they should not receive system
-// events.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, EventDispatchWhenLaunched) {
-  const Extension* extension =
-      InstallAndLaunchEphemeralApp(kDispatchEventTestApp);
-  ASSERT_TRUE(extension);
-
-  // Send a fake alarm event to the app and verify that a response is
-  // received.
-  EventRouter* event_router = EventRouter::Get(profile());
-  ASSERT_TRUE(event_router);
-
-  ExtensionTestMessageListener alarm_received_listener("alarm_received", false);
-  DispatchAlarmEvent(event_router, extension->id());
-  ASSERT_TRUE(alarm_received_listener.WaitUntilSatisfied());
-
-  CloseAppWaitForUnload(extension->id());
-
-  // Dispatch the alarm event again and verify that the event page did not get
-  // loaded for the app.
-  DispatchAlarmEvent(event_router, extension->id());
-  VerifyAppNotLoaded(extension->id());
-}
-
-// Verify that ephemeral apps will receive messages while they are running.
-// Flaky test: crbug.com/394426
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,
-                       DISABLED_ReceiveMessagesWhenLaunched) {
-  const Extension* receiver =
-      InstallAndLaunchEphemeralApp(kMessagingReceiverApp);
-  ASSERT_TRUE(receiver);
-
-  // Verify that messages are received while the app is running.
-  ResultCatcher result_catcher;
-  LoadAndLaunchPlatformApp("ephemeral_apps/messaging_sender_success",
-                           "Launched");
-  EXPECT_TRUE(result_catcher.GetNextResult());
-
-  CloseAppWaitForUnload(receiver->id());
-
-  // Verify that messages are not received while the app is inactive.
-  LoadAndLaunchPlatformApp("ephemeral_apps/messaging_sender_fail", "Launched");
-  EXPECT_TRUE(result_catcher.GetNextResult());
-}
-
-// Verifies that the chrome.runtime.onInstalled() event is received by a running
-// ephemeral app only when it is promoted.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,
-                       InstallEventReceivedWhileRunning) {
-  TestInstallEvent(false /* close app */);
-}
-
-// Verifies that when an idle ephemeral app is promoted, it will be loaded to
-// receive the chrome.runtime.onInstalled() event.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, InstallEventReceivedWhileIdle) {
-  TestInstallEvent(true /* close app */);
-}
-
-// Verifies that the chrome.runtime.onRestarted() event is received by an
-// ephemeral app.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, RestartEventReceived) {
-  const Extension* app = InstallAndLaunchEphemeralApp(kDispatchEventTestApp);
-  ASSERT_TRUE(app);
-  CloseAppWaitForUnload(app->id());
-
-  // Fake ephemeral app running before restart.
-  ExtensionSystem::Get(profile())->extension_service()->EnableExtension(
-      app->id());
-  ASSERT_TRUE(ExtensionRegistry::Get(profile())->enabled_extensions().Contains(
-      app->id()));
-  ExtensionPrefs::Get(profile())->SetExtensionRunning(app->id(), true);
-
-  ExtensionTestMessageListener restart_listener("restarted", false);
-  apps::AppRestoreService::Get(profile())->HandleStartup(true);
-  EXPECT_TRUE(restart_listener.WaitUntilSatisfied());
-}
-
-// Verify that an updated ephemeral app will still have its ephemeral flag
-// enabled.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, UpdateEphemeralApp) {
-  InitSyncService();
-
-  const Extension* app_v1 = InstallAndLaunchEphemeralApp(kMessagingReceiverApp);
-  ASSERT_TRUE(app_v1);
-  VerifyEphemeralApp(app_v1->id());
-  CloseAppWaitForUnload(app_v1->id());
-  VerifyInactiveEphemeralApp(app_v1->id());
-
-  std::string app_id = app_v1->id();
-  base::Version app_original_version = *app_v1->version();
-
-  // Update to version 2 of the app.
-  app_v1 = NULL;  // The extension object will be destroyed during update.
-  InstallObserver installed_observer(profile());
-  const Extension* app_v2 =
-      UpdateEphemeralApp(app_id,
-                         GetTestPath(kMessagingReceiverAppV2),
-                         GetTestPath(kMessagingReceiverApp)
-                             .ReplaceExtension(FILE_PATH_LITERAL(".pem")));
-
-  // Check the notification parameters.
-  const InstallObserver::InstallParameters& params = installed_observer.Last();
-  EXPECT_EQ(app_id, params.id);
-  EXPECT_TRUE(params.is_update);
-  EXPECT_FALSE(params.from_ephemeral);
-
-  // The ephemeral flag should still be set.
-  ASSERT_TRUE(app_v2);
-  EXPECT_GT(app_v2->version()->CompareTo(app_original_version), 0);
-  VerifyEphemeralApp(app_id);
-
-  // The app should still be disabled in extension system.
-  VerifyInactiveEphemeralApp(app_id);
-}
-
-// Verify that if notifications have been disabled for an ephemeral app, it will
-// remain disabled even after being evicted from the cache.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, StickyNotificationSettings) {
-  const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp);
-  ASSERT_TRUE(app);
-
-  // Disable notifications for this app.
-  NotifierStateTracker* notifier_state_tracker =
-      NotifierStateTrackerFactory::GetForProfile(profile());
-  ASSERT_TRUE(notifier_state_tracker);
-
-  message_center::NotifierId notifier_id(
-      message_center::NotifierId::APPLICATION, app->id());
-  EXPECT_TRUE(notifier_state_tracker->IsNotifierEnabled(notifier_id));
-  notifier_state_tracker->SetNotifierEnabled(notifier_id, false);
-  EXPECT_FALSE(notifier_state_tracker->IsNotifierEnabled(notifier_id));
-
-  // Remove the app.
-  CloseAppWaitForUnload(app->id());
-  EvictApp(app->id());
-
-  // Reinstall the ephemeral app and verify that notifications remain disabled.
-  app = InstallEphemeralApp(kNotificationsTestApp);
-  ASSERT_TRUE(app);
-  message_center::NotifierId reinstalled_notifier_id(
-      message_center::NotifierId::APPLICATION, app->id());
-  EXPECT_FALSE(notifier_state_tracker->IsNotifierEnabled(
-      reinstalled_notifier_id));
-}
-
-// Verify that only running ephemeral apps will appear in the Notification
-// Settings UI. Inactive, cached ephemeral apps should not appear.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,
-                       IncludeRunningEphemeralAppsInNotifiers) {
-  message_center::NotifierSettingsProvider* settings_provider =
-      message_center::MessageCenter::Get()->GetNotifierSettingsProvider();
-  DCHECK(settings_provider);
-
-  const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp);
-  ASSERT_TRUE(app);
-  message_center::NotifierId notifier_id(
-      message_center::NotifierId::APPLICATION, app->id());
-
-  // Since the ephemeral app is running, it should be included in the list
-  // of notifiers to show in the UI.
-  NotifierList notifiers;
-  STLElementDeleter<NotifierList> notifier_deleter(&notifiers);
-
-  settings_provider->GetNotifierList(&notifiers);
-  EXPECT_TRUE(IsNotifierInList(notifier_id, notifiers));
-  STLDeleteElements(&notifiers);
-
-  // Close the ephemeral app.
-  CloseAppWaitForUnload(app->id());
-
-  // Inactive ephemeral apps should not be included in the list of notifiers to
-  // show in the UI.
-  settings_provider->GetNotifierList(&notifiers);
-  EXPECT_FALSE(IsNotifierInList(notifier_id, notifiers));
-}
-
-// Verify that ephemeral apps will have no ability to retain file entries after
-// close. Normal retainEntry behavior for installed apps is tested in
-// FileSystemApiTest.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,
-                       DisableRetainFileSystemEntries) {
-  // Create a dummy file that we can just return to the test.
-  base::ScopedTempDir temp_dir;
-  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  base::FilePath temp_file;
-  ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &temp_file));
-
-  using extensions::FileSystemChooseEntryFunction;
-  FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
-      &temp_file);
-  // The temporary file needs to be registered for the tests to pass on
-  // ChromeOS.
-  FileSystemChooseEntryFunction::RegisterTempExternalFileSystemForTest(
-      "temp", temp_dir.path());
-
-  // The first test opens the file and writes the file handle to local storage.
-  const Extension* app = InstallEphemeralApp(kFileSystemTestApp,
-                                             Manifest::UNPACKED);
-  ASSERT_TRUE(LaunchAppAndRunTest(app, "OpenAndRetainFile")) << message_;
-
-  // Verify that after the app has been closed, all retained entries are
-  // flushed.
-  std::vector<apps::SavedFileEntry> file_entries =
-      apps::SavedFilesService::Get(profile())
-          ->GetAllFileEntries(app->id());
-  EXPECT_TRUE(file_entries.empty());
-
-  // The second test verifies that the file cannot be reopened.
-  ASSERT_TRUE(LaunchAppAndRunTest(app, "RestoreRetainedFile")) << message_;
-}
-
-// Checks the process of launching an ephemeral app and then promoting the app
-// while it is running.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, PromoteAppWhileRunning) {
-  InitSyncService();
-
-  const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp);
-  ASSERT_TRUE(app);
-
-  PromoteEphemeralAppAndVerify(app, ExtensionRegistry::ENABLED);
-
-  // Ensure that the app is not unloaded and disabled after it is closed.
-  CloseApp(app->id());
-  VerifyPromotedApp(app->id(), ExtensionRegistry::ENABLED);
-}
-
-// Checks the process of launching an ephemeral app and then promoting the app
-// while it is idle.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, PromoteAppWhileIdle) {
-  InitSyncService();
-
-  const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp);
-  ASSERT_TRUE(app);
-  CloseAppWaitForUnload(app->id());
-  VerifyInactiveEphemeralApp(app->id());
-
-  PromoteEphemeralAppAndVerify(app, ExtensionRegistry::ENABLED);
-}
-
-// Verifies that promoting an ephemeral app that was disabled due to a
-// permissions increase will enable it.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, PromoteAppAndGrantPermissions) {
-  InitSyncService();
-
-  const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp);
-  ASSERT_TRUE(app);
-  CloseAppWaitForUnload(app->id());
-  DisableEphemeralApp(app, Extension::DISABLE_PERMISSIONS_INCREASE);
-
-  PromoteEphemeralAppAndVerify(app, ExtensionRegistry::ENABLED);
-  EXPECT_FALSE(ExtensionPrefs::Get(profile())
-                   ->DidExtensionEscalatePermissions(app->id()));
-}
-
-// Verifies that promoting an ephemeral app that has unsupported requirements
-// will not enable it.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,
-                       PromoteUnsupportedEphemeralApp) {
-  InitSyncService();
-
-  const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp);
-  ASSERT_TRUE(app);
-  CloseAppWaitForUnload(app->id());
-  DisableEphemeralApp(app, Extension::DISABLE_UNSUPPORTED_REQUIREMENT);
-
-  // When promoted to a regular installed app, it should remain disabled.
-  // However, DISABLE_UNSUPPORTED_REQUIREMENT is not a syncable disable reason,
-  // so sync should still say "enabled".
-  bool expect_sync_enabled = true;
-  PromoteEphemeralAppAndVerify(app, ExtensionRegistry::DISABLED,
-                               expect_sync_enabled);
-}
-
-// Verifies that promoting an ephemeral app that is blacklisted will not enable
-// it.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,
-                       PromoteBlacklistedEphemeralApp) {
-  InitSyncService();
-
-  const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp);
-  ASSERT_TRUE(app);
-  CloseAppWaitForUnload(app->id());
-
-  ExtensionService* service =
-      ExtensionSystem::Get(profile())->extension_service();
-  service->BlacklistExtensionForTest(app->id());
-  ASSERT_TRUE(
-      ExtensionRegistry::Get(profile())->blacklisted_extensions().Contains(
-          app->id()));
-
-  // When promoted to a regular installed app, it should remain blacklisted.
-  PromoteEphemeralAppAndVerify(app, ExtensionRegistry::BLACKLISTED);
-
-  // The app should be synced, but disabled.
-  scoped_ptr<ExtensionSyncData> sync_change =
-      GetLastSyncChangeForApp(app->id());
-  VerifySyncChange(sync_change.get(), false);
-}
-
-// Checks the process of promoting an ephemeral app from sync while the app is
-// running.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,
-                       PromoteAppFromSyncWhileRunning) {
-  InitSyncService();
-
-  const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp);
-  ASSERT_TRUE(app);
-
-  PromoteEphemeralAppFromSyncAndVerify(app, true, ExtensionRegistry::ENABLED);
-
-  // Ensure that the app is not unloaded and disabled after it is closed.
-  CloseApp(app->id());
-  VerifyPromotedApp(app->id(), ExtensionRegistry::ENABLED);
-}
-
-// Checks the process of promoting an ephemeral app from sync while the app is
-// idle.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, PromoteAppFromSyncWhileIdle) {
-  InitSyncService();
-
-  const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp);
-  ASSERT_TRUE(app);
-  CloseAppWaitForUnload(app->id());
-  VerifyInactiveEphemeralApp(app->id());
-
-  PromoteEphemeralAppFromSyncAndVerify(app, true, ExtensionRegistry::ENABLED);
-}
-
-// Checks the process of promoting an ephemeral app from sync, where the app
-// from sync is disabled, and the ephemeral app is running.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,
-                       PromoteDisabledAppFromSyncWhileRunning) {
-  InitSyncService();
-
-  const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp);
-  ASSERT_TRUE(app);
-
-  PromoteEphemeralAppFromSyncAndVerify(app, false, ExtensionRegistry::DISABLED);
-}
-
-// Checks the process of promoting an ephemeral app from sync, where the app
-// from sync is disabled, and the ephemeral app is idle.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,
-                       PromoteDisabledAppFromSyncWhileIdle) {
-  InitSyncService();
-
-  const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp);
-  ASSERT_TRUE(app);
-  CloseAppWaitForUnload(app->id());
-  VerifyInactiveEphemeralApp(app->id());
-
-  PromoteEphemeralAppFromSyncAndVerify(app, false, ExtensionRegistry::DISABLED);
-}
-
-// In most cases, ExtensionService::PromoteEphemeralApp() will be called to
-// permanently install an ephemeral app. However, there may be cases where an
-// install occurs through the usual route of installing from the Web Store (due
-// to race conditions). Ensure that the app is still installed correctly.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,
-                       ReplaceEphemeralAppWithInstalledApp) {
-  InitSyncService();
-
-  const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp);
-  ASSERT_TRUE(app);
-  CloseAppWaitForUnload(app->id());
-  std::string app_id = app->id();
-  app = NULL;
-
-  InstallObserver installed_observer(profile());
-  ReplaceEphemeralApp(app_id, kNotificationsTestApp, 1);
-  VerifyPromotedApp(app_id, ExtensionRegistry::ENABLED);
-
-  // Check the notification parameters.
-  const InstallObserver::InstallParameters& params = installed_observer.Last();
-  EXPECT_EQ(app_id, params.id);
-  EXPECT_TRUE(params.is_update);
-  EXPECT_TRUE(params.from_ephemeral);
-}
-
-// This is similar to ReplaceEphemeralAppWithInstalledApp, but installs will
-// be delayed until the app is idle.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,
-                       ReplaceEphemeralAppWithDelayedInstalledApp) {
-  InitSyncService();
-  const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp);
-  ASSERT_TRUE(app);
-  std::string app_id = app->id();
-  app = NULL;
-
-  // Initiate install.
-  ReplaceEphemeralApp(app_id, kNotificationsTestApp, 0);
-
-  // The delayed installation will occur when the ephemeral app is closed.
-  extensions::TestExtensionRegistryObserver observer(
-      ExtensionRegistry::Get(profile()), app_id);
-  InstallObserver installed_observer(profile());
-  CloseAppWaitForUnload(app_id);
-  observer.WaitForExtensionWillBeInstalled();
-  VerifyPromotedApp(app_id, ExtensionRegistry::ENABLED);
-
-  // Check the notification parameters.
-  const InstallObserver::InstallParameters& params = installed_observer.Last();
-  EXPECT_EQ(app_id, params.id);
-  EXPECT_TRUE(params.is_update);
-  EXPECT_TRUE(params.from_ephemeral);
-}
-
-// Verifies that an installed app cannot turn into an ephemeral app as result of
-// race conditions, i.e. an ephemeral app can be promoted to an installed app,
-// but not vice versa.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,
-                       ReplaceInstalledAppWithEphemeralApp) {
-  const Extension* app = InstallPlatformApp(kNotificationsTestApp);
-  ASSERT_TRUE(app);
-  std::string app_id = app->id();
-  app = NULL;
-
-  EXPECT_FALSE(extensions::util::IsEphemeralApp(app_id, profile()));
-  app =
-      InstallEphemeralAppWithSourceAndFlags(GetTestPath(kNotificationsTestApp),
-                                            0,
-                                            Manifest::INTERNAL,
-                                            Extension::NO_FLAGS);
-  EXPECT_FALSE(extensions::util::IsEphemeralApp(app_id, profile()));
-}
-
-// Ephemerality was previously encoded by the Extension::IS_EPHEMERAL creation
-// flag. This was changed to an "ephemeral_app" property. Check that the prefs
-// are handled correctly.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,
-                       ExtensionPrefBackcompatibility) {
-  // Ensure that apps with the old prefs are recognized as ephemeral.
-  const Extension* app =
-      InstallExtensionWithSourceAndFlags(GetTestPath(kNotificationsTestApp),
-                                         1,
-                                         Manifest::INTERNAL,
-                                         Extension::IS_EPHEMERAL);
-  ASSERT_TRUE(app);
-  EXPECT_TRUE(extensions::util::IsEphemeralApp(app->id(), profile()));
-
-  // Ensure that when the app is promoted to an installed app, the bit in the
-  // creation flags is cleared.
-  PromoteEphemeralApp(app);
-  EXPECT_FALSE(extensions::util::IsEphemeralApp(app->id(), profile()));
-
-  int creation_flags =
-      ExtensionPrefs::Get(profile())->GetCreationFlags(app->id());
-  EXPECT_EQ(0, creation_flags & Extension::IS_EPHEMERAL);
-}
-
-// Verifies that the power keep awake will be automatically released for
-// ephemeral apps that stop running. Well behaved apps should actually call
-// chrome.power.releaseKeepAwake() themselves.
-IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, ReleasePowerKeepAwake) {
-  PowerSettingsMock power_settings;
-  extensions::PowerAPI::Get(profile())->SetCreateBlockerFunctionForTesting(
-      base::Bind(&PowerSaveBlockerStub::Create, &power_settings));
-
-  const Extension* app = InstallAndLaunchEphemeralApp(kPowerTestApp);
-  ASSERT_TRUE(app);
-  EXPECT_EQ(1, power_settings.keep_awake_count());
-
-  CloseAppWaitForUnload(app->id());
-
-  EXPECT_EQ(0, power_settings.keep_awake_count());
-}
diff --git a/chrome/browser/apps/ephemeral_app_browsertest.h b/chrome/browser/apps/ephemeral_app_browsertest.h
deleted file mode 100644
index 1e47b9de..0000000
--- a/chrome/browser/apps/ephemeral_app_browsertest.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_APPS_EPHEMERAL_APP_BROWSERTEST_H_
-#define CHROME_BROWSER_APPS_EPHEMERAL_APP_BROWSERTEST_H_
-
-#include <string>
-
-#include "base/files/file_path.h"
-#include "chrome/browser/apps/app_browsertest_util.h"
-#include "extensions/common/manifest.h"
-
-namespace base {
-class CommandLine;
-}
-
-// Contains common code for ephemeral app browser tests.
-class EphemeralAppTestBase : public extensions::PlatformAppBrowserTest {
- public:
-  static const char kMessagingReceiverApp[];
-  static const char kMessagingReceiverAppV2[];
-  static const char kDispatchEventTestApp[];
-  static const char kNotificationsTestApp[];
-  static const char kFileSystemTestApp[];
-
-  EphemeralAppTestBase();
-  ~EphemeralAppTestBase() override;
-
-  void SetUpCommandLine(base::CommandLine* command_line) override;
-  void SetUpOnMainThread() override;
-
- protected:
-  base::FilePath GetTestPath(const char* test_path);
-
-  const extensions::Extension* InstallEphemeralApp(
-      const char* test_path, extensions::Manifest::Location manifest_location);
-  const extensions::Extension* InstallEphemeralApp(const char* test_path);
-  const extensions::Extension* InstallAndLaunchEphemeralApp(
-      const char* test_path);
-  const extensions::Extension*  UpdateEphemeralApp(
-      const std::string& app_id,
-      const base::FilePath& test_dir,
-      const base::FilePath& pem_path);
-  void PromoteEphemeralApp(const extensions::Extension* app);
-  void DisableEphemeralApp(const extensions::Extension* app,
-                           extensions::Extension::DisableReason disable_reason);
-
-  void CloseAppWaitForUnload(const std::string& app_id);
-  void CloseApp(const std::string& app_id);
-  void EvictApp(const std::string& app_id);
-};
-
-#endif  // CHROME_BROWSER_APPS_EPHEMERAL_APP_BROWSERTEST_H_
diff --git a/chrome/browser/apps/ephemeral_app_service.cc b/chrome/browser/apps/ephemeral_app_service.cc
deleted file mode 100644
index 6f17c4b..0000000
--- a/chrome/browser/apps/ephemeral_app_service.cc
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/apps/ephemeral_app_service.h"
-
-#include "apps/app_lifetime_monitor_factory.h"
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/thread_task_runner_handle.h"
-#include "chrome/browser/apps/ephemeral_app_service_factory.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/common/content_switches.h"
-#include "extensions/browser/extension_prefs.h"
-#include "extensions/browser/extension_registry.h"
-#include "extensions/browser/extension_system.h"
-#include "extensions/browser/extension_util.h"
-#include "extensions/browser/uninstall_reason.h"
-#include "extensions/common/extension.h"
-#include "extensions/common/extension_set.h"
-#include "extensions/common/one_shot_event.h"
-
-using extensions::Extension;
-using extensions::ExtensionPrefs;
-using extensions::ExtensionRegistry;
-using extensions::ExtensionSet;
-using extensions::ExtensionSystem;
-
-namespace {
-
-// The number of seconds after an app has stopped running before it will be
-// disabled.
-const int kDefaultDisableAppDelay = 1;
-
-}  // namespace
-
-// static
-EphemeralAppService* EphemeralAppService::Get(Profile* profile) {
-  return EphemeralAppServiceFactory::GetForProfile(profile);
-}
-
-EphemeralAppService::EphemeralAppService(Profile* profile)
-    : profile_(profile),
-      extension_registry_observer_(this),
-      app_lifetime_monitor_observer_(this),
-      disable_idle_app_delay_(kDefaultDisableAppDelay),
-      weak_ptr_factory_(this) {
-  ExtensionSystem::Get(profile_)->ready().Post(
-      FROM_HERE,
-      base::Bind(&EphemeralAppService::Init, weak_ptr_factory_.GetWeakPtr()));
-}
-
-EphemeralAppService::~EphemeralAppService() {
-}
-
-void EphemeralAppService::ClearCachedApps() {
-  ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
-  DCHECK(registry);
-  ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
-  DCHECK(prefs);
-  ExtensionService* service =
-      ExtensionSystem::Get(profile_)->extension_service();
-  DCHECK(service);
-
-  scoped_ptr<ExtensionSet> extensions =
-      registry->GenerateInstalledExtensionsSet();
-
-  for (ExtensionSet::const_iterator it = extensions->begin();
-       it != extensions->end();
-       ++it) {
-    std::string extension_id = (*it)->id();
-    if (!prefs->IsEphemeralApp(extension_id))
-      continue;
-
-    DCHECK(registry->GetExtensionById(extension_id,
-                                      ExtensionRegistry::EVERYTHING));
-    service->UninstallExtension(
-        extension_id,
-        extensions::UNINSTALL_REASON_ORPHANED_EPHEMERAL_EXTENSION,
-        base::Bind(&base::DoNothing),
-        NULL);
-  }
-}
-
-void EphemeralAppService::OnExtensionWillBeInstalled(
-    content::BrowserContext* browser_context,
-    const extensions::Extension* extension,
-    bool is_update,
-    bool from_ephemeral,
-    const std::string& old_name) {
-  if (from_ephemeral)
-    HandleEphemeralAppPromoted(extension);
-}
-
-void EphemeralAppService::OnAppStop(Profile* profile,
-                                    const std::string& app_id) {
-  if (!extensions::util::IsEphemeralApp(app_id, profile_))
-    return;
-
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, base::Bind(&EphemeralAppService::DisableEphemeralApp,
-                            weak_ptr_factory_.GetWeakPtr(), app_id),
-      base::TimeDelta::FromSeconds(disable_idle_app_delay_));
-}
-
-void EphemeralAppService::OnChromeTerminating() {
-  extension_registry_observer_.RemoveAll();
-  app_lifetime_monitor_observer_.RemoveAll();
-}
-
-void EphemeralAppService::Init() {
-  // Start observing.
-  extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
-  app_lifetime_monitor_observer_.Add(
-      apps::AppLifetimeMonitorFactory::GetForProfile(profile_));
-
-  // Execute startup clean up tasks (except during tests).
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType))
-    return;
-
-  content::BrowserThread::PostAfterStartupTask(
-      FROM_HERE, content::BrowserThread::GetMessageLoopProxyForThread(
-                     content::BrowserThread::UI),
-      base::Bind(&EphemeralAppService::ClearCachedApps,
-                 weak_ptr_factory_.GetWeakPtr()));
-}
-
-void EphemeralAppService::DisableEphemeralApp(const std::string& app_id) {
-  if (!extensions::util::IsEphemeralApp(app_id, profile_) ||
-      !extensions::util::IsExtensionIdle(app_id, profile_)) {
-    return;
-  }
-
-  // After an ephemeral app has stopped running, unload it from extension
-  // system and disable it to prevent all background activity.
-  ExtensionService* service =
-      ExtensionSystem::Get(profile_)->extension_service();
-  DCHECK(service);
-  service->DisableExtension(app_id, Extension::DISABLE_INACTIVE_EPHEMERAL_APP);
-}
-
-void EphemeralAppService::HandleEphemeralAppPromoted(const Extension* app) {
-  // When ephemeral apps are promoted to regular install apps, remove the
-  // DISABLE_INACTIVE_EPHEMERAL_APP reason and enable the app if there are no
-  // other reasons.
-  ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
-  DCHECK(prefs);
-
-  int disable_reasons = prefs->GetDisableReasons(app->id());
-  if (disable_reasons & Extension::DISABLE_INACTIVE_EPHEMERAL_APP) {
-    if (disable_reasons == Extension::DISABLE_INACTIVE_EPHEMERAL_APP) {
-      // This will also clear disable reasons.
-      prefs->SetExtensionEnabled(app->id());
-    } else {
-      prefs->RemoveDisableReason(app->id(),
-                                 Extension::DISABLE_INACTIVE_EPHEMERAL_APP);
-    }
-  }
-}
diff --git a/chrome/browser/apps/ephemeral_app_service.h b/chrome/browser/apps/ephemeral_app_service.h
deleted file mode 100644
index d8b1a89..0000000
--- a/chrome/browser/apps/ephemeral_app_service.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_APPS_EPHEMERAL_APP_SERVICE_H_
-#define CHROME_BROWSER_APPS_EPHEMERAL_APP_SERVICE_H_
-
-#include <set>
-
-#include "apps/app_lifetime_monitor.h"
-#include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "extensions/browser/extension_registry_observer.h"
-
-class Profile;
-
-namespace extensions {
-class Extension;
-class ExtensionRegistry;
-}  // namespace extensions
-
-// Delete cached ephemeral apps at startup.
-// TODO(benwells): Remove this system.  https://crbug.com/517735.
-class EphemeralAppService : public KeyedService,
-                            public extensions::ExtensionRegistryObserver,
-                            public apps::AppLifetimeMonitor::Observer {
- public:
-  // Returns the instance for the given profile. This is a convenience wrapper
-  // around EphemeralAppServiceFactory::GetForProfile.
-  static EphemeralAppService* Get(Profile* profile);
-
-  explicit EphemeralAppService(Profile* profile);
-  ~EphemeralAppService() override;
-
-  // Clears the ephemeral app cache. Removes all idle ephemeral apps.
-  void ClearCachedApps();
-
-  void set_disable_delay_for_test(int delay) {
-    disable_idle_app_delay_ = delay;
-  }
-
- private:
-  // extensions::ExtensionRegistryObserver.
-  void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
-                                  const extensions::Extension* extension,
-                                  bool is_update,
-                                  bool from_ephemeral,
-                                  const std::string& old_name) override;
-
-  // apps::AppLifetimeMonitor::Observer implementation.
-  void OnAppStop(Profile* profile, const std::string& app_id) override;
-  void OnChromeTerminating() override;
-
-  void Init();
-
-  void DisableEphemeralApp(const std::string& app_id);
-
-  void HandleEphemeralAppPromoted(const extensions::Extension* app);
-
-  Profile* profile_;
-
-  ScopedObserver<extensions::ExtensionRegistry,
-                 extensions::ExtensionRegistryObserver>
-      extension_registry_observer_;
-  ScopedObserver<apps::AppLifetimeMonitor, apps::AppLifetimeMonitor::Observer>
-      app_lifetime_monitor_observer_;
-
-  // Number of seconds before disabling idle ephemeral apps.
-  // Overridden in tests.
-  int disable_idle_app_delay_;
-
-  base::WeakPtrFactory<EphemeralAppService> weak_ptr_factory_;
-
-  friend class EphemeralAppServiceBrowserTest;
-
-  DISALLOW_COPY_AND_ASSIGN(EphemeralAppService);
-};
-
-#endif  // CHROME_BROWSER_APPS_EPHEMERAL_APP_SERVICE_H_
diff --git a/chrome/browser/apps/ephemeral_app_service_browsertest.cc b/chrome/browser/apps/ephemeral_app_service_browsertest.cc
deleted file mode 100644
index cf187430..0000000
--- a/chrome/browser/apps/ephemeral_app_service_browsertest.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <vector>
-
-#include "chrome/browser/apps/ephemeral_app_browsertest.h"
-#include "chrome/browser/apps/ephemeral_app_service.h"
-#include "extensions/browser/extension_registry.h"
-
-using extensions::Extension;
-using extensions::ExtensionRegistry;
-
-class EphemeralAppServiceBrowserTest : public EphemeralAppTestBase {};
-
-// Verify that the cache of ephemeral apps is correctly cleared. All ephemeral
-// apps should be removed.
-IN_PROC_BROWSER_TEST_F(EphemeralAppServiceBrowserTest, ClearCachedApps) {
-  const Extension* running_app =
-      InstallAndLaunchEphemeralApp(kMessagingReceiverApp);
-  const Extension* inactive_app =
-      InstallAndLaunchEphemeralApp(kDispatchEventTestApp);
-  std::string inactive_app_id = inactive_app->id();
-  std::string running_app_id = running_app->id();
-  CloseAppWaitForUnload(inactive_app_id);
-
-  EphemeralAppService* ephemeral_service =
-      EphemeralAppService::Get(browser()->profile());
-  ASSERT_TRUE(ephemeral_service);
-
-  ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
-  ASSERT_TRUE(registry);
-
-  int extension_count = registry->GenerateInstalledExtensionsSet()->size();
-
-  ephemeral_service->ClearCachedApps();
-
-  EXPECT_FALSE(registry->GetExtensionById(inactive_app_id,
-                                          ExtensionRegistry::EVERYTHING));
-  EXPECT_FALSE(registry->GetExtensionById(running_app_id,
-                                          ExtensionRegistry::EVERYTHING));
-
-  int new_extension_count = registry->GenerateInstalledExtensionsSet()->size();
-  EXPECT_EQ(2, extension_count - new_extension_count);
-}
diff --git a/chrome/browser/apps/ephemeral_app_service_factory.cc b/chrome/browser/apps/ephemeral_app_service_factory.cc
deleted file mode 100644
index 06a7c02..0000000
--- a/chrome/browser/apps/ephemeral_app_service_factory.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/apps/ephemeral_app_service_factory.h"
-
-#include "apps/app_lifetime_monitor_factory.h"
-#include "chrome/browser/apps/ephemeral_app_service.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "extensions/browser/extension_system_provider.h"
-#include "extensions/browser/extensions_browser_client.h"
-
-using extensions::ExtensionsBrowserClient;
-
-// static
-EphemeralAppService*
-EphemeralAppServiceFactory::GetForProfile(Profile* profile) {
-  return static_cast<EphemeralAppService*>(
-      GetInstance()->GetServiceForBrowserContext(profile, true));
-}
-
-// static
-EphemeralAppServiceFactory* EphemeralAppServiceFactory::GetInstance() {
-  return base::Singleton<EphemeralAppServiceFactory>::get();
-}
-
-EphemeralAppServiceFactory::EphemeralAppServiceFactory()
-    : BrowserContextKeyedServiceFactory(
-          "EphemeralAppService",
-          BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
-  DependsOn(apps::AppLifetimeMonitorFactory::GetInstance());
-}
-
-EphemeralAppServiceFactory::~EphemeralAppServiceFactory() {
-}
-
-KeyedService* EphemeralAppServiceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  return new EphemeralAppService(Profile::FromBrowserContext(context));
-}
-
-content::BrowserContext* EphemeralAppServiceFactory::GetBrowserContextToUse(
-    content::BrowserContext* context) const {
-  return ExtensionsBrowserClient::Get()->GetOriginalContext(context);
-}
-
-bool EphemeralAppServiceFactory::ServiceIsCreatedWithBrowserContext() const {
-  return true;
-}
-
-bool EphemeralAppServiceFactory::ServiceIsNULLWhileTesting() const {
-  return true;
-}
diff --git a/chrome/browser/apps/ephemeral_app_service_factory.h b/chrome/browser/apps/ephemeral_app_service_factory.h
deleted file mode 100644
index 412027ef..0000000
--- a/chrome/browser/apps/ephemeral_app_service_factory.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_APPS_EPHEMERAL_APP_SERVICE_FACTORY_H_
-#define CHROME_BROWSER_APPS_EPHEMERAL_APP_SERVICE_FACTORY_H_
-
-#include "base/memory/singleton.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-
-class EphemeralAppService;
-class Profile;
-
-class EphemeralAppServiceFactory : public BrowserContextKeyedServiceFactory {
- public:
-  static EphemeralAppService* GetForProfile(Profile* profile);
-
-  static EphemeralAppServiceFactory* GetInstance();
-
- private:
-  friend struct base::DefaultSingletonTraits<EphemeralAppServiceFactory>;
-
-  EphemeralAppServiceFactory();
-  ~EphemeralAppServiceFactory() override;
-
-  // BrowserContextKeyedServiceFactory implementation:
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* context) const override;
-  content::BrowserContext* GetBrowserContextToUse(
-      content::BrowserContext* context) const override;
-  bool ServiceIsCreatedWithBrowserContext() const override;
-  bool ServiceIsNULLWhileTesting() const override;
-};
-
-#endif  // CHROME_BROWSER_APPS_EPHEMERAL_APP_SERVICE_FACTORY_H_
diff --git a/chrome/browser/apps/shortcut_manager.cc b/chrome/browser/apps/shortcut_manager.cc
index 412b6c8..884a5d9 100644
--- a/chrome/browser/apps/shortcut_manager.cc
+++ b/chrome/browser/apps/shortcut_manager.cc
@@ -12,7 +12,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_ui_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -25,7 +24,6 @@
 #include "content/public/common/content_switches.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
-#include "extensions/browser/extension_util.h"
 #include "extensions/common/extension_set.h"
 #include "extensions/common/one_shot_event.h"
 
@@ -48,17 +46,10 @@
 void CreateShortcutsForApp(Profile* profile, const Extension* app) {
   web_app::ShortcutLocations creation_locations;
 
-  if (extensions::util::IsEphemeralApp(app->id(), profile)) {
-    // Ephemeral apps should not have visible shortcuts, but may still require
-    // platform-specific handling.
-    creation_locations.applications_menu_location =
-        web_app::APP_MENU_LOCATION_HIDDEN;
-  } else {
-    // Creates a shortcut for an app in the Chrome Apps subdir of the
-    // applications menu, if there is not already one present.
-    creation_locations.applications_menu_location =
-        web_app::APP_MENU_LOCATION_SUBDIR_CHROMEAPPS;
-  }
+  // Creates a shortcut for an app in the Chrome Apps subdir of the
+  // applications menu, if there is not already one present.
+  creation_locations.applications_menu_location =
+      web_app::APP_MENU_LOCATION_SUBDIR_CHROMEAPPS;
 
   web_app::CreateShortcuts(
       web_app::SHORTCUT_CREATION_AUTOMATED, creation_locations, profile, app);
@@ -119,7 +110,6 @@
     content::BrowserContext* browser_context,
     const Extension* extension,
     bool is_update,
-    bool from_ephemeral,
     const std::string& old_name) {
   if (!extension->is_app())
     return;
@@ -127,7 +117,7 @@
   // If the app is being updated, update any existing shortcuts but do not
   // create new ones. If it is being installed, automatically create a
   // shortcut in the applications menu (e.g., Start Menu).
-  if (is_update && !from_ephemeral) {
+  if (is_update) {
     web_app::UpdateAllShortcuts(
         base::UTF8ToUTF16(old_name), profile_, extension);
   } else {
diff --git a/chrome/browser/apps/shortcut_manager.h b/chrome/browser/apps/shortcut_manager.h
index fb662d3..a6dcde91 100644
--- a/chrome/browser/apps/shortcut_manager.h
+++ b/chrome/browser/apps/shortcut_manager.h
@@ -42,7 +42,6 @@
   void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
                                   const extensions::Extension* extension,
                                   bool is_update,
-                                  bool from_ephemeral,
                                   const std::string& old_name) override;
   void OnExtensionUninstalled(content::BrowserContext* browser_context,
                               const extensions::Extension* extension,
diff --git a/chrome/browser/autofill/autofill_server_browsertest.cc b/chrome/browser/autofill/autofill_server_browsertest.cc
index b5b28165..1f84810c 100644
--- a/chrome/browser/autofill/autofill_server_browsertest.cc
+++ b/chrome/browser/autofill/autofill_server_browsertest.cc
@@ -167,7 +167,8 @@
   // submission, with form fields matching those from the query request.
   const char kUploadRequest[] =
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"15916856893790176210\""
       " autofillused=\"false\""
       " datapresent=\"1f7e0003780000080004\""
diff --git a/chrome/browser/background/background_application_list_model.cc b/chrome/browser/background/background_application_list_model.cc
index ef4aefa..91dacd6 100644
--- a/chrome/browser/background/background_application_list_model.cc
+++ b/chrome/browser/background/background_application_list_model.cc
@@ -25,7 +25,6 @@
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
-#include "extensions/browser/extension_util.h"
 #include "extensions/browser/image_loader.h"
 #include "extensions/browser/notification_types.h"
 #include "extensions/common/extension.h"
@@ -264,11 +263,6 @@
   // 2) It is a hosted app, and has a background contents registered or in the
   //    manifest.
 
-  // Ephemeral apps are denied any background activity after their event page
-  // has been destroyed, thus they cannot be background apps.
-  if (extensions::util::IsEphemeralApp(extension.id(), profile))
-    return false;
-
   // Not a background app if we don't have the background permission.
   if (!extension.permissions_data()->HasAPIPermission(
           APIPermission::kBackground)) {
diff --git a/chrome/browser/background/background_application_list_model_unittest.cc b/chrome/browser/background/background_application_list_model_unittest.cc
index 9b87387..35e99e90 100644
--- a/chrome/browser/background/background_application_list_model_unittest.cc
+++ b/chrome/browser/background/background_application_list_model_unittest.cc
@@ -132,20 +132,6 @@
       .RemovePermissionsUnsafe(
           extension, extension->permissions_data()->active_permissions());
 }
-
-void AddEphemeralApp(const Extension* extension, ExtensionService* service) {
-  extensions::ExtensionPrefs* prefs =
-      extensions::ExtensionPrefs::Get(service->profile());
-  ASSERT_TRUE(prefs);
-  prefs->OnExtensionInstalled(extension,
-                              extensions::Extension::ENABLED,
-                              syncer::StringOrdinal(),
-                              extensions::kInstallFlagIsEphemeral,
-                              std::string());
-
-  service->AddExtension(extension);
-}
-
 }  // namespace
 
 // Crashes on Mac tryslaves.
@@ -228,32 +214,6 @@
   ASSERT_EQ(0U, model->size());
 }
 
-// Verifies that an ephemeral app cannot trigger background mode.
-TEST_F(BackgroundApplicationListModelTest, EphemeralAppTest) {
-  InitializeAndLoadEmptyExtensionService();
-  ASSERT_TRUE(service()->is_ready());
-  ASSERT_TRUE(registry()->enabled_extensions().is_empty());
-  scoped_ptr<BackgroundApplicationListModel> model(
-      new BackgroundApplicationListModel(profile_.get()));
-  ASSERT_EQ(0U, model->size());
-
-  scoped_refptr<Extension> background = CreateExtension("background", true);
-
-  // An ephemeral app with the background permission should not trigger
-  // background mode.
-  AddEphemeralApp(background.get(), service());
-  ASSERT_FALSE(IsBackgroundApp(*background.get()));
-  ASSERT_EQ(1U, registry()->enabled_extensions().size());
-  ASSERT_EQ(0U, model->size());
-
-  // If the ephemeral app becomes promoted to an installed app, it can now
-  // trigger background mode.
-  service()->PromoteEphemeralApp(background.get(), false /*from sync*/);
-  ASSERT_TRUE(IsBackgroundApp(*background.get()));
-  ASSERT_EQ(1U, registry()->enabled_extensions().size());
-  ASSERT_EQ(1U, model->size());
-}
-
 // With minimal test logic, verifies behavior with dynamic permissions.
 TEST_F(BackgroundApplicationListModelTest, AddRemovePermissionsTest) {
   InitializeAndLoadEmptyExtensionService();
diff --git a/chrome/browser/background/background_mode_manager_unittest.cc b/chrome/browser/background/background_mode_manager_unittest.cc
index 633680b..757fc1c 100644
--- a/chrome/browser/background/background_mode_manager_unittest.cc
+++ b/chrome/browser/background/background_mode_manager_unittest.cc
@@ -310,20 +310,6 @@
     return false;
   }
 
-  void AddEphemeralApp(const extensions::Extension* extension,
-                       ExtensionService* service) {
-    extensions::ExtensionPrefs* prefs =
-        extensions::ExtensionPrefs::Get(service->profile());
-    ASSERT_TRUE(prefs);
-    prefs->OnExtensionInstalled(extension,
-                                extensions::Extension::ENABLED,
-                                syncer::StringOrdinal(),
-                                extensions::kInstallFlagIsEphemeral,
-                                std::string());
-
-    service->AddExtension(extension);
-  }
-
   scoped_ptr<TestBackgroundModeManager> manager_;
 
   scoped_ptr<base::CommandLine> command_line_;
diff --git a/chrome/browser/browsing_data/browsing_data_remover.cc b/chrome/browser/browsing_data/browsing_data_remover.cc
index 7779d42f..1c2d5039 100644
--- a/chrome/browser/browsing_data/browsing_data_remover.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover.cc
@@ -95,7 +95,6 @@
 #endif
 
 #if defined(ENABLE_EXTENSIONS)
-#include "chrome/browser/apps/ephemeral_app_service.h"
 #include "chrome/browser/extensions/activity_log/activity_log.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_special_storage_policy.h"
@@ -693,16 +692,6 @@
 
     storage_partition_remove_mask |=
         content::StoragePartition::REMOVE_DATA_MASK_WEBRTC_IDENTITY;
-
-#if defined(ENABLE_EXTENSIONS)
-    // Clear the ephemeral apps cache. This is nullptr while testing. OTR
-    // Profile has neither apps nor an ExtensionService, so ClearCachedApps
-    // fails.
-    EphemeralAppService* ephemeral_app_service =
-        EphemeralAppService::Get(profile_);
-    if (ephemeral_app_service && !profile_->IsOffTheRecord())
-      ephemeral_app_service->ClearCachedApps();
-#endif
   }
 
   if (remove_mask & REMOVE_WEBRTC_IDENTITY) {
diff --git a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
index b091d89..dbbf9c6 100644
--- a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
@@ -461,6 +461,7 @@
   // Press Search+Shift+/ to enter ChromeVox's "find in page".
   SendKeyPressWithSearchAndShift(ui::VKEY_OEM_2);
   EXPECT_EQ("Find in page.", speech_monitor_.GetNextUtterance());
+  EXPECT_EQ(",", speech_monitor_.GetNextUtterance());
   EXPECT_EQ("Enter a search query.", speech_monitor_.GetNextUtterance());
 }
 
@@ -485,6 +486,7 @@
   SendKeyPressWithControl(ui::VKEY_OEM_1);
   SendKeyPress(ui::VKEY_OEM_2);
   EXPECT_EQ("Find in page.", speech_monitor_.GetNextUtterance());
+  EXPECT_EQ(",", speech_monitor_.GetNextUtterance());
   EXPECT_EQ("Enter a search query.", speech_monitor_.GetNextUtterance());
 }
 
diff --git a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
index 512d2d4..1d83f066 100644
--- a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
+++ b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
@@ -206,8 +206,8 @@
     // Descriptive statement about the app.
     emk::kRequirements,
 
-    // Execute some pages in a separate sandbox. (manifest_constants.cc only has
-    // constants for sub-keys.)
+    // Execute some pages in a separate sandbox.  (Note:
+    // extensions::manifest_keys only has constants for sub-keys.)
     "sandbox",
 
     // TBD, doc missing
@@ -216,8 +216,8 @@
     // Network access.
     emk::kSockets,
 
-    // TBD
-    // emk::kIsolatedStorage,
+    // TBD.  (Note: extensions::manifest_keys only has constants for sub-keys.)
+    // "storage",
 
     // TBD, doc missing
     // emk::kSystemIndicator,
@@ -287,7 +287,7 @@
 
     // Possibly risky due to its experimental nature: not vetted for security,
     // potentially buggy, subject to change without notice.
-    // "experimental,"
+    // "experimental",
 
     // TBD
     // "fileSystem",
diff --git a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc
index 180be997..f5717ed 100644
--- a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc
+++ b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc
@@ -208,6 +208,24 @@
     error.clear();
   }
 
+  // Verify that a platform app with an unsafe manifest entry cannot be
+  // installed.  Since the program logic is based entirely on whitelists, there
+  // is no significant advantage in testing all unsafe manifest entries
+  // individually.
+  {
+    base::DictionaryValue values;
+    values.Set("commands", new base::DictionaryValue());
+    extension = CreatePlatformAppWithExtraValues(
+        &values,
+        extensions::Manifest::EXTERNAL_POLICY,
+        extensions::Extension::NO_FLAGS);
+    ASSERT_TRUE(extension);
+
+    EXPECT_FALSE(provider.UserMayLoad(extension.get(), &error));
+    EXPECT_NE(base::string16(), error);
+    error.clear();
+  }
+
   // Verify that a platform app with an unknown manifest entry under "app"
   // cannot be installed.
   {
@@ -224,10 +242,30 @@
     error.clear();
   }
 
-  // Verify that a platform app with an unsafe permission entry cannot be
+  // Verify that a platform app with an unknown permission entry cannot be
   // installed.
   {
     base::ListValue* const permissions = new base::ListValue();
+    permissions->AppendString("not_whitelisted_permission");
+    base::DictionaryValue values;
+    values.Set(extensions::manifest_keys::kPermissions, permissions);
+
+    extension = CreatePlatformAppWithExtraValues(
+        &values,
+        extensions::Manifest::EXTERNAL_POLICY,
+        extensions::Extension::NO_FLAGS);
+    ASSERT_TRUE(extension);
+
+    EXPECT_FALSE(provider.UserMayLoad(extension.get(), &error));
+    EXPECT_NE(base::string16(), error);
+    error.clear();
+  }
+
+  // Verify that a platform app with an unsafe permission entry cannot be
+  // installed.  Since the program logic is based entirely on whitelists, there
+  // is no significant advantage in testing all unsafe permissions individually.
+  {
+    base::ListValue* const permissions = new base::ListValue();
     permissions->AppendString("audioCapture");
     base::DictionaryValue values;
     values.Set(extensions::manifest_keys::kPermissions, permissions);
diff --git a/chrome/browser/chromeos/file_manager/file_browser_handlers.cc b/chrome/browser/chromeos/file_manager/file_browser_handlers.cc
index 846adbd9..44adfc6 100644
--- a/chrome/browser/chromeos/file_manager/file_browser_handlers.cc
+++ b/chrome/browser/chromeos/file_manager/file_browser_handlers.cc
@@ -120,9 +120,6 @@
     if (profile->IsOffTheRecord() &&
         !extensions::util::IsIncognitoEnabled(extension->id(), profile))
       continue;
-    if (extensions::util::IsEphemeralApp(extension->id(), profile))
-      continue;
-
     FileBrowserHandler::List* handler_list =
         FileBrowserHandler::GetHandlers(extension.get());
     if (!handler_list)
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.cc b/chrome/browser/chromeos/file_manager/file_tasks.cc
index 66619f606..a09ef59 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks.cc
@@ -405,10 +405,6 @@
     if (!CanLaunchViaEvent(extension))
       continue;
 
-    // Ephemeral apps cannot be file handlers.
-    if (extensions::util::IsEphemeralApp(extension->id(), profile))
-      continue;
-
     if (profile->IsOffTheRecord() &&
         !extensions::util::IsIncognitoEnabled(extension->id(), profile))
       continue;
diff --git a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
index b1d68460..9efaba6 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
@@ -461,88 +461,53 @@
   // % ruby -le 'print (0...32).to_a.map{(?a + rand(16)).chr}.join'
   const char kFooId[] = "hhgbjpmdppecanaaogonaigmmifgpaph";
   const char kBarId[] = "odlhccgofgkadkkhcmhgnhgahonahoca";
-  const char kEphemeralId[] = "opoomfdlbjcbjinalcjdjfoiikdeaoel";
 
   // Foo.app can handle "text/plain" and "text/html".
   extensions::ExtensionBuilder foo_app;
-  foo_app.SetManifest(extensions::DictionaryBuilder()
-                      .Set("name", "Foo")
-                      .Set("version", "1.0.0")
-                      .Set("manifest_version", 2)
-                      .Set("app",
-                           extensions::DictionaryBuilder()
-                           .Set("background",
-                                extensions::DictionaryBuilder()
-                                .Set("scripts",
-                                     extensions::ListBuilder()
-                                     .Append("background.js"))))
-                      .Set("file_handlers",
-                           extensions::DictionaryBuilder()
-                           .Set("text",
-                                extensions::DictionaryBuilder()
-                                .Set("title", "Text")
-                                .Set("types",
-                                     extensions::ListBuilder()
-                                     .Append("text/plain")
-                                     .Append("text/html")))));
-  foo_app.SetID(kFooId);
-  extension_service_->AddExtension(foo_app.Build().get());
-
-  // Bar.app can only handle "text/plain".
-  extensions::ExtensionBuilder bar_app;
-  bar_app.SetManifest(extensions::DictionaryBuilder()
-                      .Set("name", "Bar")
-                      .Set("version", "1.0.0")
-                      .Set("manifest_version", 2)
-                      .Set("app",
-                           extensions::DictionaryBuilder()
-                           .Set("background",
-                                extensions::DictionaryBuilder()
-                                .Set("scripts",
-                                     extensions::ListBuilder()
-                                     .Append("background.js"))))
-                      .Set("file_handlers",
-                           extensions::DictionaryBuilder()
-                           .Set("text",
-                                extensions::DictionaryBuilder()
-                                .Set("title", "Text")
-                                .Set("types",
-                                     extensions::ListBuilder()
-                                     .Append("text/plain")))));
-  bar_app.SetID(kBarId);
-  extension_service_->AddExtension(bar_app.Build().get());
-
-  // Ephemeral.app is an ephemeral app that can handle "text/plain".
-  // It should not ever be found as ephemeral apps cannot be file handlers.
-  extensions::ExtensionBuilder ephemeral_app;
-  ephemeral_app.SetManifest(
+  foo_app.SetManifest(
       extensions::DictionaryBuilder()
-          .Set("name", "Ephemeral")
+          .Set("name", "Foo")
           .Set("version", "1.0.0")
           .Set("manifest_version", 2)
           .Set("app",
                extensions::DictionaryBuilder().Set(
                    "background",
                    extensions::DictionaryBuilder().Set(
-                       "scripts",
-                       extensions::ListBuilder().Append("background.js"))))
+                       "scripts", std::move(extensions::ListBuilder().Append(
+                                      "background.js")))))
           .Set("file_handlers",
                extensions::DictionaryBuilder().Set(
                    "text",
-                   extensions::DictionaryBuilder().Set("title", "Text").Set(
-                       "types",
-                       extensions::ListBuilder().Append("text/plain")))));
-  ephemeral_app.SetID(kEphemeralId);
-  scoped_refptr<extensions::Extension> built_ephemeral_app(
-      ephemeral_app.Build());
-  extension_service_->AddExtension(built_ephemeral_app.get());
-  extensions::ExtensionPrefs* extension_prefs =
-      extensions::ExtensionPrefs::Get(&test_profile_);
-  extension_prefs->OnExtensionInstalled(built_ephemeral_app.get(),
-                                        extensions::Extension::ENABLED,
-                                        syncer::StringOrdinal(),
-                                        extensions::kInstallFlagIsEphemeral,
-                                        std::string());
+                   extensions::DictionaryBuilder()
+                       .Set("title", "Text")
+                       .Set("types", std::move(extensions::ListBuilder()
+                                                   .Append("text/plain")
+                                                   .Append("text/html"))))));
+  foo_app.SetID(kFooId);
+  extension_service_->AddExtension(foo_app.Build().get());
+
+  // Bar.app can only handle "text/plain".
+  extensions::ExtensionBuilder bar_app;
+  bar_app.SetManifest(
+      extensions::DictionaryBuilder()
+          .Set("name", "Bar")
+          .Set("version", "1.0.0")
+          .Set("manifest_version", 2)
+          .Set("app",
+               extensions::DictionaryBuilder().Set(
+                   "background",
+                   extensions::DictionaryBuilder().Set(
+                       "scripts", std::move(extensions::ListBuilder().Append(
+                                      "background.js")))))
+          .Set("file_handlers",
+               extensions::DictionaryBuilder().Set(
+                   "text",
+                   extensions::DictionaryBuilder()
+                       .Set("title", "Text")
+                       .Set("types", std::move(extensions::ListBuilder().Append(
+                                         "text/plain"))))));
+  bar_app.SetID(kBarId);
+  extension_service_->AddExtension(bar_app.Build().get());
 
   // Find apps for a "text/plain" file. Foo.app and Bar.app should be found.
   PathAndMimeTypeSet path_mime_set;
@@ -598,7 +563,6 @@
   // Copied from FindFileHandlerTasks test above.
   const char kFooId[] = "hhgbjpmdppecanaaogonaigmmifgpaph";
   const char kBarId[] = "odlhccgofgkadkkhcmhgnhgahonahoca";
-  const char kEphemeralId[] = "opoomfdlbjcbjinalcjdjfoiikdeaoel";
 
   // Foo.app can handle ".txt" and ".html".
   // This one is an extension, and has "file_browser_handlers"
@@ -608,17 +572,17 @@
           .Set("name", "Foo")
           .Set("version", "1.0.0")
           .Set("manifest_version", 2)
-          .Set("permissions",
-               extensions::ListBuilder().Append("fileBrowserHandler"))
-          .Set(
-              "file_browser_handlers",
-              extensions::ListBuilder().Append(
-                  extensions::DictionaryBuilder()
-                      .Set("id", "open")
-                      .Set("default_title", "open")
-                      .Set("file_filters", extensions::ListBuilder()
-                                               .Append("filesystem:*.txt")
-                                               .Append("filesystem:*.html")))));
+          .Set("permissions", std::move(extensions::ListBuilder().Append(
+                                  "fileBrowserHandler")))
+          .Set("file_browser_handlers",
+               std::move(extensions::ListBuilder().Append(
+                   extensions::DictionaryBuilder()
+                       .Set("id", "open")
+                       .Set("default_title", "open")
+                       .Set("file_filters",
+                            std::move(extensions::ListBuilder()
+                                          .Append("filesystem:*.txt")
+                                          .Append("filesystem:*.html")))))));
   foo_app.SetID(kFooId);
   extension_service_->AddExtension(foo_app.Build().get());
 
@@ -629,48 +593,19 @@
           .Set("name", "Bar")
           .Set("version", "1.0.0")
           .Set("manifest_version", 2)
-          .Set("permissions",
-               extensions::ListBuilder().Append("fileBrowserHandler"))
+          .Set("permissions", std::move(extensions::ListBuilder().Append(
+                                  "fileBrowserHandler")))
           .Set("file_browser_handlers",
-               extensions::ListBuilder().Append(
+               std::move(extensions::ListBuilder().Append(
                    extensions::DictionaryBuilder()
                        .Set("id", "open")
                        .Set("default_title", "open")
-                       .Set("file_filters", extensions::ListBuilder().Append(
-                                                "filesystem:*.txt")))));
+                       .Set("file_filters",
+                            std::move(extensions::ListBuilder().Append(
+                                "filesystem:*.txt")))))));
   bar_app.SetID(kBarId);
   extension_service_->AddExtension(bar_app.Build().get());
 
-  // Ephemeral.app is an ephemeral app that can handle ".txt".
-  // It should not ever be found as ephemeral apps cannot be file browser
-  // handlers.
-  extensions::ExtensionBuilder ephemeral_app;
-  ephemeral_app.SetManifest(
-      extensions::DictionaryBuilder()
-          .Set("name", "Ephemeral")
-          .Set("version", "1.0.0")
-          .Set("manifest_version", 2)
-          .Set("permissions",
-               extensions::ListBuilder().Append("fileBrowserHandler"))
-          .Set("file_browser_handlers",
-               extensions::ListBuilder().Append(
-                   extensions::DictionaryBuilder()
-                       .Set("id", "open")
-                       .Set("default_title", "open")
-                       .Set("file_filters", extensions::ListBuilder().Append(
-                                                "filesystem:*.txt")))));
-  ephemeral_app.SetID(kEphemeralId);
-  scoped_refptr<extensions::Extension> built_ephemeral_app(
-      ephemeral_app.Build());
-  extension_service_->AddExtension(built_ephemeral_app.get());
-  extensions::ExtensionPrefs* extension_prefs =
-      extensions::ExtensionPrefs::Get(&test_profile_);
-  extension_prefs->OnExtensionInstalled(built_ephemeral_app.get(),
-                                        extensions::Extension::ENABLED,
-                                        syncer::StringOrdinal(),
-                                        extensions::kInstallFlagIsEphemeral,
-                                        std::string());
-
   // Find apps for a ".txt" file. Foo.app and Bar.app should be found.
   std::vector<GURL> file_urls;
   file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.txt"));
@@ -716,25 +651,24 @@
   // Foo.app can handle "text/plain".
   // This is a packaged app (file handler).
   extensions::ExtensionBuilder foo_app;
-  foo_app.SetManifest(extensions::DictionaryBuilder()
-                      .Set("name", "Foo")
-                      .Set("version", "1.0.0")
-                      .Set("manifest_version", 2)
-                      .Set("app",
-                           extensions::DictionaryBuilder()
-                           .Set("background",
-                                extensions::DictionaryBuilder()
-                                .Set("scripts",
-                                     extensions::ListBuilder()
-                                     .Append("background.js"))))
-                      .Set("file_handlers",
-                           extensions::DictionaryBuilder()
-                           .Set("text",
-                                extensions::DictionaryBuilder()
-                                .Set("title", "Text")
-                                .Set("types",
-                                     extensions::ListBuilder()
-                                     .Append("text/plain")))));
+  foo_app.SetManifest(
+      extensions::DictionaryBuilder()
+          .Set("name", "Foo")
+          .Set("version", "1.0.0")
+          .Set("manifest_version", 2)
+          .Set("app",
+               extensions::DictionaryBuilder().Set(
+                   "background",
+                   extensions::DictionaryBuilder().Set(
+                       "scripts", std::move(extensions::ListBuilder().Append(
+                                      "background.js")))))
+          .Set("file_handlers",
+               extensions::DictionaryBuilder().Set(
+                   "text",
+                   extensions::DictionaryBuilder()
+                       .Set("title", "Text")
+                       .Set("types", std::move(extensions::ListBuilder().Append(
+                                         "text/plain"))))));
   foo_app.SetID(kFooId);
   extension_service_->AddExtension(foo_app.Build().get());
 
@@ -746,15 +680,16 @@
           .Set("name", "Bar")
           .Set("version", "1.0.0")
           .Set("manifest_version", 2)
-          .Set("permissions",
-               extensions::ListBuilder().Append("fileBrowserHandler"))
+          .Set("permissions", std::move(extensions::ListBuilder().Append(
+                                  "fileBrowserHandler")))
           .Set("file_browser_handlers",
-               extensions::ListBuilder().Append(
+               std::move(extensions::ListBuilder().Append(
                    extensions::DictionaryBuilder()
                        .Set("id", "open")
                        .Set("default_title", "open")
-                       .Set("file_filters", extensions::ListBuilder().Append(
-                                                "filesystem:*.txt")))));
+                       .Set("file_filters",
+                            std::move(extensions::ListBuilder().Append(
+                                "filesystem:*.txt")))))));
   bar_app.SetID(kBarId);
   extension_service_->AddExtension(bar_app.Build().get());
 
@@ -837,15 +772,16 @@
           .Set("name", "Bar")
           .Set("version", "1.0.0")
           .Set("manifest_version", 2)
-          .Set("permissions",
-               extensions::ListBuilder().Append("fileBrowserHandler"))
+          .Set("permissions", std::move(extensions::ListBuilder().Append(
+                                  "fileBrowserHandler")))
           .Set("file_browser_handlers",
-               extensions::ListBuilder().Append(
+               std::move(extensions::ListBuilder().Append(
                    extensions::DictionaryBuilder()
                        .Set("id", "open")
                        .Set("default_title", "open")
-                       .Set("file_filters", extensions::ListBuilder().Append(
-                                                "filesystem:*.gdoc")))));
+                       .Set("file_filters",
+                            std::move(extensions::ListBuilder().Append(
+                                "filesystem:*.gdoc")))))));
   bar_app.SetID(kBarId);
   extension_service_->AddExtension(bar_app.Build().get());
 
@@ -858,15 +794,16 @@
           .Set("name", "Files")
           .Set("version", "1.0.0")
           .Set("manifest_version", 2)
-          .Set("permissions",
-               extensions::ListBuilder().Append("fileBrowserHandler"))
+          .Set("permissions", std::move(extensions::ListBuilder().Append(
+                                  "fileBrowserHandler")))
           .Set("file_browser_handlers",
-               extensions::ListBuilder().Append(
+               std::move(extensions::ListBuilder().Append(
                    extensions::DictionaryBuilder()
                        .Set("id", "open")
                        .Set("default_title", "open")
-                       .Set("file_filters", extensions::ListBuilder().Append(
-                                                "filesystem:*.gdoc")))));
+                       .Set("file_filters",
+                            std::move(extensions::ListBuilder().Append(
+                                "filesystem:*.gdoc")))))));
   files_app.SetID(kFileManagerAppId);
   extension_service_->AddExtension(files_app.Build().get());
 
@@ -901,87 +838,99 @@
 
   // Foo app provides file handler for text/plain and all file types.
   extensions::ExtensionBuilder foo_app;
-  foo_app.SetManifest(extensions::DictionaryBuilder()
-                      .Set("name", "Foo")
-                      .Set("version", "1.0.0")
-                      .Set("manifest_version", 2)
-                      .Set("app", extensions::DictionaryBuilder()
-                           .Set("background", extensions::DictionaryBuilder()
-                                .Set("scripts", extensions::ListBuilder()
-                                    .Append("background.js"))))
-                      .Set("file_handlers",
-                           extensions::DictionaryBuilder()
-                           .Set("any",
-                                extensions::DictionaryBuilder()
-                                .Set("types", extensions::ListBuilder()
-                                     .Append("*/*")))
-                           .Set("text",
-                                extensions::DictionaryBuilder()
-                                .Set("types", extensions::ListBuilder()
-                                     .Append("text/plain")))));
+  foo_app.SetManifest(
+      extensions::DictionaryBuilder()
+          .Set("name", "Foo")
+          .Set("version", "1.0.0")
+          .Set("manifest_version", 2)
+          .Set("app",
+               extensions::DictionaryBuilder().Set(
+                   "background",
+                   extensions::DictionaryBuilder().Set(
+                       "scripts", std::move(extensions::ListBuilder().Append(
+                                      "background.js")))))
+          .Set("file_handlers",
+               extensions::DictionaryBuilder()
+                   .Set("any",
+                        extensions::DictionaryBuilder().Set(
+                            "types",
+                            std::move(extensions::ListBuilder().Append("*/*"))))
+                   .Set("text",
+                        extensions::DictionaryBuilder().Set(
+                            "types", std::move(extensions::ListBuilder().Append(
+                                         "text/plain"))))));
   foo_app.SetID(kFooId);
   extension_service_->AddExtension(foo_app.Build().get());
 
   // Bar app provides file handler for .txt and not provide generic file
   // handler.
   extensions::ExtensionBuilder bar_app;
-  bar_app.SetManifest(extensions::DictionaryBuilder()
-                      .Set("name", "Bar")
-                      .Set("version", "1.0.0")
-                      .Set("manifest_version", 2)
-                      .Set("app", extensions::DictionaryBuilder()
-                           .Set("background", extensions::DictionaryBuilder()
-                                .Set("scripts", extensions::ListBuilder()
-                                    .Append("background.js"))))
-                      .Set("file_handlers",
-                           extensions::DictionaryBuilder()
-                           .Set("text",
-                                extensions::DictionaryBuilder()
-                                .Set("extensions", extensions::ListBuilder()
-                                     .Append("txt")))));
+  bar_app.SetManifest(
+      extensions::DictionaryBuilder()
+          .Set("name", "Bar")
+          .Set("version", "1.0.0")
+          .Set("manifest_version", 2)
+          .Set("app",
+               extensions::DictionaryBuilder().Set(
+                   "background",
+                   extensions::DictionaryBuilder().Set(
+                       "scripts", std::move(extensions::ListBuilder().Append(
+                                      "background.js")))))
+          .Set("file_handlers",
+               extensions::DictionaryBuilder().Set(
+                   "text",
+                   extensions::DictionaryBuilder().Set(
+                       "extensions",
+                       std::move(extensions::ListBuilder().Append("txt"))))));
   bar_app.SetID(kBarId);
   extension_service_->AddExtension(bar_app.Build().get());
 
   // Baz app provides file handler for all extensions and images.
   extensions::ExtensionBuilder baz_app;
-  baz_app.SetManifest(extensions::DictionaryBuilder()
-                      .Set("name", "Baz")
-                      .Set("version", "1.0.0")
-                      .Set("manifest_version", 2)
-                      .Set("app", extensions::DictionaryBuilder()
-                           .Set("background", extensions::DictionaryBuilder()
-                                .Set("scripts", extensions::ListBuilder()
-                                    .Append("background.js"))))
-                      .Set("file_handlers",
-                           extensions::DictionaryBuilder()
-                           .Set("any",
-                                extensions::DictionaryBuilder()
-                                .Set("extensions", extensions::ListBuilder()
-                                     .Append("*")
-                                     .Append("bar")))
-                           .Set("image",
-                                extensions::DictionaryBuilder()
-                                .Set("types", extensions::ListBuilder()
-                                     .Append("image/*")))));
+  baz_app.SetManifest(
+      extensions::DictionaryBuilder()
+          .Set("name", "Baz")
+          .Set("version", "1.0.0")
+          .Set("manifest_version", 2)
+          .Set("app",
+               extensions::DictionaryBuilder().Set(
+                   "background",
+                   extensions::DictionaryBuilder().Set(
+                       "scripts", std::move(extensions::ListBuilder().Append(
+                                      "background.js")))))
+          .Set("file_handlers",
+               extensions::DictionaryBuilder()
+                   .Set("any",
+                        extensions::DictionaryBuilder().Set(
+                            "extensions", std::move(extensions::ListBuilder()
+                                                        .Append("*")
+                                                        .Append("bar"))))
+                   .Set("image",
+                        extensions::DictionaryBuilder().Set(
+                            "types", std::move(extensions::ListBuilder().Append(
+                                         "image/*"))))));
   baz_app.SetID(kBazId);
   extension_service_->AddExtension(baz_app.Build().get());
 
   // Qux app provides file handler for all types.
   extensions::ExtensionBuilder qux_app;
-  qux_app.SetManifest(extensions::DictionaryBuilder()
-                      .Set("name", "Qux")
-                      .Set("version", "1.0.0")
-                      .Set("manifest_version", 2)
-                      .Set("app", extensions::DictionaryBuilder()
-                           .Set("background", extensions::DictionaryBuilder()
-                                .Set("scripts", extensions::ListBuilder()
-                                    .Append("background.js"))))
-                      .Set("file_handlers",
-                           extensions::DictionaryBuilder()
-                           .Set("any",
-                                extensions::DictionaryBuilder()
-                                .Set("types", extensions::ListBuilder()
-                                     .Append("*")))));
+  qux_app.SetManifest(
+      extensions::DictionaryBuilder()
+          .Set("name", "Qux")
+          .Set("version", "1.0.0")
+          .Set("manifest_version", 2)
+          .Set("app",
+               extensions::DictionaryBuilder().Set(
+                   "background",
+                   extensions::DictionaryBuilder().Set(
+                       "scripts", std::move(extensions::ListBuilder().Append(
+                                      "background.js")))))
+          .Set("file_handlers",
+               extensions::DictionaryBuilder().Set(
+                   "any",
+                   extensions::DictionaryBuilder().Set(
+                       "types",
+                       std::move(extensions::ListBuilder().Append("*"))))));
   qux_app.SetID(kQuxId);
   extension_service_->AddExtension(qux_app.Build().get());
 
diff --git a/chrome/browser/chromeos/login/app_launch_signin_screen.cc b/chrome/browser/chromeos/login/app_launch_signin_screen.cc
index c34087a..adbbf0b 100644
--- a/chrome/browser/chromeos/login/app_launch_signin_screen.cc
+++ b/chrome/browser/chromeos/login/app_launch_signin_screen.cc
@@ -215,7 +215,7 @@
 
 void AppLaunchSigninScreen::CheckUserStatus(const AccountId& account_id) {}
 
-bool AppLaunchSigninScreen::IsUserWhitelisted(const std::string& user_id) {
+bool AppLaunchSigninScreen::IsUserWhitelisted(const AccountId& account_id) {
   NOTREACHED();
   return true;
 }
diff --git a/chrome/browser/chromeos/login/app_launch_signin_screen.h b/chrome/browser/chromeos/login/app_launch_signin_screen.h
index 45a9cc5b..a716ebd 100644
--- a/chrome/browser/chromeos/login/app_launch_signin_screen.h
+++ b/chrome/browser/chromeos/login/app_launch_signin_screen.h
@@ -80,7 +80,7 @@
   void Signout() override;
   void HandleGetUsers() override;
   void CheckUserStatus(const AccountId& account_id) override;
-  bool IsUserWhitelisted(const std::string& user_id) override;
+  bool IsUserWhitelisted(const AccountId& account_id) override;
 
   // AuthStatusConsumer implementation:
   void OnAuthFailure(const AuthFailure& error) override;
diff --git a/chrome/browser/chromeos/login/auth/chrome_login_performer.cc b/chrome/browser/chromeos/login/auth/chrome_login_performer.cc
index e912445..47353c4 100644
--- a/chrome/browser/chromeos/login/auth/chrome_login_performer.cc
+++ b/chrome/browser/chromeos/login/auth/chrome_login_performer.cc
@@ -84,13 +84,13 @@
   }
 }
 
-bool ChromeLoginPerformer::IsUserWhitelisted(const std::string& user_id,
+bool ChromeLoginPerformer::IsUserWhitelisted(const AccountId& account_id,
                                              bool* wildcard_match) {
-  return CrosSettings::IsWhitelisted(user_id, wildcard_match);
+  return CrosSettings::IsWhitelisted(account_id.GetUserEmail(), wildcard_match);
 }
 
 void ChromeLoginPerformer::RunOnlineWhitelistCheck(
-    const std::string& user_id,
+    const AccountId& account_id,
     bool wildcard_match,
     const std::string& refresh_token,
     const base::Closure& success_callback,
@@ -99,7 +99,7 @@
   policy::BrowserPolicyConnectorChromeOS* connector =
       g_browser_process->platform_part()->browser_policy_connector_chromeos();
   if (connector->IsEnterpriseManaged() && wildcard_match &&
-      !connector->IsNonEnterpriseUser(user_id)) {
+      !connector->IsNonEnterpriseUser(account_id.GetUserEmail())) {
     wildcard_login_checker_.reset(new policy::WildcardLoginChecker());
     if (refresh_token.empty()) {
       wildcard_login_checker_->StartWithSigninContext(
@@ -143,27 +143,27 @@
   return authentication->TransformKey(context);
 }
 
-void ChromeLoginPerformer::SetupSupervisedUserFlow(const std::string& user_id) {
-  SupervisedUserLoginFlow* new_flow = new SupervisedUserLoginFlow(user_id);
-  new_flow->SetHost(ChromeUserManager::Get()
-                        ->GetUserFlow(AccountId::FromUserEmail(user_id))
-                        ->host());
-  ChromeUserManager::Get()->SetUserFlow(AccountId::FromUserEmail(user_id),
-                                        new_flow);
+void ChromeLoginPerformer::SetupSupervisedUserFlow(
+    const AccountId& account_id) {
+  SupervisedUserLoginFlow* new_flow = new SupervisedUserLoginFlow(account_id);
+  new_flow->SetHost(ChromeUserManager::Get()->GetUserFlow(account_id)->host());
+  ChromeUserManager::Get()->SetUserFlow(account_id, new_flow);
 }
 
-void ChromeLoginPerformer::SetupEasyUnlockUserFlow(const std::string& user_id) {
-  ChromeUserManager::Get()->SetUserFlow(AccountId::FromUserEmail(user_id),
-                                        new EasyUnlockUserLoginFlow(user_id));
+void ChromeLoginPerformer::SetupEasyUnlockUserFlow(
+    const AccountId& account_id) {
+  ChromeUserManager::Get()->SetUserFlow(
+      account_id, new EasyUnlockUserLoginFlow(account_id));
 }
 
-bool ChromeLoginPerformer::CheckPolicyForUser(const std::string& user_id) {
+bool ChromeLoginPerformer::CheckPolicyForUser(const AccountId& account_id) {
   // Login is not allowed if policy could not be loaded for the account.
   policy::BrowserPolicyConnectorChromeOS* connector =
       g_browser_process->platform_part()->browser_policy_connector_chromeos();
   policy::DeviceLocalAccountPolicyService* policy_service =
       connector->GetDeviceLocalAccountPolicyService();
-  return policy_service && policy_service->IsPolicyAvailableForUser(user_id);
+  return policy_service &&
+         policy_service->IsPolicyAvailableForUser(account_id.GetUserEmail());
 }
 ////////////////////////////////////////////////////////////////////////////////
 // ChromeLoginPerformer, private:
diff --git a/chrome/browser/chromeos/login/auth/chrome_login_performer.h b/chrome/browser/chromeos/login/auth/chrome_login_performer.h
index a0b670c5..695805c 100644
--- a/chrome/browser/chromeos/login/auth/chrome_login_performer.h
+++ b/chrome/browser/chromeos/login/auth/chrome_login_performer.h
@@ -20,6 +20,8 @@
 #include "content/public/browser/notification_registrar.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 
+class AccountId;
+
 namespace policy {
 class WildcardLoginChecker;
 }
@@ -33,14 +35,14 @@
   explicit ChromeLoginPerformer(Delegate* delegate);
   ~ChromeLoginPerformer() override;
 
-  bool IsUserWhitelisted(const std::string& user_id,
+  bool IsUserWhitelisted(const AccountId& account_id,
                          bool* wildcard_match) override;
 
  protected:
   bool RunTrustedCheck(const base::Closure& callback) override;
   void DidRunTrustedCheck(const base::Closure& callback);
 
-  void RunOnlineWhitelistCheck(const std::string& user_id,
+  void RunOnlineWhitelistCheck(const AccountId& account_id,
                                bool wildcard_match,
                                const std::string& refresh_token,
                                const base::Closure& success_callback,
@@ -52,12 +54,12 @@
 
   UserContext TransformSupervisedKey(const UserContext& context) override;
 
-  void SetupSupervisedUserFlow(const std::string& user_id) override;
+  void SetupSupervisedUserFlow(const AccountId& account_id) override;
 
-  void SetupEasyUnlockUserFlow(const std::string& user_id) override;
+  void SetupEasyUnlockUserFlow(const AccountId& account_id) override;
 
   scoped_refptr<Authenticator> CreateAuthenticator() override;
-  bool CheckPolicyForUser(const std::string& user_id) override;
+  bool CheckPolicyForUser(const AccountId& account_id) override;
   content::BrowserContext* GetSigninContext() override;
   net::URLRequestContextGetter* GetSigninRequestContext() override;
 
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index e6c39899..20ed1a91 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -147,6 +147,7 @@
 #if defined(ENABLE_TOPCHROME_MD)
     ::switches::kTopChromeMD,
 #endif
+    ::switches::kTraceToConsole,
     ::switches::kUIDisablePartialSwap,
     ::switches::kUIEnableCompositorAnimationTimelines,
     ::switches::kUIPrioritizeInGpuProcess,
diff --git a/chrome/browser/chromeos/login/easy_unlock/bootstrap_manager.cc b/chrome/browser/chromeos/login/easy_unlock/bootstrap_manager.cc
index 7ad5dde..d4fb577a 100644
--- a/chrome/browser/chromeos/login/easy_unlock/bootstrap_manager.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/bootstrap_manager.cc
@@ -31,21 +31,22 @@
 BootstrapManager::~BootstrapManager() {
 }
 
-void BootstrapManager::AddPendingBootstrap(const std::string& user_id) {
-  DCHECK(!user_id.empty());
+void BootstrapManager::AddPendingBootstrap(const AccountId& account_id) {
+  DCHECK(account_id.is_valid());
   PrefService* local_state = g_browser_process->local_state();
 
   ListPrefUpdate update(local_state, kPendingEasyBootstrapUsers);
-  update->AppendString(user_id);
+  update->AppendString(account_id.GetUserEmail());
 }
 
-void BootstrapManager::FinishPendingBootstrap(const std::string& user_id) {
+void BootstrapManager::FinishPendingBootstrap(const AccountId& account_id) {
   PrefService* local_state = g_browser_process->local_state();
 
   ListPrefUpdate update(local_state, kPendingEasyBootstrapUsers);
   for (size_t i = 0; i < update->GetSize(); ++i) {
-    std::string current_user;
-    if (update->GetString(i, &current_user) && user_id == current_user) {
+    std::string current_user_email;
+    if (update->GetString(i, &current_user_email) &&
+        account_id.GetUserEmail() == current_user_email) {
       update->Remove(i, NULL);
       break;
     }
@@ -58,23 +59,27 @@
   const base::ListValue* users =
       local_state->GetList(kPendingEasyBootstrapUsers);
   for (size_t i = 0; i < users->GetSize(); ++i) {
-    std::string current_user;
-    if (users->GetString(i, &current_user))
-      delegate_->RemovePendingBootstrapUser(current_user);
+    std::string current_user_email;
+    if (users->GetString(i, &current_user_email)) {
+      delegate_->RemovePendingBootstrapUser(
+          user_manager::UserManager::Get()->GetKnownUserAccountId(
+              current_user_email, std::string() /* gaia_id */));
+    }
   }
 
   local_state->ClearPref(kPendingEasyBootstrapUsers);
   local_state->CommitPendingWrite();
 }
 
-bool BootstrapManager::HasPendingBootstrap(const std::string& user_id) const {
+bool BootstrapManager::HasPendingBootstrap(const AccountId& account_id) const {
   PrefService* local_state = g_browser_process->local_state();
 
   const base::ListValue* users =
       local_state->GetList(kPendingEasyBootstrapUsers);
   for (size_t i = 0; i < users->GetSize(); ++i) {
     std::string current_user;
-    if (users->GetString(i, &current_user) && user_id == current_user)
+    if (users->GetString(i, &current_user) &&
+        account_id.GetUserEmail() == current_user)
       return true;
   }
   return false;
diff --git a/chrome/browser/chromeos/login/easy_unlock/bootstrap_manager.h b/chrome/browser/chromeos/login/easy_unlock/bootstrap_manager.h
index 46955baf..88879c8 100644
--- a/chrome/browser/chromeos/login/easy_unlock/bootstrap_manager.h
+++ b/chrome/browser/chromeos/login/easy_unlock/bootstrap_manager.h
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 
+class AccountId;
 class PrefRegistrySimple;
 
 namespace chromeos {
@@ -21,7 +22,7 @@
 
   class Delegate {
    public:
-    virtual void RemovePendingBootstrapUser(const std::string& user_id) = 0;
+    virtual void RemovePendingBootstrapUser(const AccountId& account_id) = 0;
 
    protected:
     virtual ~Delegate() {}
@@ -30,11 +31,11 @@
   explicit BootstrapManager(Delegate* delegate);
   ~BootstrapManager();
 
-  void AddPendingBootstrap(const std::string& user_id);
-  void FinishPendingBootstrap(const std::string& user_id);
+  void AddPendingBootstrap(const AccountId& account_id);
+  void FinishPendingBootstrap(const AccountId& account_id);
   void RemoveAllPendingBootstrap();
 
-  bool HasPendingBootstrap(const std::string& user_id) const;
+  bool HasPendingBootstrap(const AccountId& account_id) const;
 
  private:
   Delegate* delegate_;
diff --git a/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_context_initializer.cc b/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_context_initializer.cc
index d42c5df..6b3a82b 100644
--- a/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_context_initializer.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_context_initializer.cc
@@ -98,14 +98,14 @@
   service->AddObserver(this);
 
   static_cast<EasyUnlockServiceSignin*>(service)
-      ->SetCurrentUser(user_context_.GetAccountId().GetUserEmail());
+      ->SetCurrentUser(user_context_.GetAccountId());
   OnScreenlockStateChanged(service->GetScreenlockState());
 }
 
 void BootstrapUserContextInitializer::OnEasyUnlockAuthenticated(
     EasyUnlockAuthAttempt::Type auth_attempt_type,
     bool success,
-    const std::string& user_id,
+    const AccountId& account_id,
     const std::string& key_secret,
     const std::string& key_label) {
   DCHECK_EQ(EasyUnlockAuthAttempt::TYPE_SIGNIN, auth_attempt_type);
@@ -202,7 +202,7 @@
   service->RemoveObserver(this);
 
   service->AttemptAuth(
-      user_context_.GetAccountId().GetUserEmail(),
+      user_context_.GetAccountId(),
       base::Bind(&BootstrapUserContextInitializer::OnEasyUnlockAuthenticated,
                  weak_ptr_factory_.GetWeakPtr()));
 }
diff --git a/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_context_initializer.h b/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_context_initializer.h
index c2ea90f3..2317a1c 100644
--- a/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_context_initializer.h
+++ b/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_context_initializer.h
@@ -17,6 +17,8 @@
 #include "chromeos/login/auth/user_context.h"
 #include "google_apis/gaia/gaia_oauth_client.h"
 
+class AccountId;
+
 namespace chromeos {
 
 // Performs initialization work for adding a new account via Easy bootstrap.
@@ -52,7 +54,7 @@
                            const EasyUnlockDeviceKeyDataList& data_list);
   void OnEasyUnlockAuthenticated(EasyUnlockAuthAttempt::Type auth_attempt_type,
                                  bool success,
-                                 const std::string& user_id,
+                                 const AccountId& account_id,
                                  const std::string& key_secret,
                                  const std::string& key_label);
   void CreateRandomKey();
diff --git a/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_flow.cc b/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_flow.cc
index acf5cf5..856922b0 100644
--- a/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_flow.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_flow.cc
@@ -20,14 +20,14 @@
 
 BootstrapUserFlow::BootstrapUserFlow(const UserContext& user_context,
                                      bool is_new_account)
-    : ExtendedUserFlow(user_context.GetAccountId().GetUserEmail()),
+    : ExtendedUserFlow(user_context.GetAccountId()),
       user_context_(user_context),
       is_new_account_(is_new_account),
       finished_(false),
       user_profile_(nullptr),
       weak_ptr_factory_(this) {
   ChromeUserManager::Get()->GetBootstrapManager()->AddPendingBootstrap(
-      user_context_.GetAccountId().GetUserEmail());
+      user_context_.GetAccountId());
 }
 
 BootstrapUserFlow::~BootstrapUserFlow() {
@@ -111,7 +111,7 @@
   finished_ = true;
 
   ChromeUserManager::Get()->GetBootstrapManager()->FinishPendingBootstrap(
-      user_context_.GetAccountId().GetUserEmail());
+      user_context_.GetAccountId());
   UserSessionManager::GetInstance()->DoBrowserLaunch(user_profile_, host());
 
   user_profile_ = nullptr;
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper.cc
index f201e55..953aae4e 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper.cc
@@ -23,11 +23,11 @@
 EasyUnlockChallengeWrapper::EasyUnlockChallengeWrapper(
     const std::string& challenge,
     const std::string& channel_binding_data,
-    const std::string& user_id,
+    const AccountId& account_id,
     EasyUnlockTpmKeyManager* key_manager)
     : challenge_(challenge),
       channel_binding_data_(channel_binding_data),
-      user_id_(user_id),
+      account_id_(account_id),
       key_manager_(key_manager),
       weak_ptr_factory_(this) {}
 
@@ -62,7 +62,7 @@
 void EasyUnlockChallengeWrapper::SignUsingTpmKey(
     const std::string& data_to_sign,
     const base::Callback<void(const std::string&)>& callback) {
-  key_manager_->SignUsingTpmKey(user_id_, data_to_sign, callback);
+  key_manager_->SignUsingTpmKey(account_id_, data_to_sign, callback);
 }
 
 void EasyUnlockChallengeWrapper::OnChannelBindingDataSigned(
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper.h b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper.h
index 206d263..afd35b6 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper.h
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper.h
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "components/signin/core/account_id/account_id.h"
 
 class EasyUnlockTpmKeyManager;
 
@@ -24,12 +25,12 @@
   // |challenge|: The raw challenge to wrap.
   // |channel_binding_data|: Data unique to the current secure channel such that
   //                         we can bind with a TPM signature.
-  // |user_id|: The id of the user who owns both devices.
+  // |account_id|: The id of the user who owns both devices.
   // |key_manager|: Responsible for signing some piece of data with the TPM.
   //                Not owned and should outlive this instance.
   EasyUnlockChallengeWrapper(const std::string& challenge,
                              const std::string& channel_binding_data,
-                             const std::string& user_id,
+                             const AccountId& account_id,
                              EasyUnlockTpmKeyManager* key_manager);
   virtual ~EasyUnlockChallengeWrapper();
 
@@ -59,7 +60,7 @@
   const std::string channel_binding_data_;
 
   // The id of the user who owns both devices.
-  const std::string user_id_;
+  const AccountId account_id_;
 
   // Responsible for signing data with the TPM. Not owned.
   EasyUnlockTpmKeyManager* key_manager_;
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper_unittest.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper_unittest.cc
index 7e1df56..db57ea42 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper_unittest.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper_unittest.cc
@@ -29,7 +29,7 @@
   TestableEasyUnlockChallengeWrapper()
       : EasyUnlockChallengeWrapper(kChallenge,
                                    kChannelBindingData,
-                                   kUserId,
+                                   AccountId::FromUserEmail(kUserId),
                                    nullptr) {}
   ~TestableEasyUnlockChallengeWrapper() override {}
 
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.cc
index eb42a33..e65a434 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.cc
@@ -85,8 +85,8 @@
   EasyUnlockTpmKeyManager* tpm_key_manager =
       EasyUnlockTpmKeyManagerFactory::GetInstance()->GetForUser(
           user_context.GetAccountId().GetUserEmail());
-  const std::string tpm_public_key = tpm_key_manager->GetPublicTpmKey(
-      user_context.GetAccountId().GetUserEmail());
+  const std::string tpm_public_key =
+      tpm_key_manager->GetPublicTpmKey(user_context.GetAccountId());
 
   EasyUnlockDeviceKeyDataList devices;
   if (!RemoteDeviceListToDeviceDataList(*remote_devices, &devices))
@@ -110,7 +110,7 @@
 
 // static
 void EasyUnlockKeyManager::DeviceDataToRemoteDeviceDictionary(
-    const std::string& user_id,
+    const AccountId& account_id,
     const EasyUnlockDeviceKeyData& data,
     base::DictionaryValue* dict) {
   dict->SetString(kKeyBluetoothAddress, data.bluetooth_address);
@@ -123,7 +123,7 @@
   dict->SetString(kKeyPermitType, kPermitTypeLicence);
   dict->SetString(kKeyPermitPermitId,
                   base::StringPrintf(kPermitPermitIdFormat,
-                                     user_id.c_str()));
+                                     account_id.GetUserEmail().c_str()));
 }
 
 // static
@@ -161,14 +161,14 @@
 
 // static
 void EasyUnlockKeyManager::DeviceDataListToRemoteDeviceList(
-    const std::string& user_id,
+    const AccountId& account_id,
     const EasyUnlockDeviceKeyDataList& data_list,
     base::ListValue* device_list) {
   device_list->Clear();
   for (size_t i = 0; i < data_list.size(); ++i) {
     scoped_ptr<base::DictionaryValue> device_dict(new base::DictionaryValue);
-    DeviceDataToRemoteDeviceDictionary(
-        user_id, data_list[i], device_dict.get());
+    DeviceDataToRemoteDeviceDictionary(account_id, data_list[i],
+                                       device_dict.get());
     device_list->Append(device_dict.release());
   }
 }
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h
index 9d83875..35eda97 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h
@@ -17,6 +17,8 @@
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_refresh_keys_operation.h"
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_types.h"
 
+class AccountId;
+
 namespace base {
 class DictionaryValue;
 class ListValue;
@@ -54,7 +56,7 @@
   // conversion fails (missing required propery). Note that
   // EasyUnlockDeviceKeyData contains a sub set of the remote device dictionary.
   static void DeviceDataToRemoteDeviceDictionary(
-      const std::string& user_id,
+      const AccountId& account_id,
       const EasyUnlockDeviceKeyData& data,
       base::DictionaryValue* dict);
   static bool RemoteDeviceDictionaryToDeviceData(
@@ -64,7 +66,7 @@
   // Helpers to convert between EasyUnlockDeviceKeyDataList and remote devices
   // ListValue.
   static void DeviceDataListToRemoteDeviceList(
-      const std::string& user_id,
+      const AccountId& account_id,
       const EasyUnlockDeviceKeyDataList& data_list,
       base::ListValue* device_list);
   static bool RemoteDeviceListToDeviceDataList(
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.cc
index a04c385..35af9694 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.cc
@@ -86,7 +86,7 @@
     DCHECK(lock_users.size() == 1);
     proximity_auth::ScreenlockBridge::Get()
         ->lock_handler()
-        ->ShowUserPodCustomIcon(lock_users[0]->email(), icon_options);
+        ->ShowUserPodCustomIcon(lock_users[0]->GetAccountId(), icon_options);
   }
 
   // chromeos::AuthStatusConsumer:
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.cc
index cb389ed..dccd50d 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.cc
@@ -184,7 +184,7 @@
 
 // static
 void EasyUnlockTpmKeyManager::ResetLocalStateForUser(
-    const std::string& user_id) {
+    const AccountId& account_id) {
   if (!g_browser_process)
     return;
   PrefService* local_state = g_browser_process->local_state();
@@ -192,20 +192,19 @@
     return;
 
   DictionaryPrefUpdate update(local_state, prefs::kEasyUnlockLocalStateTpmKeys);
-  update->RemoveWithoutPathExpansion(user_id, NULL);
+  update->RemoveWithoutPathExpansion(account_id.GetUserEmail(), NULL);
 }
 
 EasyUnlockTpmKeyManager::EasyUnlockTpmKeyManager(
-    const std::string& user_id,
+    const AccountId& account_id,
     const std::string& username_hash,
     PrefService* local_state)
-    : user_id_(user_id),
+    : account_id_(account_id),
       username_hash_(username_hash),
       local_state_(local_state),
       create_tpm_key_state_(CREATE_TPM_KEY_NOT_STARTED),
       get_tpm_slot_weak_ptr_factory_(this),
-      weak_ptr_factory_(this) {
-}
+      weak_ptr_factory_(this) {}
 
 EasyUnlockTpmKeyManager::~EasyUnlockTpmKeyManager() {
 }
@@ -213,13 +212,13 @@
 bool EasyUnlockTpmKeyManager::PrepareTpmKey(
     bool check_private_key,
     const base::Closure& callback) {
-  CHECK(!user_id_.empty());
+  CHECK(account_id_.is_valid());
   CHECK(!username_hash_.empty());
 
   if (create_tpm_key_state_ == CREATE_TPM_KEY_DONE)
     return true;
 
-  std::string key = GetPublicTpmKey(user_id_);
+  std::string key = GetPublicTpmKey(account_id_);
   if (!check_private_key && !key.empty() &&
       create_tpm_key_state_ == CREATE_TPM_KEY_NOT_STARTED) {
     return true;
@@ -257,24 +256,24 @@
 }
 
 std::string EasyUnlockTpmKeyManager::GetPublicTpmKey(
-    const std::string& user_id) {
+    const AccountId& account_id) {
   if (!local_state_)
     return std::string();
   const base::DictionaryValue* dict =
       local_state_->GetDictionary(prefs::kEasyUnlockLocalStateTpmKeys);
   std::string key;
   if (dict)
-    dict->GetStringWithoutPathExpansion(user_id, &key);
+    dict->GetStringWithoutPathExpansion(account_id.GetUserEmail(), &key);
   std::string decoded;
   base::Base64Decode(key, &decoded);
   return decoded;
 }
 
 void EasyUnlockTpmKeyManager::SignUsingTpmKey(
-    const std::string& user_id,
+    const AccountId& account_id,
     const std::string& data,
     const base::Callback<void(const std::string& data)> callback) {
-  std::string key = GetPublicTpmKey(user_id);
+  const std::string key = GetPublicTpmKey(account_id);
   if (key.empty()) {
     callback.Run(std::string());
     return;
@@ -298,7 +297,7 @@
          create_tpm_key_state_ == CREATE_TPM_KEY_DONE;
 }
 
-void EasyUnlockTpmKeyManager::SetKeyInLocalState(const std::string& user_id,
+void EasyUnlockTpmKeyManager::SetKeyInLocalState(const AccountId& account_id,
                                                  const std::string& value) {
   if (!local_state_)
     return;
@@ -307,7 +306,7 @@
   base::Base64Encode(value, &encoded);
   DictionaryPrefUpdate update(local_state_,
                               prefs::kEasyUnlockLocalStateTpmKeys);
-  update->SetStringWithoutPathExpansion(user_id, encoded);
+  update->SetStringWithoutPathExpansion(account_id.GetUserEmail(), encoded);
 }
 
 void EasyUnlockTpmKeyManager::OnUserTPMInitialized(
@@ -378,7 +377,7 @@
   get_tpm_slot_weak_ptr_factory_.InvalidateWeakPtrs();
 
   if (!public_key.empty())
-    SetKeyInLocalState(user_id_, public_key);
+    SetKeyInLocalState(account_id_, public_key);
 
   for (size_t i = 0; i < prepare_tpm_key_callbacks_.size(); ++i) {
     if (!prepare_tpm_key_callbacks_[i].is_null())
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.h b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.h
index f08bb49..01f0a34 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.h
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "crypto/scoped_nss_types.h"
 
 class PrefRegistrySimple;
@@ -25,14 +26,14 @@
   static void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
 
   // Clears local state for user. Should be called when a user is removed.
-  static void ResetLocalStateForUser(const std::string& user_id);
+  static void ResetLocalStateForUser(const AccountId& account_id);
 
-  // |user_id|: Id for the user associated with the service. Empty for sign-in
-  //     service.
+  // |account_id|: Id for the user associated with the service. Empty for
+  //     sign-in service.
   // |username_hash|: Username hash for the user associated with the service.
   //     Empty for sign-in service.
   // |local_state|: The local state prefs.
-  EasyUnlockTpmKeyManager(const std::string& user_id,
+  EasyUnlockTpmKeyManager(const AccountId& account_id,
                           const std::string& username_hash,
                           PrefService* local_state);
   ~EasyUnlockTpmKeyManager() override;
@@ -64,12 +65,12 @@
   bool StartGetSystemSlotTimeoutMs(size_t timeout_ms);
 
   // Gets the public RSA key for user. The key is retrieved from local state.
-  std::string GetPublicTpmKey(const std::string& user_id);
+  std::string GetPublicTpmKey(const AccountId& account_id);
 
   // Signs |data| using private RSA key associated with |user_id| stored in TPM
   // system slot.
   void SignUsingTpmKey(
-      const std::string& user_id,
+      const AccountId& account_id,
       const std::string& data,
       const base::Callback<void(const std::string& data)> callback);
 
@@ -86,7 +87,7 @@
 
   // Utility method for setting public key values in local state.
   // Note that the keys are saved base64 encoded.
-  void SetKeyInLocalState(const std::string& user_id,
+  void SetKeyInLocalState(const AccountId& account_id,
                           const std::string& value);
 
   // Called when TPM system slot is initialized and ready to be used.
@@ -128,7 +129,7 @@
       const base::Callback<void(const std::string&)>& callback,
       const std::string& signature);
 
-  std::string user_id_;
+  const AccountId account_id_;
   std::string username_hash_;
 
   PrefService* local_state_;
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.cc
index ebce3abcc..3badfbea 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.cc
@@ -37,8 +37,9 @@
 
 EasyUnlockTpmKeyManager* EasyUnlockTpmKeyManagerFactory::GetForUser(
     const std::string& user_id) {
-  const user_manager::User* user = user_manager::UserManager::Get()->FindUser(
-      AccountId::FromUserEmail(user_id));
+  user_manager::UserManager* user_manager = user_manager::UserManager::Get();
+  const user_manager::User* user = user_manager->FindUser(
+      user_manager->GetKnownUserAccountId(user_id, std::string()));
   if (!user)
     return NULL;
   Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
@@ -63,7 +64,7 @@
   if (!chromeos::ProfileHelper::IsSigninProfile(profile))
     user = chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
   return new EasyUnlockTpmKeyManager(
-      user ? user->email() : std::string(),
+      user ? user->GetAccountId() : EmptyAccountId(),
       user ? user->username_hash() : std::string(), GetLocalState());
 }
 
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_unittest.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_unittest.cc
index ef61f00..7120dac 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_unittest.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_unittest.cc
@@ -202,8 +202,7 @@
 
   void SetUp() override {
     ASSERT_TRUE(profile_manager_.SetUp());
-    const user_manager::User* user =
-        user_manager_->AddUser(AccountId::FromUserEmail(kTestUserId));
+    const user_manager::User* user = user_manager_->AddUser(test_account_id_);
     username_hash_ = user->username_hash();
 
     signin_profile_ = profile_manager_.CreateTestingProfile(
@@ -214,8 +213,9 @@
         TestingProfile::TestingFactories());
 
     user_profile_ = profile_manager_.CreateTestingProfile(
-        kTestUserId, scoped_ptr<syncable_prefs::TestingPrefServiceSyncable>(),
-        base::UTF8ToUTF16(kTestUserId), 0 /* avatar id */,
+        test_account_id_.GetUserEmail(),
+        scoped_ptr<syncable_prefs::TestingPrefServiceSyncable>(),
+        base::UTF8ToUTF16(test_account_id_.GetUserEmail()), 0 /* avatar id */,
         std::string() /* supervized user id */,
         TestingProfile::TestingFactories());
   }
@@ -223,7 +223,7 @@
   void TearDown() override {
     if (test_nss_user_)
       ResetTestNssUser();
-    profile_manager_.DeleteTestingProfile(kTestUserId);
+    profile_manager_.DeleteTestingProfile(test_account_id_.GetUserEmail());
     profile_manager_.DeleteTestingProfile(chrome::kInitialProfile);
   }
 
@@ -323,15 +323,18 @@
   }
 
   // Sets TPM public key pref in the test user's profile prefs.
-  void SetLocalStatePublicKey(const std::string& user_id,
-                              const std::string& value) {
+  static void SetLocalStatePublicKey(const AccountId& account_id,
+                                     const std::string& value) {
     std::string encoded;
     base::Base64Encode(value, &encoded);
     DictionaryPrefUpdate update(g_browser_process->local_state(),
                                 prefs::kEasyUnlockLocalStateTpmKeys);
-    update->SetStringWithoutPathExpansion(kTestUserId, encoded);
+    update->SetStringWithoutPathExpansion(account_id.GetUserEmail(), encoded);
   }
 
+ protected:
+  const AccountId test_account_id_ = AccountId::FromUserEmail(kTestUserId);
+
  private:
   content::TestBrowserThreadBundle thread_bundle_;
 
@@ -359,20 +362,20 @@
   ASSERT_TRUE(InitTestNssUser());
 
   base::RunLoop run_loop;
-  EXPECT_TRUE(user_key_manager()->GetPublicTpmKey(kTestUserId).empty());
-  EXPECT_TRUE(signin_key_manager()->GetPublicTpmKey(kTestUserId).empty());
+  EXPECT_TRUE(user_key_manager()->GetPublicTpmKey(test_account_id_).empty());
+  EXPECT_TRUE(signin_key_manager()->GetPublicTpmKey(test_account_id_).empty());
   ASSERT_FALSE(user_key_manager()->PrepareTpmKey(
       false /* check_private_key */,
       run_loop.QuitClosure()));
-  EXPECT_TRUE(user_key_manager()->GetPublicTpmKey(kTestUserId).empty());
+  EXPECT_TRUE(user_key_manager()->GetPublicTpmKey(test_account_id_).empty());
 
   ASSERT_TRUE(SetUpTestSystemSlot());
   VerifyKeyGenerationNotStartedAndFinalizeTestNssUser();
   run_loop.Run();
 
-  EXPECT_FALSE(user_key_manager()->GetPublicTpmKey(kTestUserId).empty());
-  EXPECT_EQ(user_key_manager()->GetPublicTpmKey(kTestUserId),
-            signin_key_manager()->GetPublicTpmKey(kTestUserId));
+  EXPECT_FALSE(user_key_manager()->GetPublicTpmKey(test_account_id_).empty());
+  EXPECT_EQ(user_key_manager()->GetPublicTpmKey(test_account_id_),
+            signin_key_manager()->GetPublicTpmKey(test_account_id_));
 
   EXPECT_TRUE(user_key_manager()->PrepareTpmKey(
       false /* check_private_key */,
@@ -405,9 +408,9 @@
   run_loop.Run();
 
   EXPECT_EQ(2, callback_count);
-  EXPECT_FALSE(user_key_manager()->GetPublicTpmKey(kTestUserId).empty());
-  EXPECT_EQ(user_key_manager()->GetPublicTpmKey(kTestUserId),
-            signin_key_manager()->GetPublicTpmKey(kTestUserId));
+  EXPECT_FALSE(user_key_manager()->GetPublicTpmKey(test_account_id_).empty());
+  EXPECT_EQ(user_key_manager()->GetPublicTpmKey(test_account_id_),
+            signin_key_manager()->GetPublicTpmKey(test_account_id_));
 
   EXPECT_TRUE(user_key_manager()->PrepareTpmKey(
       false /* check_private_key */,
@@ -416,24 +419,24 @@
 
 TEST_F(EasyUnlockTpmKeyManagerTest, PublicKeySetInPrefs) {
   SetLocalStatePublicKey(
-      kTestUserId, std::string(kTestPublicKey, arraysize(kTestPublicKey)));
+      test_account_id_, std::string(kTestPublicKey, arraysize(kTestPublicKey)));
 
   EXPECT_TRUE(user_key_manager()->PrepareTpmKey(
       false /* check_private_key */,
       base::Bind(&ExpectNotCalledCallback)));
 
-  EXPECT_FALSE(user_key_manager()->GetPublicTpmKey(kTestUserId).empty());
-  EXPECT_EQ(user_key_manager()->GetPublicTpmKey(kTestUserId),
+  EXPECT_FALSE(user_key_manager()->GetPublicTpmKey(test_account_id_).empty());
+  EXPECT_EQ(user_key_manager()->GetPublicTpmKey(test_account_id_),
             std::string(kTestPublicKey, arraysize(kTestPublicKey)));
-  EXPECT_EQ(user_key_manager()->GetPublicTpmKey(kTestUserId),
-            signin_key_manager()->GetPublicTpmKey(kTestUserId));
+  EXPECT_EQ(user_key_manager()->GetPublicTpmKey(test_account_id_),
+            signin_key_manager()->GetPublicTpmKey(test_account_id_));
 }
 
 TEST_F(EasyUnlockTpmKeyManagerTest, PublicKeySetInPrefsCheckPrivateKey) {
   ASSERT_TRUE(InitTestNssUser());
 
   SetLocalStatePublicKey(
-      kTestUserId, std::string(kTestPublicKey, arraysize(kTestPublicKey)));
+      test_account_id_, std::string(kTestPublicKey, arraysize(kTestPublicKey)));
 
   base::RunLoop run_loop;
   ASSERT_FALSE(user_key_manager()->PrepareTpmKey(
@@ -444,11 +447,11 @@
   VerifyKeyGenerationNotStartedAndFinalizeTestNssUser();
   run_loop.Run();
 
-  EXPECT_FALSE(user_key_manager()->GetPublicTpmKey(kTestUserId).empty());
-  EXPECT_NE(user_key_manager()->GetPublicTpmKey(kTestUserId),
+  EXPECT_FALSE(user_key_manager()->GetPublicTpmKey(test_account_id_).empty());
+  EXPECT_NE(user_key_manager()->GetPublicTpmKey(test_account_id_),
             std::string(kTestPublicKey, arraysize(kTestPublicKey)));
-  EXPECT_EQ(user_key_manager()->GetPublicTpmKey(kTestUserId),
-            signin_key_manager()->GetPublicTpmKey(kTestUserId));
+  EXPECT_EQ(user_key_manager()->GetPublicTpmKey(test_account_id_),
+            signin_key_manager()->GetPublicTpmKey(test_account_id_));
 }
 
 TEST_F(EasyUnlockTpmKeyManagerTest, PublicKeySetInPrefsCheckPrivateKey_OK) {
@@ -457,7 +460,7 @@
   VerifyKeyGenerationNotStartedAndFinalizeTestNssUser();
   ASSERT_TRUE(ImportPrivateKey(kTestPrivateKey,  arraysize(kTestPrivateKey)));
   SetLocalStatePublicKey(
-      kTestUserId, std::string(kTestPublicKey, arraysize(kTestPublicKey)));
+      test_account_id_, std::string(kTestPublicKey, arraysize(kTestPublicKey)));
 
   int callback_count = 0;
   base::RunLoop run_loop;
@@ -472,11 +475,11 @@
   run_loop.Run();
 
   EXPECT_EQ(1, callback_count);
-  EXPECT_FALSE(user_key_manager()->GetPublicTpmKey(kTestUserId).empty());
-  EXPECT_EQ(user_key_manager()->GetPublicTpmKey(kTestUserId),
+  EXPECT_FALSE(user_key_manager()->GetPublicTpmKey(test_account_id_).empty());
+  EXPECT_EQ(user_key_manager()->GetPublicTpmKey(test_account_id_),
             std::string(kTestPublicKey, arraysize(kTestPublicKey)));
-  EXPECT_EQ(user_key_manager()->GetPublicTpmKey(kTestUserId),
-            signin_key_manager()->GetPublicTpmKey(kTestUserId));
+  EXPECT_EQ(user_key_manager()->GetPublicTpmKey(test_account_id_),
+            signin_key_manager()->GetPublicTpmKey(test_account_id_));
 
   EXPECT_TRUE(user_key_manager()->PrepareTpmKey(
       true /* check_private_key */,
@@ -500,7 +503,7 @@
 
   run_loop.Run();
 
-  EXPECT_TRUE(user_key_manager()->GetPublicTpmKey(kTestUserId).empty());
+  EXPECT_TRUE(user_key_manager()->GetPublicTpmKey(test_account_id_).empty());
 }
 
 TEST_F(EasyUnlockTpmKeyManagerTest, GetSystemSlotTimeoutAfterSlotFetched) {
@@ -519,7 +522,7 @@
 
   run_loop.Run();
 
-  EXPECT_FALSE(user_key_manager()->GetPublicTpmKey(kTestUserId).empty());
+  EXPECT_FALSE(user_key_manager()->GetPublicTpmKey(test_account_id_).empty());
 }
 
 TEST_F(EasyUnlockTpmKeyManagerTest, GetSystemSlotRetryAfterFailure) {
@@ -535,7 +538,7 @@
 
   run_loop.Run();
 
-  EXPECT_TRUE(user_key_manager()->GetPublicTpmKey(kTestUserId).empty());
+  EXPECT_TRUE(user_key_manager()->GetPublicTpmKey(test_account_id_).empty());
 
   base::RunLoop run_loop_retry;
 
@@ -548,20 +551,19 @@
 
   run_loop_retry.Run();
 
-  EXPECT_FALSE(user_key_manager()->GetPublicTpmKey(kTestUserId).empty());
+  EXPECT_FALSE(user_key_manager()->GetPublicTpmKey(test_account_id_).empty());
 }
 
 TEST_F(EasyUnlockTpmKeyManagerTest, SignData) {
   ASSERT_TRUE(SetUpTestSystemSlot());
   ASSERT_TRUE(ImportPrivateKey(kTestPrivateKey,  arraysize(kTestPrivateKey)));
   SetLocalStatePublicKey(
-      kTestUserId, std::string(kTestPublicKey, arraysize(kTestPublicKey)));
+      test_account_id_, std::string(kTestPublicKey, arraysize(kTestPublicKey)));
 
   base::RunLoop loop;
   std::string signed_data;
   signin_key_manager()->SignUsingTpmKey(
-      kTestUserId,
-      "data",
+      test_account_id_, "data",
       base::Bind(&RecordStringAndRunClosure, &signed_data, loop.QuitClosure()));
   loop.Run();
 
@@ -572,8 +574,7 @@
   base::RunLoop loop;
   std::string signed_data;
   signin_key_manager()->SignUsingTpmKey(
-      kTestUserId,
-      "data",
+      test_account_id_, "data",
       base::Bind(&RecordStringAndRunClosure, &signed_data, loop.QuitClosure()));
   loop.Run();
 
@@ -582,13 +583,12 @@
 
 TEST_F(EasyUnlockTpmKeyManagerTest, SignDataNoPrivateKeyPresent) {
   SetLocalStatePublicKey(
-      kTestUserId, std::string(kTestPublicKey, arraysize(kTestPublicKey)));
+      test_account_id_, std::string(kTestPublicKey, arraysize(kTestPublicKey)));
 
   base::RunLoop loop;
   std::string signed_data;
   signin_key_manager()->SignUsingTpmKey(
-      kTestUserId,
-      "data",
+      test_account_id_, "data",
       base::Bind(&RecordStringAndRunClosure, &signed_data, loop.QuitClosure()));
 
   ASSERT_TRUE(SetUpTestSystemSlot());
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.cc
index 6dec53e..2ba28ad9 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.cc
@@ -7,9 +7,8 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/signin/easy_unlock_service.h"
 
-EasyUnlockUserLoginFlow::EasyUnlockUserLoginFlow(const std::string& user_id)
-    : chromeos::ExtendedUserFlow(user_id) {
-}
+EasyUnlockUserLoginFlow::EasyUnlockUserLoginFlow(const AccountId& account_id)
+    : chromeos::ExtendedUserFlow(account_id) {}
 
 EasyUnlockUserLoginFlow::~EasyUnlockUserLoginFlow() {}
 
@@ -31,8 +30,8 @@
   EasyUnlockService* service = EasyUnlockService::Get(profile);
   if (!service)
     return false;
-  service->HandleAuthFailure(user_id());
-  service->RecordEasySignInOutcome(user_id(), false);
+  service->HandleAuthFailure(account_id());
+  service->RecordEasySignInOutcome(account_id(), false);
   UnregisterFlowSoon();
   return true;
 }
@@ -43,7 +42,7 @@
   EasyUnlockService* service = EasyUnlockService::Get(profile);
   if (!service)
     return;
-  service->RecordEasySignInOutcome(user_id(), true);
+  service->RecordEasySignInOutcome(account_id(), true);
 }
 
 bool EasyUnlockUserLoginFlow::HandlePasswordChangeDetected() {
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.h b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.h
index 0f069bb..34b1919f 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.h
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.h
@@ -10,12 +10,14 @@
 #include "base/macros.h"
 #include "chrome/browser/chromeos/login/user_flow.h"
 
+class AccountId;
+
 // Handler for login flow initiazted by Easy Signin login attempt.
 // The only difference to the default login flow is hanlding of the auth
 // failure.
 class EasyUnlockUserLoginFlow : public chromeos::ExtendedUserFlow {
  public:
-  explicit EasyUnlockUserLoginFlow(const std::string& user_id);
+  explicit EasyUnlockUserLoginFlow(const AccountId& account_id);
   ~EasyUnlockUserLoginFlow() override;
 
  private:
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index 94c54bab..8655f71 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -125,8 +125,7 @@
   if (user_context.GetUserType() == user_manager::USER_TYPE_REGULAR &&
       user_context.GetAuthFlow() == UserContext::AUTH_FLOW_OFFLINE &&
       easy_unlock_service) {
-    easy_unlock_service->RecordPasswordLoginEvent(
-        user_context.GetAccountId().GetUserEmail());
+    easy_unlock_service->RecordPasswordLoginEvent(user_context.GetAccountId());
   }
 }
 
@@ -438,12 +437,13 @@
   NOTREACHED();
 }
 
-bool ExistingUserController::IsUserWhitelisted(const std::string& user_id) {
+bool ExistingUserController::IsUserWhitelisted(const AccountId& account_id) {
   bool wildcard_match = false;
   if (login_performer_.get())
-    return login_performer_->IsUserWhitelisted(user_id, &wildcard_match);
+    return login_performer_->IsUserWhitelisted(account_id, &wildcard_match);
 
-  return chromeos::CrosSettings::IsWhitelisted(user_id, &wildcard_match);
+  return chromeos::CrosSettings::IsWhitelisted(account_id.GetUserEmail(),
+                                               &wildcard_match);
 }
 
 void ExistingUserController::OnConsumerKioskAutoLaunchCheckCompleted(
diff --git a/chrome/browser/chromeos/login/existing_user_controller.h b/chrome/browser/chromeos/login/existing_user_controller.h
index d9c7a503..36ba07b 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.h
+++ b/chrome/browser/chromeos/login/existing_user_controller.h
@@ -92,7 +92,7 @@
   void SetDisplayEmail(const std::string& email) override;
   void ShowWrongHWIDScreen() override;
   void Signout() override;
-  bool IsUserWhitelisted(const std::string& user_id) override;
+  bool IsUserWhitelisted(const AccountId& account_id) override;
 
   // content::NotificationObserver implementation.
   void Observe(int type,
diff --git a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
index fec9718c..daafbd6a 100644
--- a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
@@ -321,8 +321,7 @@
   SupervisedUserCreationScreen supervised_user_creation_screen(
       &mock_base_screen_delegate, &supervised_user_creation_screen_handler);
 
-  supervised_user_creation_screen.AuthenticateManager(
-      account_id_.GetUserEmail(), kPassword);
+  supervised_user_creation_screen.AuthenticateManager(account_id_, kPassword);
 }
 
 MATCHER_P(HasDetails, expected, "") {
diff --git a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc b/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
index 00c7dded..fc3fdcaf 100644
--- a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
@@ -282,7 +282,7 @@
   chromeos::ScreenLocker::default_screen_locker()->Signout();
 }
 
-bool WebUIScreenLocker::IsUserWhitelisted(const std::string& user_id) {
+bool WebUIScreenLocker::IsUserWhitelisted(const AccountId& account_id) {
   NOTREACHED();
   return true;
 }
diff --git a/chrome/browser/chromeos/login/lock/webui_screen_locker.h b/chrome/browser/chromeos/login/lock/webui_screen_locker.h
index 670aea2..28e0f58 100644
--- a/chrome/browser/chromeos/login/lock/webui_screen_locker.h
+++ b/chrome/browser/chromeos/login/lock/webui_screen_locker.h
@@ -93,7 +93,7 @@
   void ResyncUserData() override;
   void SetDisplayEmail(const std::string& email) override;
   void Signout() override;
-  bool IsUserWhitelisted(const std::string& user_id) override;
+  bool IsUserWhitelisted(const AccountId& account_id) override;
 
   // LockWindow::Observer:
   void OnLockWindowReady() override;
diff --git a/chrome/browser/chromeos/login/screens/user_selection_screen.cc b/chrome/browser/chromeos/login/screens/user_selection_screen.cc
index c2df683..68609e6 100644
--- a/chrome/browser/chromeos/login/screens/user_selection_screen.cc
+++ b/chrome/browser/chromeos/login/screens/user_selection_screen.cc
@@ -429,29 +429,25 @@
   if (status == TokenHandleUtil::INVALID) {
     RecordReauthReason(account_id, ReauthReason::INVALID_TOKEN_HANDLE);
     token_handle_util_->MarkHandleInvalid(account_id);
-    SetAuthType(account_id.GetUserEmail(), ONLINE_SIGN_IN, base::string16());
+    SetAuthType(account_id, ONLINE_SIGN_IN, base::string16());
   }
 }
 
 // EasyUnlock stuff
 
-void UserSelectionScreen::SetAuthType(const std::string& user_id,
+void UserSelectionScreen::SetAuthType(const AccountId& account_id,
                                       AuthType auth_type,
                                       const base::string16& initial_value) {
-  const AccountId& account_id =
-      user_manager::UserManager::GetKnownUserAccountId(user_id, std::string());
-  if (GetAuthType(account_id.GetUserEmail()) == FORCE_OFFLINE_PASSWORD)
+  if (GetAuthType(account_id) == FORCE_OFFLINE_PASSWORD)
     return;
-  DCHECK(GetAuthType(account_id.GetUserEmail()) != FORCE_OFFLINE_PASSWORD ||
+  DCHECK(GetAuthType(account_id) != FORCE_OFFLINE_PASSWORD ||
          auth_type == FORCE_OFFLINE_PASSWORD);
   user_auth_type_map_[account_id] = auth_type;
   view_->SetAuthType(account_id, auth_type, initial_value);
 }
 
 proximity_auth::ScreenlockBridge::LockHandler::AuthType
-UserSelectionScreen::GetAuthType(const std::string& username) const {
-  const AccountId& account_id =
-      user_manager::UserManager::GetKnownUserAccountId(username, std::string());
+UserSelectionScreen::GetAuthType(const AccountId& account_id) const {
   if (user_auth_type_map_.find(account_id) == user_auth_type_map_.end())
     return OFFLINE_PASSWORD;
   return user_auth_type_map_.find(account_id)->second;
@@ -473,20 +469,16 @@
 }
 
 void UserSelectionScreen::ShowUserPodCustomIcon(
-    const std::string& user_id,
+    const AccountId& account_id,
     const proximity_auth::ScreenlockBridge::UserPodCustomIconOptions&
         icon_options) {
   scoped_ptr<base::DictionaryValue> icon = icon_options.ToDictionaryValue();
   if (!icon || icon->empty())
     return;
-  const AccountId account_id =
-      user_manager::UserManager::GetKnownUserAccountId(user_id, std::string());
   view_->ShowUserPodCustomIcon(account_id, *icon);
 }
 
-void UserSelectionScreen::HideUserPodCustomIcon(const std::string& user_id) {
-  const AccountId account_id =
-      user_manager::UserManager::GetKnownUserAccountId(user_id, std::string());
+void UserSelectionScreen::HideUserPodCustomIcon(const AccountId& account_id) {
   view_->HideUserPodCustomIcon(account_id);
 }
 
@@ -498,18 +490,17 @@
     ScreenLocker::default_screen_locker()->EnableInput();
 }
 
-void UserSelectionScreen::Unlock(const std::string& user_email) {
+void UserSelectionScreen::Unlock(const AccountId& account_id) {
   DCHECK_EQ(GetScreenType(), LOCK_SCREEN);
   ScreenLocker::Hide();
 }
 
-void UserSelectionScreen::AttemptEasySignin(const std::string& user_id,
+void UserSelectionScreen::AttemptEasySignin(const AccountId& account_id,
                                             const std::string& secret,
                                             const std::string& key_label) {
   DCHECK_EQ(GetScreenType(), SIGNIN_SCREEN);
 
-  UserContext user_context(
-      user_manager::UserManager::GetKnownUserAccountId(user_id, std::string()));
+  UserContext user_context(account_id);
   user_context.SetAuthFlow(UserContext::AUTH_FLOW_EASY_UNLOCK);
   user_context.SetKey(Key(secret));
   user_context.GetKey()->SetLabel(key_label);
@@ -529,7 +520,7 @@
   EasyUnlockService* service = GetEasyUnlockServiceForUser(account_id);
   if (!service)
     return;
-  service->AttemptAuth(account_id.GetUserEmail());
+  service->AttemptAuth(account_id);
 }
 
 void UserSelectionScreen::RecordClickOnLockIcon(const AccountId& account_id) {
diff --git a/chrome/browser/chromeos/login/screens/user_selection_screen.h b/chrome/browser/chromeos/login/screens/user_selection_screen.h
index 70faa8be..2ec86fb 100644
--- a/chrome/browser/chromeos/login/screens/user_selection_screen.h
+++ b/chrome/browser/chromeos/login/screens/user_selection_screen.h
@@ -64,20 +64,20 @@
   // proximity_auth::ScreenlockBridge::LockHandler implementation:
   void ShowBannerMessage(const base::string16& message) override;
   void ShowUserPodCustomIcon(
-      const std::string& user_email,
+      const AccountId& account_id,
       const proximity_auth::ScreenlockBridge::UserPodCustomIconOptions& icon)
       override;
-  void HideUserPodCustomIcon(const std::string& user_email) override;
+  void HideUserPodCustomIcon(const AccountId& account_id) override;
 
   void EnableInput() override;
-  void SetAuthType(const std::string& user_email,
+  void SetAuthType(const AccountId& account_id,
                    AuthType auth_type,
                    const base::string16& auth_value) override;
-  AuthType GetAuthType(const std::string& user_email) const override;
+  AuthType GetAuthType(const AccountId& account_id) const override;
   ScreenType GetScreenType() const override;
 
-  void Unlock(const std::string& user_email) override;
-  void AttemptEasySignin(const std::string& user_email,
+  void Unlock(const AccountId& account_id) override;
+  void AttemptEasySignin(const AccountId& account_id,
                          const std::string& secret,
                          const std::string& key_label) override;
 
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index 5958dc6..0df31bf 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -952,7 +952,7 @@
         user_manager::UserManager::Get()->GetActiveUser();
     std::string supervised_user_sync_id =
         ChromeUserManager::Get()->GetSupervisedUserManager()->GetUserSyncId(
-            active_user->email());
+            active_user->GetAccountId().GetUserEmail());
     profile->GetPrefs()->SetString(prefs::kSupervisedUserId,
                                    supervised_user_sync_id);
   } else if (user_manager::UserManager::Get()->
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_controller_new.cc b/chrome/browser/chromeos/login/supervised/supervised_user_creation_controller_new.cc
index 8b0f7d9d..8699e30e 100644
--- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_controller_new.cc
+++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_controller_new.cc
@@ -56,7 +56,7 @@
 
 SupervisedUserCreationControllerNew::SupervisedUserCreationControllerNew(
     SupervisedUserCreationControllerNew::StatusConsumer* consumer,
-    const std::string& manager_id)
+    const AccountId& manager_id)
     : SupervisedUserCreationController(consumer),
       stage_(STAGE_INITIAL),
       weak_factory_(this) {
@@ -163,7 +163,7 @@
 
   stage_ = TRANSACTION_STARTED;
 
-  manager->CreateUserRecord(creation_context_->manager_id,
+  manager->CreateUserRecord(creation_context_->manager_id.GetUserEmail(),
                             creation_context_->local_user_id,
                             creation_context_->sync_user_id,
                             creation_context_->display_name);
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_controller_new.h b/chrome/browser/chromeos/login/supervised/supervised_user_creation_controller_new.h
index 597fab0..b272102 100644
--- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_controller_new.h
+++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_controller_new.h
@@ -16,6 +16,7 @@
 #include "chrome/browser/chromeos/login/supervised/supervised_user_creation_controller.h"
 #include "chrome/browser/supervised_user/legacy/supervised_user_registration_utility.h"
 #include "chromeos/login/auth/extended_authenticator.h"
+#include "components/signin/core/account_id/account_id.h"
 
 class Profile;
 
@@ -41,7 +42,7 @@
   // |Consumer| is not owned by controller, and it is expected that it wouldn't
   // be deleted before SupervisedUserCreationControllerNew.
   SupervisedUserCreationControllerNew(StatusConsumer* consumer,
-                                      const std::string& manager_id);
+                                      const AccountId& manager_id);
   ~SupervisedUserCreationControllerNew() override;
 
   // Returns the current supervised user controller if it has been created.
@@ -119,7 +120,7 @@
     base::string16 display_name;
     int avatar_index;
 
-    std::string manager_id;
+    AccountId manager_id = EmptyAccountId();
 
     std::string local_user_id;  // Used to identify cryptohome.
     std::string sync_user_id;   // Used to identify user in manager's sync data.
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.cc b/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.cc
index c116b68..a94ea4f 100644
--- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.cc
+++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.cc
@@ -27,12 +27,12 @@
 } // namespace
 
 SupervisedUserCreationFlow::SupervisedUserCreationFlow(
-    const std::string& manager_id)
-        : ExtendedUserFlow(manager_id),
-        token_validated_(false),
-        logged_in_(false),
-        session_started_(false),
-        manager_profile_(NULL) {}
+    const AccountId& manager_id)
+    : ExtendedUserFlow(manager_id),
+      token_validated_(false),
+      logged_in_(false),
+      session_started_(false),
+      manager_profile_(NULL) {}
 
 SupervisedUserCreationFlow::~SupervisedUserCreationFlow() {
   LOG(ERROR) << "Destroyed " << this;
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.h b/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.h
index 678a5bb..0cda0855 100644
--- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.h
+++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.h
@@ -11,6 +11,7 @@
 #include "chrome/browser/chromeos/login/user_flow.h"
 #include "components/user_manager/user.h"
 
+class AccountId;
 class Profile;
 
 namespace chromeos {
@@ -18,7 +19,7 @@
 // UserFlow implementation for creating new supervised user.
 class SupervisedUserCreationFlow : public ExtendedUserFlow {
  public:
-  explicit SupervisedUserCreationFlow(const std::string& manager_id);
+  explicit SupervisedUserCreationFlow(const AccountId& manager_id);
   ~SupervisedUserCreationFlow() override;
 
   bool CanLockScreen() override;
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc b/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc
index 99ef7a4f..81b58223 100644
--- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc
+++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc
@@ -216,22 +216,21 @@
 }
 
 void SupervisedUserCreationScreen::AuthenticateManager(
-    const std::string& manager_id,
+    const AccountId& manager_id,
     const std::string& manager_password) {
   if (manager_signin_in_progress_)
     return;
   manager_signin_in_progress_ = true;
 
   UserFlow* flow = new SupervisedUserCreationFlow(manager_id);
-  ChromeUserManager::Get()->SetUserFlow(AccountId::FromUserEmail(manager_id),
-                                        flow);
+  ChromeUserManager::Get()->SetUserFlow(manager_id, flow);
 
   // Make sure no two controllers exist at the same time.
   controller_.reset();
 
   controller_.reset(new SupervisedUserCreationControllerNew(this, manager_id));
 
-  UserContext user_context(AccountId::FromUserEmail(manager_id));
+  UserContext user_context(manager_id);
   user_context.SetKey(Key(manager_password));
   ExistingUserController::current_controller()->Login(user_context,
                                                       SigninSpecifics());
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.h b/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.h
index d51a8ed..6c975d9 100644
--- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.h
+++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.h
@@ -88,7 +88,7 @@
   void ImportSupervisedUser(const std::string& user_id) override;
   void ImportSupervisedUserWithPassword(const std::string& user_id,
                                         const std::string& password) override;
-  void AuthenticateManager(const std::string& manager_id,
+  void AuthenticateManager(const AccountId& manager_id,
                            const std::string& manager_password) override;
   void AbortFlow() override;
   void FinishFlow() override;
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.cc b/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.cc
index d47863c..faac4cb 100644
--- a/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.cc
+++ b/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.cc
@@ -28,12 +28,8 @@
 
 namespace chromeos {
 
-SupervisedUserLoginFlow::SupervisedUserLoginFlow(
-    const std::string& user_id)
-    : ExtendedUserFlow(user_id),
-      data_loaded_(false),
-      weak_factory_(this) {
-}
+SupervisedUserLoginFlow::SupervisedUserLoginFlow(const AccountId& account_id)
+    : ExtendedUserFlow(account_id), weak_factory_(this) {}
 
 SupervisedUserLoginFlow::~SupervisedUserLoginFlow() {}
 
@@ -86,9 +82,9 @@
   SupervisedUserAuthentication* auth =
       ChromeUserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
 
-  if (auth->HasScheduledPasswordUpdate(user_id())) {
+  if (auth->HasScheduledPasswordUpdate(account_id().GetUserEmail())) {
     auth->LoadPasswordUpdateData(
-        user_id(),
+        account_id().GetUserEmail(),
         base::Bind(&SupervisedUserLoginFlow::OnPasswordChangeDataLoaded,
                    weak_factory_.GetWeakPtr()),
         base::Bind(&SupervisedUserLoginFlow::OnPasswordChangeDataLoadFailed,
@@ -108,9 +104,9 @@
   // Edge case, when manager has signed in and already updated the password.
   SupervisedUserAuthentication* auth =
       ChromeUserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
-  if (!auth->NeedPasswordChange(user_id(), password_data)) {
-    VLOG(1) << "Password already changed for " << user_id();
-    auth->ClearScheduledPasswordUpdate(user_id());
+  if (!auth->NeedPasswordChange(account_id().GetUserEmail(), password_data)) {
+    VLOG(1) << "Password already changed for " << account_id().Serialize();
+    auth->ClearScheduledPasswordUpdate(account_id().GetUserEmail());
     Finish();
     return;
   }
@@ -148,7 +144,7 @@
 
   authenticator_ = ExtendedAuthenticator::Create(this);
   SupervisedUserAuthentication::Schema current_schema =
-      auth->GetPasswordSchema(user_id());
+      auth->GetPasswordSchema(account_id().GetUserEmail());
 
   key.revision = revision;
 
@@ -169,7 +165,7 @@
              current_schema) {
     VLOG(1) << "Updating the key";
 
-    if (auth->HasIncompleteKey(user_id())) {
+    if (auth->HasIncompleteKey(account_id().GetUserEmail())) {
       // We need to use Migrate instead of Authorized Update privilege.
       key.privileges = kCryptohomeSupervisedUserIncompleteKeyPrivileges;
     }
@@ -192,8 +188,8 @@
   VLOG(1) << "New key added";
   SupervisedUserAuthentication* auth =
       ChromeUserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
-  auth->StorePasswordData(user_id(), *password_data.get());
-  auth->MarkKeyIncomplete(user_id(), true /* incomplete */);
+  auth->StorePasswordData(account_id().GetUserEmail(), *password_data.get());
+  auth->MarkKeyIncomplete(account_id().GetUserEmail(), true /* incomplete */);
   authenticator_->RemoveKey(
       context_,
       kLegacyCryptohomeSupervisedUserKeyLabel,
@@ -239,10 +235,11 @@
       ChromeUserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
 
   // Incomplete state is not there in password_data, carry it from old state.
-  bool was_incomplete = auth->HasIncompleteKey(user_id());
-  auth->StorePasswordData(user_id(), *password_data.get());
+  const bool was_incomplete =
+      auth->HasIncompleteKey(account_id().GetUserEmail());
+  auth->StorePasswordData(account_id().GetUserEmail(), *password_data.get());
   if (was_incomplete)
-    auth->MarkKeyIncomplete(user_id(), true /* incomplete */);
+    auth->MarkKeyIncomplete(account_id().GetUserEmail(), true /* incomplete */);
 
   UMA_HISTOGRAM_ENUMERATION(
       "ManagedUsers.ChromeOS.PasswordChange",
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.h b/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.h
index 6bd1b2b8..f2eb558 100644
--- a/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.h
+++ b/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.h
@@ -20,7 +20,7 @@
     : public ExtendedUserFlow,
       public ExtendedAuthenticator::NewAuthStatusConsumer {
  public:
-  explicit SupervisedUserLoginFlow(const std::string& user_id);
+  explicit SupervisedUserLoginFlow(const AccountId& account_id);
   ~SupervisedUserLoginFlow() override;
 
   // ExtendedUserFlow overrides.
@@ -51,9 +51,9 @@
 
   scoped_refptr<ExtendedAuthenticator> authenticator_;
 
-  bool data_loaded_;
+  bool data_loaded_ = false;
   UserContext context_;
-  Profile* profile_;
+  Profile* profile_ = nullptr;
   base::WeakPtrFactory<SupervisedUserLoginFlow> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(SupervisedUserLoginFlow);
diff --git a/chrome/browser/chromeos/login/ui/login_display.h b/chrome/browser/chromeos/login/ui/login_display.h
index 8824c46..11fdb4f 100644
--- a/chrome/browser/chromeos/login/ui/login_display.h
+++ b/chrome/browser/chromeos/login/ui/login_display.h
@@ -91,7 +91,7 @@
     virtual void ResetPublicSessionAutoLoginTimer() = 0;
 
     // Returns true if user is allowed to log in by domain policy.
-    virtual bool IsUserWhitelisted(const std::string& user_id) = 0;
+    virtual bool IsUserWhitelisted(const AccountId& account_id) = 0;
 
    protected:
     virtual ~Delegate();
diff --git a/chrome/browser/chromeos/login/ui/models/user_board_model.h b/chrome/browser/chromeos/login/ui/models/user_board_model.h
index c69fb30..5a568e0 100644
--- a/chrome/browser/chromeos/login/ui/models/user_board_model.h
+++ b/chrome/browser/chromeos/login/ui/models/user_board_model.h
@@ -7,6 +7,8 @@
 
 #include "chrome/browser/chromeos/login/screens/base_screen.h"
 
+class AccountId;
+
 namespace chromeos {
 
 class UserBoardModel : public BaseScreen {
diff --git a/chrome/browser/chromeos/login/ui/webui_login_display.cc b/chrome/browser/chromeos/login/ui/webui_login_display.cc
index f6fab4e4..782ad0f 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_display.cc
+++ b/chrome/browser/chromeos/login/ui/webui_login_display.cc
@@ -42,11 +42,7 @@
 // LoginDisplay implementation: ------------------------------------------------
 
 WebUILoginDisplay::WebUILoginDisplay(LoginDisplay::Delegate* delegate)
-    : LoginDisplay(delegate, gfx::Rect()),
-      show_guest_(false),
-      show_new_user_(false),
-      webui_handler_(NULL) {
-}
+    : LoginDisplay(delegate, gfx::Rect()) {}
 
 void WebUILoginDisplay::ClearAndEnablePassword() {
   if (webui_handler_)
@@ -325,10 +321,10 @@
     delegate_->ResetPublicSessionAutoLoginTimer();
 }
 
-bool WebUILoginDisplay::IsUserWhitelisted(const std::string& user_id) {
+bool WebUILoginDisplay::IsUserWhitelisted(const AccountId& account_id) {
   DCHECK(delegate_);
   if (delegate_)
-    return delegate_->IsUserWhitelisted(user_id);
+    return delegate_->IsUserWhitelisted(account_id);
   return true;
 }
 
diff --git a/chrome/browser/chromeos/login/ui/webui_login_display.h b/chrome/browser/chromeos/login/ui/webui_login_display.h
index a06ac1c..de4fb84 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_display.h
+++ b/chrome/browser/chromeos/login/ui/webui_login_display.h
@@ -81,7 +81,7 @@
 
   void HandleGetUsers() override;
   void CheckUserStatus(const AccountId& account_id) override;
-  bool IsUserWhitelisted(const std::string& user_id) override;
+  bool IsUserWhitelisted(const AccountId& account_id) override;
 
   // ui::UserActivityDetector implementation:
   void OnUserActivity(const ui::Event* event) override;
@@ -89,17 +89,17 @@
  private:
 
   // Whether to show guest login.
-  bool show_guest_;
+  bool show_guest_ = false;
 
   // Weather to show the user pods or a GAIA sign in.
   // Public sessions are always shown.
-  bool show_users_;
+  bool show_users_ = false;
 
   // Whether to show add new user.
-  bool show_new_user_;
+  bool show_new_user_ = false;
 
   // Reference to the WebUI handling layer for the login screen
-  LoginDisplayWebUIHandler* webui_handler_;
+  LoginDisplayWebUIHandler* webui_handler_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(WebUILoginDisplay);
 };
diff --git a/chrome/browser/chromeos/login/user_flow.cc b/chrome/browser/chromeos/login/user_flow.cc
index 74e37c3..5df5639 100644
--- a/chrome/browser/chromeos/login/user_flow.cc
+++ b/chrome/browser/chromeos/login/user_flow.cc
@@ -10,15 +10,6 @@
 
 namespace chromeos {
 
-namespace {
-
-void UnregisterFlow(const std::string& user_id) {
-  ChromeUserManager::Get()->ResetUserFlow(AccountId::FromUserEmail(user_id));
-}
-
-} // namespace
-
-
 UserFlow::UserFlow() : host_(NULL) {}
 
 UserFlow::~UserFlow() {}
@@ -70,9 +61,8 @@
 void DefaultUserFlow::LaunchExtraSteps(Profile* profile) {
 }
 
-ExtendedUserFlow::ExtendedUserFlow(const std::string& user_id)
-    : user_id_(user_id) {
-}
+ExtendedUserFlow::ExtendedUserFlow(const AccountId& account_id)
+    : account_id_(account_id) {}
 
 ExtendedUserFlow::~ExtendedUserFlow() {
 }
@@ -89,10 +79,10 @@
 }
 
 void ExtendedUserFlow::UnregisterFlowSoon() {
-  std::string id_copy(user_id());
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-      base::Bind(&UnregisterFlow,
-                 id_copy));
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&ChromeUserManager::ResetUserFlow,
+                 base::Unretained(ChromeUserManager::Get()), account_id()));
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_flow.h b/chrome/browser/chromeos/login/user_flow.h
index aa5d2558..d90d3cc 100644
--- a/chrome/browser/chromeos/login/user_flow.h
+++ b/chrome/browser/chromeos/login/user_flow.h
@@ -8,6 +8,7 @@
 #include "base/compiler_specific.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chromeos/login/auth/auth_status_consumer.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "components/user_manager/user.h"
 
 namespace chromeos {
@@ -69,7 +70,7 @@
 // UserFlow stub for non-regular flows.
 class ExtendedUserFlow : public UserFlow {
  public:
-  explicit ExtendedUserFlow(const std::string& user_id);
+  explicit ExtendedUserFlow(const AccountId& account_id);
   ~ExtendedUserFlow() override;
 
   void AppendAdditionalCommandLineSwitches() override;
@@ -80,12 +81,10 @@
  protected:
   // Subclasses can call this method to unregister flow in the next event.
   virtual void UnregisterFlowSoon();
-  std::string user_id() {
-    return user_id_;
-  }
+  const AccountId& account_id() { return account_id_; }
 
  private:
-  std::string user_id_;
+  const AccountId account_id_;
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
index 426a0530..4b79a97 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -744,7 +744,7 @@
 
 bool ChromeUserManagerImpl::HasPendingBootstrap(
     const AccountId& account_id) const {
-  return bootstrap_manager_->HasPendingBootstrap(account_id.GetUserEmail());
+  return bootstrap_manager_->HasPendingBootstrap(account_id);
 }
 
 void ChromeUserManagerImpl::PublicAccountUserLoggedIn(
@@ -870,7 +870,7 @@
 
   multi_profile_user_controller_->RemoveCachedValues(account_id.GetUserEmail());
 
-  EasyUnlockService::ResetLocalStateForUser(account_id.GetUserEmail());
+  EasyUnlockService::ResetLocalStateForUser(account_id);
 }
 
 void
@@ -1100,8 +1100,7 @@
 }
 
 void ChromeUserManagerImpl::RemovePendingBootstrapUser(
-    const std::string& user_id) {
-  const AccountId account_id(AccountId::FromUserEmail(user_id));
+    const AccountId& account_id) {
   DCHECK(HasPendingBootstrap(account_id));
   RemoveNonOwnerUserInternal(account_id, nullptr);
 }
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
index 206fd43..8a96e78 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
@@ -206,7 +206,7 @@
   void OnUserNotAllowed(const std::string& user_email) override;
 
   // BootstrapManager::Delegate implementation:
-  void RemovePendingBootstrapUser(const std::string& user_id) override;
+  void RemovePendingBootstrapUser(const AccountId& account_id) override;
 
   // Update the number of users.
   void UpdateNumberOfUsers();
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
index f1d2f1c97..35d00176 100644
--- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -834,7 +834,6 @@
   void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
                                   const extensions::Extension* extension,
                                   bool is_update,
-                                  bool from_ephemeral,
                                   const std::string& old_name) override {
     if (waiting_extension_id_ == extension->id()) {
       observed_ = true;
diff --git a/chrome/browser/chromeos/policy/display_rotation_default_handler_browsertest.cc b/chrome/browser/chromeos/policy/display_rotation_default_handler_browsertest.cc
index 1686ff3..65f51b69 100644
--- a/chrome/browser/chromeos/policy/display_rotation_default_handler_browsertest.cc
+++ b/chrome/browser/chromeos/policy/display_rotation_default_handler_browsertest.cc
@@ -2,26 +2,68 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/policy/display_rotation_default_handler.h"
+#include <stdint.h>
 
 #include "ash/display/display_manager.h"
 #include "ash/shell.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/location.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
+#include "chrome/browser/chromeos/policy/display_rotation_default_handler.h"
 #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/chromeos_switches.h"
+#include "chromeos/dbus/cryptohome_client.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_cryptohome_client.h"
+#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager_client.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "content/public/test/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/display.h"
 
 namespace em = enterprise_management;
 
+namespace {
+
+ash::DisplayManager* GetDisplayManager() {
+  return ash::Shell::GetInstance()->display_manager();
+}
+
+gfx::Display::Rotation GetRotationOfFirstDisplay() {
+  const ash::DisplayManager* const display_manager = GetDisplayManager();
+  const int64_t first_display_id = display_manager->first_display_id();
+  const gfx::Display& first_display =
+      display_manager->GetDisplayForId(first_display_id);
+  return first_display.rotation();
+}
+
+// Fails the test and returns ROTATE_0 if there is no second display.
+gfx::Display::Rotation GetRotationOfSecondDisplay() {
+  const ash::DisplayManager* const display_manager = GetDisplayManager();
+  if (display_manager->GetNumDisplays() < 2) {
+    ADD_FAILURE()
+        << "Requested rotation of second display while there was only one.";
+    return gfx::Display::ROTATE_0;
+  }
+  const ash::DisplayIdPair display_id_pair =
+      display_manager->GetCurrentDisplayIdPair();
+  const gfx::Display& second_display =
+      display_manager->GetDisplayForId(display_id_pair.second);
+  return second_display.rotation();
+}
+
+} // anonymous namespace
+
 namespace policy {
 
 class DisplayRotationDefaultTest
@@ -73,33 +115,6 @@
     RefreshPolicyAndWaitUntilDeviceSettingsUpdated();
   }
 
-  ash::DisplayManager* GetDisplayManager() const {
-    return ash::Shell::GetInstance()->display_manager();
-  }
-
-  gfx::Display::Rotation GetRotationOfFirstDisplay() const {
-    const ash::DisplayManager* const display_manager = GetDisplayManager();
-    const int64_t first_display_id = display_manager->first_display_id();
-    const gfx::Display& first_display =
-        display_manager->GetDisplayForId(first_display_id);
-    return first_display.rotation();
-  }
-
-  // Fails the test and returns ROTATE_0 if there is no second display.
-  gfx::Display::Rotation GetRotationOfSecondDisplay() const {
-    const ash::DisplayManager* const display_manager = GetDisplayManager();
-    if (display_manager->GetNumDisplays() < 2) {
-      ADD_FAILURE()
-          << "Requested rotation of second display while there was only one.";
-      return gfx::Display::ROTATE_0;
-    }
-    const ash::DisplayIdPair display_id_pair =
-        display_manager->GetCurrentDisplayIdPair();
-    const gfx::Display& second_display =
-        display_manager->GetDisplayForId(display_id_pair.second);
-    return second_display.rotation();
-  }
-
   // Creates second display if there is none yet, or removes it if there is one.
   void ToggleSecondDisplay() {
     GetDisplayManager()->AddRemoveDisplay();
@@ -231,4 +246,84 @@
                                         gfx::Display::ROTATE_90,
                                         gfx::Display::ROTATE_180,
                                         gfx::Display::ROTATE_270));
+
+// This class tests that the policy is reapplied after a reboot. To persist from
+// PRE_Reboot to Reboot, the policy is inserted into a FakeSessionManagerClient.
+// From there, it travels to DeviceSettingsProvider, whose UpdateFromService()
+// method caches the policy (using device_settings_cache::Store()).
+// In the main test, the FakeSessionManagerClient is not fully initialized.
+// Thus, DeviceSettingsProvider falls back on the cached values (using
+// device_settings_cache::Retrieve()).
+class DisplayRotationBootTest
+    : public InProcessBrowserTest,
+      public testing::WithParamInterface<gfx::Display::Rotation> {
+ protected:
+  DisplayRotationBootTest()
+      : fake_session_manager_client_(new chromeos::FakeSessionManagerClient) {}
+  ~DisplayRotationBootTest() override {}
+
+  void SetUpInProcessBrowserTestFixture() override {
+    chromeos::DBusThreadManager::GetSetterForTesting()->SetSessionManagerClient(
+        scoped_ptr<chromeos::SessionManagerClient>(
+            fake_session_manager_client_));
+    chromeos::DBusThreadManager::GetSetterForTesting()->SetCryptohomeClient(
+        scoped_ptr<chromeos::CryptohomeClient>(
+            new chromeos::FakeCryptohomeClient));
+
+    test_helper_.InstallOwnerKey();
+    test_helper_.MarkAsEnterpriseOwned();
+  }
+
+  chromeos::FakeSessionManagerClient* fake_session_manager_client_;
+  policy::DevicePolicyCrosTestHelper test_helper_;
+};
+
+IN_PROC_BROWSER_TEST_P(DisplayRotationBootTest, PRE_Reboot) {
+  const gfx::Display::Rotation policy_rotation = GetParam();
+  const gfx::Display::Rotation user_rotation = gfx::Display::ROTATE_180;
+
+  // Set policy.
+  policy::DevicePolicyBuilder* const device_policy(
+      test_helper_.device_policy());
+  em::ChromeDeviceSettingsProto& proto(device_policy->payload());
+  proto.mutable_display_rotation_default()->set_display_rotation_default(
+      static_cast<em::DisplayRotationDefaultProto::Rotation>(policy_rotation));
+  base::RunLoop run_loop;
+  scoped_ptr<chromeos::CrosSettings::ObserverSubscription> observer =
+      chromeos::CrosSettings::Get()->AddSettingsObserver(
+          chromeos::kDisplayRotationDefault, run_loop.QuitClosure());
+  device_policy->SetDefaultSigningKey();
+  device_policy->Build();
+  fake_session_manager_client_->set_device_policy(device_policy->GetBlob());
+  fake_session_manager_client_->OnPropertyChangeComplete(true);
+  run_loop.Run();
+
+  // Check the display's rotation.
+  ash::DisplayManager* const display_manager = GetDisplayManager();
+  const int64_t first_display_id = display_manager->first_display_id();
+  const gfx::Display& first_display =
+      display_manager->GetDisplayForId(first_display_id);
+  EXPECT_EQ(policy_rotation, first_display.rotation());
+
+  // Let the user rotate the display to a different orientation, to check that
+  // the policy value is restored after reboot.
+  display_manager->SetDisplayRotation(first_display_id, user_rotation,
+                                      gfx::Display::ROTATION_SOURCE_USER);
+  EXPECT_EQ(user_rotation, first_display.rotation());
+}
+
+IN_PROC_BROWSER_TEST_P(DisplayRotationBootTest, Reboot) {
+  const gfx::Display::Rotation policy_rotation = GetParam();
+
+  // Check that the policy rotation is restored.
+  EXPECT_EQ(policy_rotation, GetRotationOfFirstDisplay());
+}
+
+INSTANTIATE_TEST_CASE_P(PolicyDisplayRotationDefault,
+                        DisplayRotationBootTest,
+                        testing::Values(gfx::Display::ROTATE_0,
+                                        gfx::Display::ROTATE_90,
+                                        gfx::Display::ROTATE_180,
+                                        gfx::Display::ROTATE_270));
+
 }  // namespace policy
diff --git a/chrome/browser/chromeos/power/extension_event_observer_unittest.cc b/chrome/browser/chromeos/power/extension_event_observer_unittest.cc
index 06fff499..5858c5d 100644
--- a/chrome/browser/chromeos/power/extension_event_observer_unittest.cc
+++ b/chrome/browser/chromeos/power/extension_event_observer_unittest.cc
@@ -89,18 +89,20 @@
     scoped_refptr<extensions::Extension> app =
         extensions::ExtensionBuilder()
             .SetManifest(
-                 extensions::DictionaryBuilder()
-                     .Set("name", name)
-                     .Set("version", "1.0.0")
-                     .Set("manifest_version", 2)
-                     .Set("app",
-                          extensions::DictionaryBuilder().Set(
-                              "background",
-                              extensions::DictionaryBuilder().Set(
-                                  "scripts", extensions::ListBuilder().Append(
-                                                 "background.js"))))
-                     .Set("permissions", extensions::ListBuilder().Append(
-                                             uses_gcm ? "gcm" : "")))
+                extensions::DictionaryBuilder()
+                    .Set("name", name)
+                    .Set("version", "1.0.0")
+                    .Set("manifest_version", 2)
+                    .Set("app",
+                         extensions::DictionaryBuilder().Set(
+                             "background",
+                             extensions::DictionaryBuilder().Set(
+                                 "scripts",
+                                 std::move(extensions::ListBuilder().Append(
+                                     "background.js")))))
+                    .Set("permissions",
+                         std::move(extensions::ListBuilder().Append(
+                             uses_gcm ? "gcm" : ""))))
             .Build();
 
     created_apps_.push_back(app);
diff --git a/chrome/browser/chromeos/power/renderer_freezer_unittest.cc b/chrome/browser/chromeos/power/renderer_freezer_unittest.cc
index 953f8af..0d937c1 100644
--- a/chrome/browser/chromeos/power/renderer_freezer_unittest.cc
+++ b/chrome/browser/chromeos/power/renderer_freezer_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/power/renderer_freezer.h"
 
 #include <string>
+#include <utility>
 
 #include "base/command_line.h"
 #include "base/memory/ref_counted.h"
@@ -310,20 +311,20 @@
   // First build the GCM extension.
   scoped_refptr<extensions::Extension> gcm_app =
       extensions::ExtensionBuilder()
-          .SetManifest(extensions::DictionaryBuilder()
-                       .Set("name", "GCM App")
-                       .Set("version", "1.0.0")
-                       .Set("manifest_version", 2)
-                       .Set("app",
-                            extensions::DictionaryBuilder()
-                            .Set("background",
-                                 extensions::DictionaryBuilder()
-                                 .Set("scripts",
-                                      extensions::ListBuilder()
-                                      .Append("background.js"))))
-                       .Set("permissions",
-                            extensions::ListBuilder()
-                            .Append("gcm")))
+          .SetManifest(
+              extensions::DictionaryBuilder()
+                  .Set("name", "GCM App")
+                  .Set("version", "1.0.0")
+                  .Set("manifest_version", 2)
+                  .Set("app",
+                       extensions::DictionaryBuilder().Set(
+                           "background",
+                           extensions::DictionaryBuilder().Set(
+                               "scripts",
+                               std::move(extensions::ListBuilder().Append(
+                                   "background.js")))))
+                  .Set("permissions",
+                       std::move(extensions::ListBuilder().Append("gcm"))))
           .Build();
 
   // Now install it and give it a renderer.
@@ -343,17 +344,18 @@
   // First build the extension.
   scoped_refptr<extensions::Extension> background_app =
       extensions::ExtensionBuilder()
-          .SetManifest(extensions::DictionaryBuilder()
-                       .Set("name", "Background App")
-                       .Set("version", "1.0.0")
-                       .Set("manifest_version", 2)
-                       .Set("app",
-                            extensions::DictionaryBuilder()
-                            .Set("background",
-                                 extensions::DictionaryBuilder()
-                                 .Set("scripts",
-                                      extensions::ListBuilder()
-                                      .Append("background.js")))))
+          .SetManifest(
+              extensions::DictionaryBuilder()
+                  .Set("name", "Background App")
+                  .Set("version", "1.0.0")
+                  .Set("manifest_version", 2)
+                  .Set("app",
+                       extensions::DictionaryBuilder().Set(
+                           "background",
+                           extensions::DictionaryBuilder().Set(
+                               "scripts",
+                               std::move(extensions::ListBuilder().Append(
+                                   "background.js"))))))
           .Build();
 
   // Now install it and give it a renderer.
diff --git a/chrome/browser/chromeos/printer_detector/printer_detector_unittest.cc b/chrome/browser/chromeos/printer_detector/printer_detector_unittest.cc
index 2aa8e424..792ad86 100644
--- a/chrome/browser/chromeos/printer_detector/printer_detector_unittest.cc
+++ b/chrome/browser/chromeos/printer_detector/printer_detector_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/chromeos/printer_detector/printer_detector.h"
 
+#include <utility>
+
 #include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
@@ -127,22 +129,23 @@
 
   // Creates a test extension with the provided permissions.
   scoped_refptr<extensions::Extension> CreateTestExtension(
-      ListBuilder& permissions_builder,
+      ListBuilder permissions_builder,
       DictionaryBuilder& usb_printers_builder) {
     return extensions::ExtensionBuilder()
         .SetID("fake_extension_id")
         .SetManifest(
-             DictionaryBuilder()
-                 .Set("name", "Printer provider extension")
-                 .Set("manifest_version", 2)
-                 .Set("version", "1.0")
-                 // Needed to enable usb API.
-                 .Set("app", DictionaryBuilder().Set(
-                                 "background",
-                                 DictionaryBuilder().Set(
-                                     "scripts", ListBuilder().Append("bg.js"))))
-                 .Set("permissions", permissions_builder)
-                 .Set("usb_printers", usb_printers_builder))
+            DictionaryBuilder()
+                .Set("name", "Printer provider extension")
+                .Set("manifest_version", 2)
+                .Set("version", "1.0")
+                // Needed to enable usb API.
+                .Set("app", DictionaryBuilder().Set(
+                                "background",
+                                DictionaryBuilder().Set(
+                                    "scripts",
+                                    std::move(ListBuilder().Append("bg.js")))))
+                .Set("permissions", std::move(permissions_builder))
+                .Set("usb_printers", usb_printers_builder))
         .Build();
   }
 
@@ -171,15 +174,15 @@
 
 TEST_F(PrinterDetectorAppSearchEnabledTest, ShowAppFoundNotification) {
   scoped_refptr<extensions::Extension> extension = CreateTestExtension(
-      ListBuilder()
-          .Append("usb")
-          .Append("printerProvider")
-          .Append(DictionaryBuilder().Set(
-              "usbDevices", ListBuilder().Append(DictionaryBuilder()
-                                                     .Set("vendorId", 123)
-                                                     .Set("productId", 456))))
-          .Pass(),
-      DictionaryBuilder().Set("filters", ListBuilder().Pass()).Pass());
+      std::move(ListBuilder()
+                    .Append("usb")
+                    .Append("printerProvider")
+                    .Append(DictionaryBuilder().Set(
+                        "usbDevices", std::move(ListBuilder().Append(
+                                          DictionaryBuilder()
+                                              .Set("vendorId", 123)
+                                              .Set("productId", 456)))))),
+      DictionaryBuilder().Set("filters", ListBuilder()).Pass());
   ASSERT_TRUE(extensions::ExtensionRegistry::Get(profile_.get())
                   ->AddEnabled(extension));
 
@@ -197,14 +200,12 @@
 TEST_F(PrinterDetectorAppSearchEnabledTest,
        UsbHandlerExists_NotPrinterProvider) {
   scoped_refptr<extensions::Extension> extension = CreateTestExtension(
-      ListBuilder()
-          .Append("usb")
-          .Append(DictionaryBuilder().Set(
-              "usbDevices", ListBuilder().Append(DictionaryBuilder()
-                                                     .Set("vendorId", 123)
-                                                     .Set("productId", 756))))
-          .Pass(),
-      DictionaryBuilder().Set("filters", ListBuilder().Pass()).Pass());
+      std::move(ListBuilder().Append("usb").Append(DictionaryBuilder().Set(
+          "usbDevices",
+          std::move(ListBuilder().Append(DictionaryBuilder()
+                                             .Set("vendorId", 123)
+                                             .Set("productId", 756)))))),
+      DictionaryBuilder().Set("filters", ListBuilder()).Pass());
   ASSERT_TRUE(extensions::ExtensionRegistry::Get(profile_.get())
                   ->AddEnabled(extension));
 
@@ -222,15 +223,15 @@
 TEST_F(PrinterDetectorAppSearchEnabledTest,
        PrinterProvider_DifferentUsbProductId) {
   scoped_refptr<extensions::Extension> extension = CreateTestExtension(
-      ListBuilder()
-          .Append("usb")
-          .Append("printerProvider")
-          .Append(DictionaryBuilder().Set(
-              "usbDevices", ListBuilder().Append(DictionaryBuilder()
-                                                     .Set("vendorId", 123)
-                                                     .Set("productId", 001))))
-          .Pass(),
-      DictionaryBuilder().Set("filters", ListBuilder().Pass()).Pass());
+      std::move(ListBuilder()
+                    .Append("usb")
+                    .Append("printerProvider")
+                    .Append(DictionaryBuilder().Set(
+                        "usbDevices", std::move(ListBuilder().Append(
+                                          DictionaryBuilder()
+                                              .Set("vendorId", 123)
+                                              .Set("productId", 001)))))),
+      DictionaryBuilder().Set("filters", ListBuilder()).Pass());
   ASSERT_TRUE(extensions::ExtensionRegistry::Get(profile_.get())
                   ->AddEnabled(extension));
 
@@ -248,11 +249,11 @@
 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))));
+      std::move(ListBuilder().Append("usb").Append("printerProvider")),
+      DictionaryBuilder().Set("filters", std::move(ListBuilder().Append(
+                                             DictionaryBuilder()
+                                                 .Set("vendorId", 123)
+                                                 .Set("productId", 001)))));
   ASSERT_TRUE(extensions::ExtensionRegistry::Get(profile_.get())
                   ->AddEnabled(extension));
 
@@ -270,11 +271,11 @@
 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))));
+      std::move(ListBuilder().Append("usb").Append("printerProvider")),
+      DictionaryBuilder().Set("filters", std::move(ListBuilder().Append(
+                                             DictionaryBuilder()
+                                                 .Set("vendorId", 123)
+                                                 .Set("productId", 456)))));
   ASSERT_TRUE(extensions::ExtensionRegistry::Get(profile_.get())
                   ->AddEnabled(extension));
 
@@ -292,12 +293,12 @@
 TEST_F(PrinterDetectorAppSearchEnabledTest,
        PrinterProvider_UsbPrinters_WithInterfaceClass) {
   scoped_refptr<extensions::Extension> extension = CreateTestExtension(
-      ListBuilder().Append("usb").Append("printerProvider").Pass(),
+      std::move(ListBuilder().Append("usb").Append("printerProvider")),
       DictionaryBuilder().Set(
-          "filters", ListBuilder().Append(
+          "filters", std::move(ListBuilder().Append(
                          DictionaryBuilder()
                              .Set("vendorId", 123)
-                             .Set("interfaceClass", kPrinterInterfaceClass))));
+                             .Set("interfaceClass", kPrinterInterfaceClass)))));
   ASSERT_TRUE(extensions::ExtensionRegistry::Get(profile_.get())
                   ->AddEnabled(extension));
 
@@ -314,12 +315,12 @@
 
 TEST_F(PrinterDetectorAppSearchEnabledTest, IgnoreNonPrinters) {
   scoped_refptr<extensions::Extension> extension = CreateTestExtension(
-      ListBuilder().Append("usb").Append("printerProvider").Pass(),
+      std::move(ListBuilder().Append("usb").Append("printerProvider")),
       DictionaryBuilder().Set(
-          "filters", ListBuilder().Append(
+          "filters", std::move(ListBuilder().Append(
                          DictionaryBuilder()
                              .Set("vendorId", 123)
-                             .Set("interfaceClass", kPrinterInterfaceClass))));
+                             .Set("interfaceClass", kPrinterInterfaceClass)))));
   ASSERT_TRUE(extensions::ExtensionRegistry::Get(profile_.get())
                   ->AddEnabled(extension));
 
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
index 5dbbdc14..b78fe96 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
+++ b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
@@ -36,12 +36,12 @@
     net::URLRequestJobFactory* interceptor) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   net::URLRequestContext context;
-  scoped_ptr<net::URLRequest> request(context.CreateRequest(
-      url, net::DEFAULT_PRIORITY, NULL));
-  scoped_refptr<net::URLRequestJob> job =
+  scoped_ptr<net::URLRequest> request(
+      context.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr));
+  scoped_ptr<net::URLRequestJob> job(
       interceptor->MaybeCreateJobWithProtocolHandler(
-          url.scheme(), request.get(), context.network_delegate());
-  ASSERT_TRUE(job.get() != NULL);
+          url.scheme(), request.get(), context.network_delegate()));
+  ASSERT_TRUE(job.get());
 }
 
 void AssertIntercepted(
diff --git a/chrome/browser/devtools/devtools_network_controller_unittest.cc b/chrome/browser/devtools/devtools_network_controller_unittest.cc
index 1c57198..ab90bd86 100644
--- a/chrome/browser/devtools/devtools_network_controller_unittest.cc
+++ b/chrome/browser/devtools/devtools_network_controller_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <string>
 
+#include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
@@ -12,6 +13,8 @@
 #include "chrome/browser/devtools/devtools_network_controller.h"
 #include "chrome/browser/devtools/devtools_network_interceptor.h"
 #include "chrome/browser/devtools/devtools_network_transaction.h"
+#include "chrome/browser/devtools/devtools_network_upload_data_stream.h"
+#include "net/base/chunked_upload_data_stream.h"
 #include "net/http/http_transaction_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -26,6 +29,8 @@
 
 const char kClientId[] = "42";
 const char kAnotherClientId[] = "24";
+const char kUploadData[] = "upload_data";
+int64_t kUploadIdentifier = 17;
 
 class TestCallback {
  public:
@@ -62,10 +67,10 @@
         &controller_, network_transaction.Pass()));
   }
 
-  net::HttpRequestInfo* GetRequest() {
-    if (!request_)
-      request_.reset(new MockHttpRequest(mock_transaction_));
-    return request_.get();
+  void SetNetworkState(bool offline, double download, double upload) {
+    scoped_ptr<DevToolsNetworkConditions> conditions(
+        new DevToolsNetworkConditions(offline, 0, download, upload));
+    controller_.SetNetworkState(kClientId, conditions.Pass());
   }
 
   void SetNetworkState(const std::string& id, bool offline) {
@@ -74,9 +79,21 @@
     controller_.SetNetworkState(id, conditions.Pass());
   }
 
-  int Start() {
-    return transaction_->Start(
-        GetRequest(), completion_callback_, net::BoundNetLog());
+  int Start(bool with_upload) {
+    request_.reset(new MockHttpRequest(mock_transaction_));
+
+    if (with_upload) {
+      upload_data_stream_.reset(
+          new net::ChunkedUploadDataStream(kUploadIdentifier));
+      upload_data_stream_->AppendData(
+          kUploadData, arraysize(kUploadData), true);
+      request_->upload_data_stream = upload_data_stream_.get();
+    }
+
+    int rv = transaction_->Start(
+        request_.get(), completion_callback_, net::BoundNetLog());
+    EXPECT_EQ(with_upload, !!transaction_->custom_upload_data_stream_);
+    return rv;
   }
 
   int Read() {
@@ -104,6 +121,13 @@
     transaction_.reset();
   }
 
+  int ReadUploadData() {
+    EXPECT_EQ(net::OK,
+        transaction_->custom_upload_data_stream_->Init(completion_callback_));
+    return transaction_->custom_upload_data_stream_->Read(
+        buffer_.get(), 64, completion_callback_);
+  }
+
   ~DevToolsNetworkControllerHelper() {
     RemoveMockTransaction(&mock_transaction_);
   }
@@ -121,18 +145,19 @@
   DevToolsNetworkController controller_;
   scoped_ptr<DevToolsNetworkTransaction> transaction_;
   scoped_refptr<net::IOBuffer> buffer_;
+  scoped_ptr<net::ChunkedUploadDataStream> upload_data_stream_;
   scoped_ptr<MockHttpRequest> request_;
 };
 
 TEST(DevToolsNetworkControllerTest, SingleDisableEnable) {
   DevToolsNetworkControllerHelper helper;
-  helper.SetNetworkState(kClientId, false);
-  helper.Start();
+  helper.SetNetworkState(false, 0, 0);
+  helper.Start(false);
 
   EXPECT_FALSE(helper.ShouldFail());
-  helper.SetNetworkState(kClientId, true);
+  helper.SetNetworkState(true, 0, 0);
   EXPECT_TRUE(helper.ShouldFail());
-  helper.SetNetworkState(kClientId, false);
+  helper.SetNetworkState(false, 0, 0);
   EXPECT_FALSE(helper.ShouldFail());
 
   base::RunLoop().RunUntilIdle();
@@ -140,25 +165,25 @@
 
 TEST(DevToolsNetworkControllerTest, InterceptorIsolation) {
   DevToolsNetworkControllerHelper helper;
-  helper.SetNetworkState(kClientId, false);
-  helper.Start();
+  helper.SetNetworkState(false, 0, 0);
+  helper.Start(false);
 
   EXPECT_FALSE(helper.ShouldFail());
   helper.SetNetworkState(kAnotherClientId, true);
   EXPECT_FALSE(helper.ShouldFail());
-  helper.SetNetworkState(kClientId, true);
+  helper.SetNetworkState(true, 0, 0);
   EXPECT_TRUE(helper.ShouldFail());
 
   helper.SetNetworkState(kAnotherClientId, false);
-  helper.SetNetworkState(kClientId, false);
+  helper.SetNetworkState(false, 0, 0);
   base::RunLoop().RunUntilIdle();
 }
 
 TEST(DevToolsNetworkControllerTest, FailOnStart) {
   DevToolsNetworkControllerHelper helper;
-  helper.SetNetworkState(kClientId, true);
+  helper.SetNetworkState(true, 0, 0);
 
-  int rv = helper.Start();
+  int rv = helper.Start(false);
   EXPECT_EQ(rv, net::ERR_INTERNET_DISCONNECTED);
 
   base::RunLoop().RunUntilIdle();
@@ -167,18 +192,17 @@
 
 TEST(DevToolsNetworkControllerTest, FailRunningTransaction) {
   DevToolsNetworkControllerHelper helper;
-  helper.SetNetworkState(kClientId, false);
+  helper.SetNetworkState(false, 0, 0);
   TestCallback* callback = helper.callback();
 
-  int rv = helper.Start();
+  int rv = helper.Start(false);
   EXPECT_EQ(rv, net::OK);
 
-  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(64));
   rv = helper.Read();
   EXPECT_EQ(rv, net::ERR_IO_PENDING);
   EXPECT_EQ(callback->run_count(), 0);
 
-  helper.SetNetworkState(kClientId, true);
+  helper.SetNetworkState(true, 0, 0);
   EXPECT_EQ(callback->run_count(), 0);
 
   // Wait until HttpTrancation completes reading and invokes callback.
@@ -188,24 +212,23 @@
   EXPECT_EQ(callback->value(), net::ERR_INTERNET_DISCONNECTED);
 
   // Check that transaction is not failed second time.
-  helper.SetNetworkState(kClientId, false);
-  helper.SetNetworkState(kClientId, true);
+  helper.SetNetworkState(false, 0, 0);
+  helper.SetNetworkState(true, 0, 0);
   EXPECT_EQ(callback->run_count(), 1);
 }
 
 TEST(DevToolsNetworkControllerTest, ReadAfterFail) {
   DevToolsNetworkControllerHelper helper;
-  helper.SetNetworkState(kClientId, false);
+  helper.SetNetworkState(false, 0, 0);
 
-  int rv = helper.Start();
+  int rv = helper.Start(false);
   EXPECT_EQ(rv, net::OK);
   EXPECT_TRUE(helper.HasStarted());
 
-  helper.SetNetworkState(kClientId, true);
+  helper.SetNetworkState(true, 0, 0);
   // Not failed yet, as no IO was initiated.
   EXPECT_FALSE(helper.HasFailed());
 
-  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(64));
   rv = helper.Read();
   // Fails on first IO.
   EXPECT_EQ(rv, net::ERR_INTERNET_DISCONNECTED);
@@ -217,32 +240,85 @@
 
 TEST(DevToolsNetworkControllerTest, CancelTransaction) {
   DevToolsNetworkControllerHelper helper;
-  helper.SetNetworkState(kClientId, false);
+  helper.SetNetworkState(false, 0, 0);
 
-  int rv = helper.Start();
+  int rv = helper.Start(false);
   EXPECT_EQ(rv, net::OK);
   EXPECT_TRUE(helper.HasStarted());
   helper.CancelTransaction();
 
   // Should not crash.
-  helper.SetNetworkState(kClientId, true);
-  helper.SetNetworkState(kClientId, false);
+  helper.SetNetworkState(true, 0, 0);
+  helper.SetNetworkState(false, 0, 0);
   base::RunLoop().RunUntilIdle();
 }
 
 TEST(DevToolsNetworkControllerTest, CancelFailedTransaction) {
   DevToolsNetworkControllerHelper helper;
-  helper.SetNetworkState(kClientId, true);
+  helper.SetNetworkState(true, 0, 0);
 
-  int rv = helper.Start();
+  int rv = helper.Start(false);
   EXPECT_EQ(rv, net::ERR_INTERNET_DISCONNECTED);
   EXPECT_TRUE(helper.HasStarted());
   helper.CancelTransaction();
 
   // Should not crash.
-  helper.SetNetworkState(kClientId, true);
-  helper.SetNetworkState(kClientId, false);
+  helper.SetNetworkState(true, 0, 0);
+  helper.SetNetworkState(false, 0, 0);
   base::RunLoop().RunUntilIdle();
 }
 
+TEST(DevToolsNetworkControllerTest, UploadDoesNotFail) {
+  DevToolsNetworkControllerHelper helper;
+  helper.SetNetworkState(true, 0, 0);
+  int rv = helper.Start(true);
+  EXPECT_EQ(rv, net::ERR_INTERNET_DISCONNECTED);
+  rv = helper.ReadUploadData();
+  EXPECT_EQ(rv, static_cast<int>(arraysize(kUploadData)));
+}
+
+TEST(DevToolsNetworkControllerTest, DownloadOnly) {
+  DevToolsNetworkControllerHelper helper;
+  TestCallback* callback = helper.callback();
+
+  helper.SetNetworkState(false, 10000000, 0);
+  int rv = helper.Start(false);
+  EXPECT_EQ(rv, net::ERR_IO_PENDING);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(callback->run_count(), 1);
+  EXPECT_GE(callback->value(), net::OK);
+
+  rv = helper.Read();
+  EXPECT_EQ(rv, net::ERR_IO_PENDING);
+  EXPECT_EQ(callback->run_count(), 1);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(callback->run_count(), 2);
+  EXPECT_GE(callback->value(), net::OK);
+}
+
+TEST(DevToolsNetworkControllerTest, UploadOnly) {
+  DevToolsNetworkControllerHelper helper;
+  TestCallback* callback = helper.callback();
+
+  helper.SetNetworkState(false, 0, 1000000);
+  int rv = helper.Start(true);
+  EXPECT_EQ(rv, net::OK);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(callback->run_count(), 0);
+
+  rv = helper.Read();
+  EXPECT_EQ(rv, net::ERR_IO_PENDING);
+  EXPECT_EQ(callback->run_count(), 0);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(callback->run_count(), 1);
+  EXPECT_GE(callback->value(), net::OK);
+
+  rv = helper.ReadUploadData();
+  EXPECT_EQ(rv, net::ERR_IO_PENDING);
+  EXPECT_EQ(callback->run_count(), 1);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(callback->run_count(), 2);
+  EXPECT_EQ(callback->value(), static_cast<int>(arraysize(kUploadData)));
+}
+
 }  // namespace test
diff --git a/chrome/browser/devtools/devtools_network_interceptor.cc b/chrome/browser/devtools/devtools_network_interceptor.cc
index be28619..a75d352 100644
--- a/chrome/browser/devtools/devtools_network_interceptor.cc
+++ b/chrome/browser/devtools/devtools_network_interceptor.cc
@@ -15,6 +15,16 @@
 
 int64_t kPacketSize = 1500;
 
+base::TimeDelta CalculateTickLength(double throughput) {
+  if (!throughput)
+    return base::TimeDelta();
+  int64_t us_tick_length = (1000000L * kPacketSize) / throughput;
+  DCHECK(us_tick_length != 0);
+  if (us_tick_length == 0)
+    us_tick_length = 1;
+  return base::TimeDelta::FromMicroseconds(us_tick_length);
+}
+
 }  // namespace
 
 DevToolsNetworkInterceptor::ThrottleRecord::ThrottleRecord() {
@@ -25,6 +35,8 @@
 
 DevToolsNetworkInterceptor::DevToolsNetworkInterceptor()
     : conditions_(new DevToolsNetworkConditions()),
+      download_last_tick_(0),
+      upload_last_tick_(0),
       weak_ptr_factory_(this) {
 }
 
@@ -36,6 +48,18 @@
   return weak_ptr_factory_.GetWeakPtr();
 }
 
+void DevToolsNetworkInterceptor::FinishRecords(
+    ThrottleRecords* records, bool offline) {
+  ThrottleRecords temp;
+  temp.swap(*records);
+  for (const ThrottleRecord& record : temp) {
+    bool failed = offline && !record.is_upload;
+    record.callback.Run(
+        failed ? net::ERR_INTERNET_DISCONNECTED : record.result,
+        record.bytes);
+  }
+}
+
 void DevToolsNetworkInterceptor::UpdateConditions(
     scoped_ptr<DevToolsNetworkConditions> conditions) {
   DCHECK(conditions);
@@ -48,37 +72,24 @@
   bool offline = conditions_->offline();
   if (offline || !conditions_->IsThrottling()) {
     timer_.Stop();
-    ThrottleRecords throttled;
-    throttled.swap(throttled_);
-    for (const ThrottleRecord& record : throttled) {
-      bool failed = offline && !record.is_upload;
-      record.callback.Run(
-          failed ? net::ERR_INTERNET_DISCONNECTED : record.result,
-          record.bytes);
-    }
-
-    ThrottleRecords suspended;
-    suspended.swap(suspended_);
-    for (const ThrottleRecord& record : suspended) {
-      bool failed = offline && !record.is_upload;
-      record.callback.Run(
-          failed ? net::ERR_INTERNET_DISCONNECTED : record.result,
-          record.bytes);
-    }
-
+    FinishRecords(&download_, offline);
+    FinishRecords(&upload_, offline);
+    FinishRecords(&suspended_, offline);
     return;
   }
 
   // Throttling.
-  DCHECK(conditions_->download_throughput() != 0);
+  DCHECK(conditions_->download_throughput() != 0 ||
+         conditions_->upload_throughput() != 0);
   offset_ = now;
-  last_tick_ = 0;
-  int64_t us_tick_length =
-      (1000000L * kPacketSize) / conditions_->download_throughput();
-  DCHECK(us_tick_length != 0);
-  if (us_tick_length == 0)
-    us_tick_length = 1;
-  tick_length_ = base::TimeDelta::FromMicroseconds(us_tick_length);
+
+  download_last_tick_ = 0;
+  download_tick_length_ = CalculateTickLength(
+      conditions_->download_throughput());
+
+  upload_last_tick_ = 0;
+  upload_tick_length_ = CalculateTickLength(conditions_->upload_throughput());
+
   latency_length_ = base::TimeDelta();
   double latency = conditions_->latency();
   if (latency > 0)
@@ -86,78 +97,109 @@
   ArmTimer(now);
 }
 
-void DevToolsNetworkInterceptor::UpdateThrottled(
-    base::TimeTicks now) {
-  int64_t last_tick = (now - offset_) / tick_length_;
-  int64_t ticks = last_tick - last_tick_;
-  last_tick_ = last_tick;
-
-  int64_t length = throttled_.size();
-  if (!length) {
-    UpdateSuspended(now);
-    return;
+uint64_t DevToolsNetworkInterceptor::UpdateThrottledRecords(
+    base::TimeTicks now,
+    ThrottleRecords* records,
+    uint64_t last_tick,
+    base::TimeDelta tick_length) {
+  if (tick_length.is_zero()) {
+    DCHECK(!records->size());
+    return last_tick;
   }
 
+  int64_t new_tick = (now - offset_) / tick_length;
+  int64_t ticks = new_tick - last_tick;
+
+  int64_t length = records->size();
+  if (!length)
+    return new_tick;
+
   int64_t shift = ticks % length;
   for (int64_t i = 0; i < length; ++i) {
-    throttled_[i].bytes -=
+    (*records)[i].bytes -=
         (ticks / length) * kPacketSize + (i < shift ? kPacketSize : 0);
   }
-  std::rotate(throttled_.begin(),
-      throttled_.begin() + shift, throttled_.end());
+  std::rotate(records->begin(), records->begin() + shift, records->end());
+  return new_tick;
+}
 
+void DevToolsNetworkInterceptor::UpdateThrottled(base::TimeTicks now) {
+  download_last_tick_ = UpdateThrottledRecords(
+      now, &download_, download_last_tick_, download_tick_length_);
+  upload_last_tick_ = UpdateThrottledRecords(
+      now, &upload_, upload_last_tick_, upload_tick_length_);
   UpdateSuspended(now);
 }
 
-void DevToolsNetworkInterceptor::UpdateSuspended(
-    base::TimeTicks now) {
+void DevToolsNetworkInterceptor::UpdateSuspended(base::TimeTicks now) {
   int64_t activation_baseline =
       (now - latency_length_ - base::TimeTicks()).InMicroseconds();
   ThrottleRecords suspended;
   for (const ThrottleRecord& record : suspended_) {
-    if (record.send_end <= activation_baseline)
-      throttled_.push_back(record);
-    else
+    if (record.send_end <= activation_baseline) {
+      if (record.is_upload)
+        upload_.push_back(record);
+      else
+        download_.push_back(record);
+    } else {
       suspended.push_back(record);
+    }
   }
   suspended_.swap(suspended);
 }
 
+void DevToolsNetworkInterceptor::CollectFinished(
+    ThrottleRecords* records, ThrottleRecords* finished) {
+  ThrottleRecords active;
+  for (const ThrottleRecord& record : *records) {
+    if (record.bytes < 0)
+      finished->push_back(record);
+    else
+      active.push_back(record);
+  }
+  records->swap(active);
+}
+
 void DevToolsNetworkInterceptor::OnTimer() {
   base::TimeTicks now = base::TimeTicks::Now();
   UpdateThrottled(now);
 
-  ThrottleRecords active;
   ThrottleRecords finished;
-  for (const ThrottleRecord& record : throttled_) {
-    if (record.bytes < 0)
-      finished.push_back(record);
-    else
-      active.push_back(record);
-  }
-  throttled_.swap(active);
-
+  CollectFinished(&download_, &finished);
+  CollectFinished(&upload_, &finished);
   for (const ThrottleRecord& record : finished)
     record.callback.Run(record.result, record.bytes);
 
   ArmTimer(now);
 }
 
-void DevToolsNetworkInterceptor::ArmTimer(base::TimeTicks now) {
-  size_t throttle_count = throttled_.size();
-  size_t suspend_count = suspended_.size();
-  if (!throttle_count && !suspend_count)
-    return;
+base::TimeTicks DevToolsNetworkInterceptor::CalculateDesiredTime(
+    const ThrottleRecords& records,
+    uint64_t last_tick,
+    base::TimeDelta tick_length) {
   int64_t min_ticks_left = 0x10000L;
-  for (size_t i = 0; i < throttle_count; ++i) {
-    int64_t packets_left = (throttled_[i].bytes +
-        kPacketSize - 1) / kPacketSize;
-    int64_t ticks_left = (i + 1) + throttle_count * (packets_left - 1);
+  size_t count = records.size();
+  for (size_t i = 0; i < count; ++i) {
+    int64_t packets_left = (records[i].bytes + kPacketSize - 1) / kPacketSize;
+    int64_t ticks_left = (i + 1) + count * (packets_left - 1);
     if (i == 0 || ticks_left < min_ticks_left)
       min_ticks_left = ticks_left;
   }
-  base::TimeTicks desired_time =
-      offset_ + tick_length_ * (last_tick_ + min_ticks_left);
+  return offset_ + tick_length * (last_tick + min_ticks_left);
+}
+
+void DevToolsNetworkInterceptor::ArmTimer(base::TimeTicks now) {
+  size_t suspend_count = suspended_.size();
+  if (!download_.size() && !upload_.size() && !suspend_count)
+    return;
+
+  base::TimeTicks desired_time = CalculateDesiredTime(
+      download_, download_last_tick_, download_tick_length_);
+
+  base::TimeTicks upload_time = CalculateDesiredTime(
+      upload_, upload_last_tick_, upload_tick_length_);
+  if (upload_time < desired_time)
+    desired_time = upload_time;
 
   int64_t min_baseline = std::numeric_limits<int64>::max();
   for (size_t i = 0; i < suspend_count; ++i) {
@@ -192,8 +234,10 @@
   if (conditions_->offline())
     return is_upload ? result : net::ERR_INTERNET_DISCONNECTED;
 
-  if (!conditions_->IsThrottling())
+  if ((is_upload && !conditions_->upload_throughput()) ||
+      (!is_upload && !conditions_->download_throughput())) {
     return result;
+  }
 
   ThrottleRecord record;
   record.result = result;
@@ -209,7 +253,10 @@
     suspended_.push_back(record);
     UpdateSuspended(now);
   } else {
-    throttled_.push_back(record);
+    if (is_upload)
+      upload_.push_back(record);
+    else
+      download_.push_back(record);
   }
   ArmTimer(now);
 
@@ -218,7 +265,8 @@
 
 void DevToolsNetworkInterceptor::StopThrottle(
     const ThrottleCallback& callback) {
-  RemoveRecord(&throttled_, callback);
+  RemoveRecord(&download_, callback);
+  RemoveRecord(&upload_, callback);
   RemoveRecord(&suspended_, callback);
 }
 
diff --git a/chrome/browser/devtools/devtools_network_interceptor.h b/chrome/browser/devtools/devtools_network_interceptor.h
index c0c8058c..f9a441cb 100644
--- a/chrome/browser/devtools/devtools_network_interceptor.h
+++ b/chrome/browser/devtools/devtools_network_interceptor.h
@@ -47,13 +47,6 @@
   bool IsOffline();
 
  private:
-  scoped_ptr<DevToolsNetworkConditions> conditions_;
-
-  void UpdateThrottled(base::TimeTicks now);
-  void UpdateSuspended(base::TimeTicks now);
-  void ArmTimer(base::TimeTicks now);
-  void OnTimer();
-
   struct ThrottleRecord {
    public:
     ThrottleRecord();
@@ -66,19 +59,38 @@
   };
   using ThrottleRecords = std::vector<ThrottleRecord>;
 
+  void FinishRecords(ThrottleRecords* records, bool offline);
+
+  uint64_t UpdateThrottledRecords(base::TimeTicks now, ThrottleRecords* records,
+      uint64_t last_tick, base::TimeDelta tick_length);
+  void UpdateThrottled(base::TimeTicks now);
+  void UpdateSuspended(base::TimeTicks now);
+
+  void CollectFinished(ThrottleRecords* records, ThrottleRecords* finished);
+  void OnTimer();
+
+  base::TimeTicks CalculateDesiredTime(const ThrottleRecords& records,
+    uint64_t last_tick, base::TimeDelta tick_length);
+  void ArmTimer(base::TimeTicks now);
+
   void RemoveRecord(ThrottleRecords* records, const ThrottleCallback& callback);
 
+  scoped_ptr<DevToolsNetworkConditions> conditions_;
+
   // Throttables suspended for a "latency" period.
   ThrottleRecords suspended_;
 
-  // Throttable waiting certain amount of transfer to be "accounted".
-  ThrottleRecords throttled_;
+  // Throttables waiting certain amount of transfer to be "accounted".
+  ThrottleRecords download_;
+  ThrottleRecords upload_;
 
   base::OneShotTimer timer_;
   base::TimeTicks offset_;
-  base::TimeDelta tick_length_;
+  base::TimeDelta download_tick_length_;
+  base::TimeDelta upload_tick_length_;
   base::TimeDelta latency_length_;
-  uint64_t last_tick_;
+  uint64_t download_last_tick_;
+  uint64_t upload_last_tick_;
 
   base::WeakPtrFactory<DevToolsNetworkInterceptor> weak_ptr_factory_;
 
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 7b0e9be..039905ec 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -3423,8 +3423,7 @@
 class DownloadTestWithShelf : public DownloadTest {
   void SetUpCommandLine(base::CommandLine* command_line) override {
 #if defined(OS_CHROMEOS)
-    command_line->AppendSwitchASCII(switches::kEnableDownloadNotification,
-                                    "disabled");
+    command_line->AppendSwitch(switches::kDisableDownloadNotification);
 #endif
     DownloadTest::SetUpCommandLine(command_line);
   }
diff --git a/chrome/browser/download/notification/download_notification_browsertest.cc b/chrome/browser/download/notification/download_notification_browsertest.cc
index 992df31..7846aea 100644
--- a/chrome/browser/download/notification/download_notification_browsertest.cc
+++ b/chrome/browser/download/notification/download_notification_browsertest.cc
@@ -272,12 +272,6 @@
  public:
   ~DownloadNotificationTestBase() override {}
 
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    // TODO(yoshiki): Remove this after the download notification launches.
-    command_line->AppendSwitchASCII(switches::kEnableDownloadNotification,
-                                    "enabled");
-  }
-
   void SetUpOnMainThread() override {
     ASSERT_TRUE(embedded_test_server()->Start());
 
@@ -1075,14 +1069,8 @@
   chrome::CloseWindow(incognito_browser());
 }
 
-// TODO(yoshiki): Disabled due to crbug.com/560329
-#if defined(OS_CHROMEOS)
-#define MAYBE_SimultaneousIncognitoAndNormalDownloads DISABLED_SimultaneousIncognitoAndNormalDownloads
-#else
-#define MAYBE_SimultaneousIncognitoAndNormalDownloads SimultaneousIncognitoAndNormalDownloads
-#endif
 IN_PROC_BROWSER_TEST_F(DownloadNotificationTest,
-                       MAYBE_SimultaneousIncognitoAndNormalDownloads) {
+                       SimultaneousIncognitoAndNormalDownloads) {
   PrepareIncognitoBrowser();
 
   GURL url_incognito(net::URLRequestSlowDownloadJob::kUnknownSizeUrl);
@@ -1127,8 +1115,10 @@
   // Confirms the types of download notifications are correct.
   EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS,
             GetNotification(notification_id1)->type());
+  EXPECT_EQ(-1, GetNotification(notification_id1)->progress());
   EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS,
             GetNotification(notification_id2)->type());
+  EXPECT_LE(0, GetNotification(notification_id2)->progress());
 
   EXPECT_TRUE(download_incognito->GetBrowserContext()->IsOffTheRecord());
   EXPECT_FALSE(download_normal->GetBrowserContext()->IsOffTheRecord());
@@ -1148,10 +1138,8 @@
   // Confirms the types of download notifications are correct.
   EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT,
             GetNotification(notification_id1)->type());
-  EXPECT_EQ(-1, GetNotification(notification_id1)->progress());
   EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT,
             GetNotification(notification_id2)->type());
-  EXPECT_LE(0, GetNotification(notification_id1)->progress());
 
   chrome::CloseWindow(incognito_browser());
 }
diff --git a/chrome/browser/download/notification/download_notification_manager.cc b/chrome/browser/download/notification/download_notification_manager.cc
index 6eb6b49..da005bd 100644
--- a/chrome/browser/download/notification/download_notification_manager.cc
+++ b/chrome/browser/download/notification/download_notification_manager.cc
@@ -24,16 +24,8 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 bool DownloadNotificationManager::IsEnabled() {
-  bool enable_download_notification = true;
-  std::string arg = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-      switches::kEnableDownloadNotification);
-  if (!arg.empty()) {
-    if (arg == "enabled")
-      enable_download_notification = true;
-    else if (arg == "disabled")
-      enable_download_notification = false;
-  }
-  return enable_download_notification;
+  return !base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kDisableDownloadNotification);
 }
 
 DownloadNotificationManager::DownloadNotificationManager(Profile* profile)
diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc
index 127d2c32..f327236 100644
--- a/chrome/browser/download/save_page_browsertest.cc
+++ b/chrome/browser/download/save_page_browsertest.cc
@@ -993,9 +993,12 @@
   }
 };
 
-// Test coverage for OOPIFs for CompleteHtml (crbug.com/526786) and
-// MHTML (crbug.com/538766) as well as for redirected iframes saved
-// as MHTML (crbug.com/539936).
+// Test coverage for:
+// - crbug.com/526786: OOPIFs support for CompleteHtml
+// - crbug.com/538766: OOPIFs support for MHTML
+// - crbug.com/539936: Subframe gets redirected.
+// Test compares original-vs-saved for a page with cross-site frames
+// (subframes get redirected to a different domain - see frames-xsite.htm).
 IN_PROC_BROWSER_TEST_P(SavePageMultiFrameBrowserTest, CrossSite) {
   content::SavePageType save_page_type = GetParam();
 
@@ -1021,7 +1024,8 @@
                      skip_verification_of_original_page);
 }
 
-// Test for crbug.com/553478.
+// Test compares original-vs-saved for a page with <object> elements.
+// (see crbug.com/553478).
 IN_PROC_BROWSER_TEST_P(SavePageMultiFrameBrowserTest, ObjectElements) {
   content::SavePageType save_page_type = GetParam();
 
@@ -1049,6 +1053,9 @@
                      expected_substrings);
 }
 
+// Test compares original-vs-saved for a page with frames at about:blank uri.
+// This tests handling of iframe elements without src attribute (only with
+// srcdoc attribute) and how they get saved / cross-referenced.
 IN_PROC_BROWSER_TEST_P(SavePageMultiFrameBrowserTest, AboutBlank) {
   content::SavePageType save_page_type = GetParam();
 
@@ -1066,7 +1073,9 @@
   TestMultiFramePage(save_page_type, url, 4, expected_substrings);
 }
 
-// Test for crbug.com/554666.
+// Test compares original-vs-saved for a page with nested frames.
+// Two levels of nesting are especially good for verifying correct
+// link rewriting for subframes-vs-main-frame (see crbug.com/554666).
 IN_PROC_BROWSER_TEST_P(SavePageMultiFrameBrowserTest, NestedFrames) {
   content::SavePageType save_page_type = GetParam();
 
@@ -1100,9 +1109,20 @@
   };
   std::vector<std::string> expected_substrings(std::begin(arr), std::end(arr));
 
-  // TODO(lukasza): crbug.com/106364: Fix complete-html mode as well.
-  if (save_page_type == content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML)
-    return;
+  if (save_page_type == content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML) {
+    // TODO(lukasza): crbug.com/106364: Expand complete-html test beyond just
+    // being a crash test.  In particular, the |complete_html_arr| below should
+    // be the same as the |arr| above (and at this point the special-casing of
+    // complete-html can be removed).
+    // Draft CLs with fix proposals that should accomplish this:
+    // - crrev.com/1502563004
+    // - crrev.com/1500103002
+    std::string complete_html_arr[] = {
+        "frames-runtime-changes.htm: 4388232f-8d45-4d2e-9807-721b381be153",
+    };
+    expected_substrings = std::vector<std::string>(
+        std::begin(complete_html_arr), std::end(complete_html_arr));
+  }
 
   GURL url(embedded_test_server()->GetURL(
       "a.com", "/save_page/frames-runtime-changes.htm?do_runtime_changes=1"));
diff --git a/chrome/browser/engagement/site_engagement_helper.cc b/chrome/browser/engagement/site_engagement_helper.cc
index 81ffdf4..ada901b5 100644
--- a/chrome/browser/engagement/site_engagement_helper.cc
+++ b/chrome/browser/engagement/site_engagement_helper.cc
@@ -111,26 +111,32 @@
 SiteEngagementHelper::MediaTracker::MediaTracker(
     SiteEngagementHelper* helper,
     content::WebContents* web_contents)
-    : PeriodicTracker(helper), content::WebContentsObserver(web_contents),
-      is_hidden_(false),
-      is_playing_(false) {}
+    : PeriodicTracker(helper),
+      content::WebContentsObserver(web_contents),
+      is_hidden_(false) {}
+
+SiteEngagementHelper::MediaTracker::~MediaTracker() {}
 
 void SiteEngagementHelper::MediaTracker::TrackingStarted() {
-  if (is_playing_)
+  if (!active_media_players_.empty())
     helper()->RecordMediaPlaying(is_hidden_);
 
   Pause();
 }
 
-void SiteEngagementHelper::MediaTracker::MediaStartedPlaying() {
+void SiteEngagementHelper::MediaTracker::MediaStartedPlaying(
+    const MediaPlayerId& id) {
   // Only begin engagement detection when media actually starts playing.
-  is_playing_ = true;
+  active_media_players_.push_back(id);
   if (!IsTimerRunning())
     Start(base::TimeDelta::FromSeconds(g_seconds_delay_after_media_starts));
 }
 
-void SiteEngagementHelper::MediaTracker::MediaPaused() {
-  is_playing_ = false;
+void SiteEngagementHelper::MediaTracker::MediaStoppedPlaying(
+    const MediaPlayerId& id) {
+  active_media_players_.erase(std::remove(active_media_players_.begin(),
+                                          active_media_players_.end(), id),
+                              active_media_players_.end());
 }
 
 void SiteEngagementHelper::MediaTracker::WasShown() {
diff --git a/chrome/browser/engagement/site_engagement_helper.h b/chrome/browser/engagement/site_engagement_helper.h
index 3f89350..88ffec2e 100644
--- a/chrome/browser/engagement/site_engagement_helper.h
+++ b/chrome/browser/engagement/site_engagement_helper.h
@@ -130,6 +130,7 @@
    public:
     MediaTracker(SiteEngagementHelper* helper,
                  content::WebContents* web_contents);
+    ~MediaTracker() override;
 
    private:
     friend class SiteEngagementHelperTest;
@@ -137,13 +138,13 @@
     void TrackingStarted() override;
 
     // content::WebContentsObserver overrides.
-    void MediaStartedPlaying() override;
-    void MediaPaused() override;
+    void MediaStartedPlaying(const MediaPlayerId& id) override;
+    void MediaStoppedPlaying(const MediaPlayerId& id) override;
     void WasShown() override;
     void WasHidden() override;
 
     bool is_hidden_;
-    bool is_playing_;
+    std::vector<MediaPlayerId> active_media_players_;
   };
 
   explicit SiteEngagementHelper(content::WebContents* web_contents);
diff --git a/chrome/browser/engagement/site_engagement_helper_unittest.cc b/chrome/browser/engagement/site_engagement_helper_unittest.cc
index 6b8fee78..edcbdb2 100644
--- a/chrome/browser/engagement/site_engagement_helper_unittest.cc
+++ b/chrome/browser/engagement/site_engagement_helper_unittest.cc
@@ -53,11 +53,13 @@
   }
 
   void MediaStartedPlaying(SiteEngagementHelper* helper) {
-    helper->media_tracker_.MediaStartedPlaying();
+    helper->media_tracker_.MediaStartedPlaying(
+        content::WebContentsObserver::MediaPlayerId(nullptr, 1));
   }
 
-  void MediaPaused(SiteEngagementHelper* helper) {
-    helper->media_tracker_.MediaPaused();
+  void MediaStoppedPlaying(SiteEngagementHelper* helper) {
+    helper->media_tracker_.MediaStoppedPlaying(
+        content::WebContentsObserver::MediaPlayerId(nullptr, 1));
   }
 
   // Set a pause timer on the input tracker for test purposes.
@@ -235,7 +237,7 @@
   EXPECT_EQ(0, service->GetScore(url2));
   EXPECT_TRUE(media_tracker_timer->IsRunning());
 
-  MediaPaused(helper.get());
+  MediaStoppedPlaying(helper.get());
   media_tracker_timer->Fire();
   EXPECT_DOUBLE_EQ(0.53, service->GetScore(url1));
   EXPECT_EQ(0, service->GetScore(url2));
@@ -270,7 +272,7 @@
   EXPECT_EQ(0.53, service->GetScore(url2));
   EXPECT_TRUE(media_tracker_timer->IsRunning());
 
-  MediaPaused(helper.get());
+  MediaStoppedPlaying(helper.get());
   web_contents->WasShown();
   media_tracker_timer->Fire();
   EXPECT_DOUBLE_EQ(0.55, service->GetScore(url1));
diff --git a/chrome/browser/extensions/active_script_controller_unittest.cc b/chrome/browser/extensions/active_script_controller_unittest.cc
index 3d21d5c..4c16930 100644
--- a/chrome/browser/extensions/active_script_controller_unittest.cc
+++ b/chrome/browser/extensions/active_script_controller_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <map>
+#include <utility>
 
 #include "base/values.h"
 #include "chrome/browser/extensions/active_script_controller.h"
@@ -99,18 +100,18 @@
 
 const Extension* ActiveScriptControllerUnitTest::AddExtension() {
   const std::string kId = crx_file::id_util::GenerateId("all_hosts_extension");
-  extension_ = ExtensionBuilder()
-                   .SetManifest(
-                       DictionaryBuilder()
+  extension_ =
+      ExtensionBuilder()
+          .SetManifest(DictionaryBuilder()
                            .Set("name", "all_hosts_extension")
                            .Set("description", "an extension")
                            .Set("manifest_version", 2)
                            .Set("version", "1.0.0")
-                           .Set("permissions",
-                                ListBuilder().Append(kAllHostsPermission)))
-                   .SetLocation(Manifest::INTERNAL)
-                   .SetID(kId)
-                   .Build();
+                           .Set("permissions", std::move(ListBuilder().Append(
+                                                   kAllHostsPermission))))
+          .SetLocation(Manifest::INTERNAL)
+          .SetID(kId)
+          .Build();
 
   ExtensionRegistry::Get(profile())->AddEnabled(extension_);
   PermissionsUpdater(profile()).InitializePermissions(extension_.get());
diff --git a/chrome/browser/extensions/active_tab_unittest.cc b/chrome/browser/extensions/active_tab_unittest.cc
index be5668c0..45ae57c 100644
--- a/chrome/browser/extensions/active_tab_unittest.cc
+++ b/chrome/browser/extensions/active_tab_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <string>
+#include <utility>
 
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
@@ -50,10 +51,10 @@
     permissions.Append("tabCapture");
   return ExtensionBuilder()
       .SetManifest(DictionaryBuilder()
-          .Set("name", "Extension with ID " + id)
-          .Set("version", "1.0")
-          .Set("manifest_version", 2)
-          .Set("permissions", permissions))
+                       .Set("name", "Extension with ID " + id)
+                       .Set("version", "1.0")
+                       .Set("manifest_version", 2)
+                       .Set("permissions", std::move(permissions)))
       .SetID(id)
       .Build();
 }
diff --git a/chrome/browser/extensions/activity_log/activity_log_policy_unittest.cc b/chrome/browser/extensions/activity_log/activity_log_policy_unittest.cc
index acc27e8..6501a46 100644
--- a/chrome/browser/extensions/activity_log/activity_log_policy_unittest.cc
+++ b/chrome/browser/extensions/activity_log/activity_log_policy_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/values.h"
 #include "chrome/browser/extensions/activity_log/activity_action_constants.h"
 #include "chrome/browser/extensions/activity_log/activity_actions.h"
@@ -47,8 +49,9 @@
           .Set(activity_log_web_request_constants::kNewUrlKey,
                "http://www.youtube.com/")
           .Set(activity_log_web_request_constants::kAddedRequestHeadersKey,
-               ListBuilder().Append("arg"))
-          .Build().release());
+               std::move(ListBuilder().Append("arg")))
+          .Build()
+          .release());
 
   ActivityLogPolicy::Util::StripPrivacySensitiveFields(action);
 
diff --git a/chrome/browser/extensions/api/commands/command_service.cc b/chrome/browser/extensions/api/commands/command_service.cc
index 5ff8711..1dd125b 100644
--- a/chrome/browser/extensions/api/commands/command_service.cc
+++ b/chrome/browser/extensions/api/commands/command_service.cc
@@ -315,7 +315,6 @@
     content::BrowserContext* browser_context,
     const Extension* extension,
     bool is_update,
-    bool from_ephemeral,
     const std::string& old_name) {
   UpdateKeybindings(extension);
 }
diff --git a/chrome/browser/extensions/api/commands/command_service.h b/chrome/browser/extensions/api/commands/command_service.h
index cda73eec..ef0ae9d9 100644
--- a/chrome/browser/extensions/api/commands/command_service.h
+++ b/chrome/browser/extensions/api/commands/command_service.h
@@ -213,7 +213,6 @@
   void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
                                   const Extension* extension,
                                   bool is_update,
-                                  bool from_ephemeral,
                                   const std::string& old_name) override;
   void OnExtensionUninstalled(content::BrowserContext* browser_context,
                               const Extension* extension,
diff --git a/chrome/browser/extensions/api/debugger/debugger_apitest.cc b/chrome/browser/extensions/api/debugger/debugger_apitest.cc
index 1ca4e71f..ff1a67d 100644
--- a/chrome/browser/extensions/api/debugger/debugger_apitest.cc
+++ b/chrome/browser/extensions/api/debugger/debugger_apitest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <string>
+#include <utility>
 
 #include "base/command_line.h"
 #include "base/memory/ref_counted.h"
@@ -65,12 +66,14 @@
 void DebuggerApiTest::SetUpOnMainThread() {
   ExtensionApiTest::SetUpOnMainThread();
   extension_ =
-      ExtensionBuilder().SetManifest(
-          DictionaryBuilder().Set("name", "debugger")
-                             .Set("version", "0.1")
-                             .Set("manifest_version", 2)
-                             .Set("permissions",
-                                  ListBuilder().Append("debugger"))).Build();
+      ExtensionBuilder()
+          .SetManifest(DictionaryBuilder()
+                           .Set("name", "debugger")
+                           .Set("version", "0.1")
+                           .Set("manifest_version", 2)
+                           .Set("permissions",
+                                std::move(ListBuilder().Append("debugger"))))
+          .Build();
 }
 
 testing::AssertionResult DebuggerApiTest::RunAttachFunction(
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_is_bookmarked_condition_tracker_unittest.cc b/chrome/browser/extensions/api/declarative_content/declarative_content_is_bookmarked_condition_tracker_unittest.cc
index b114258..1c36c62 100644
--- a/chrome/browser/extensions/api/declarative_content/declarative_content_is_bookmarked_condition_tracker_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_content/declarative_content_is_bookmarked_condition_tracker_unittest.cc
@@ -39,10 +39,10 @@
     permissions.Append("bookmarks");
   return ExtensionBuilder()
       .SetManifest(DictionaryBuilder()
-                   .Set("name", "Test extension")
-                   .Set("version", "1.0")
-                   .Set("manifest_version", 2)
-                   .Set("permissions", permissions))
+                       .Set("name", "Test extension")
+                       .Set("version", "1.0")
+                       .Set("manifest_version", 2)
+                       .Set("permissions", std::move(permissions)))
       .Build();
 }
 
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
index c64fc63a..60b34684 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/files/file_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
@@ -529,7 +531,8 @@
   args = ListBuilder()
              .Append(DictionaryBuilder()
                          .Set("extensionId", extension->id())
-                         .Set("errorIds", ListBuilder().Append(error_id)))
+                         .Set("errorIds",
+                              std::move(ListBuilder().Append(error_id))))
              .Build();
   function = new api::DeveloperPrivateDeleteExtensionErrorsFunction();
   EXPECT_TRUE(RunFunction(function, *args)) << function->GetError();
diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc b/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc
index 94f1b0e7..6d38e516 100644
--- a/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc
+++ b/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/json/json_file_value_serializer.h"
 #include "base/json/json_writer.h"
 #include "base/strings/string_util.h"
@@ -80,19 +82,19 @@
 
   const scoped_refptr<const Extension> CreateExtension(
       const std::string& name,
-      ListBuilder& permissions) {
+      ListBuilder permissions) {
     const std::string kId = crx_file::id_util::GenerateId(name);
     scoped_refptr<const Extension> extension =
-        ExtensionBuilder().SetManifest(
-                               DictionaryBuilder()
-                                   .Set("name", name)
-                                   .Set("description", "an extension")
-                                   .Set("manifest_version", 2)
-                                   .Set("version", "1.0.0")
-                                   .Set("permissions", permissions))
-                          .SetLocation(Manifest::INTERNAL)
-                          .SetID(kId)
-                          .Build();
+        ExtensionBuilder()
+            .SetManifest(DictionaryBuilder()
+                             .Set("name", name)
+                             .Set("description", "an extension")
+                             .Set("manifest_version", 2)
+                             .Set("version", "1.0.0")
+                             .Set("permissions", std::move(permissions)))
+            .SetLocation(Manifest::INTERNAL)
+            .SetID(kId)
+            .Build();
 
     ExtensionRegistry::Get(profile())->AddEnabled(extension);
     PermissionsUpdater(profile()).InitializePermissions(extension.get());
@@ -177,12 +179,13 @@
   const char kVersion[] = "1.0.0.1";
   std::string id = crx_file::id_util::GenerateId("alpha");
   scoped_ptr<base::DictionaryValue> manifest =
-      DictionaryBuilder().Set("name", kName)
-                         .Set("version", kVersion)
-                         .Set("manifest_version", 2)
-                         .Set("description", "an extension")
-                         .Set("permissions",
-                              ListBuilder().Append("file://*/*")).Build();
+      DictionaryBuilder()
+          .Set("name", kName)
+          .Set("version", kVersion)
+          .Set("manifest_version", 2)
+          .Set("description", "an extension")
+          .Set("permissions", std::move(ListBuilder().Append("file://*/*")))
+          .Build();
   scoped_ptr<base::DictionaryValue> manifest_copy(manifest->DeepCopy());
   scoped_refptr<const Extension> extension =
       ExtensionBuilder().SetManifest(manifest.Pass())
@@ -345,9 +348,9 @@
           FeatureSwitch::scripts_require_action(), true));
   // Two extensions - one with all urls, one without.
   scoped_refptr<const Extension> all_urls_extension = CreateExtension(
-      "all_urls", ListBuilder().Append(kAllHostsPermission).Pass());
+      "all_urls", std::move(ListBuilder().Append(kAllHostsPermission)));
   scoped_refptr<const Extension> no_urls_extension =
-      CreateExtension("no urls", ListBuilder().Pass());
+      CreateExtension("no urls", ListBuilder());
 
   scoped_ptr<developer::ExtensionInfo> info =
       GenerateExtensionInfo(all_urls_extension->id());
@@ -392,7 +395,7 @@
 
   // Load another extension with all urls (so permissions get re-init'd).
   all_urls_extension = CreateExtension(
-      "all_urls_II", ListBuilder().Append(kAllHostsPermission).Pass());
+      "all_urls_II", std::move(ListBuilder().Append(kAllHostsPermission)));
 
   // Even though the extension has all_urls permission, the checkbox shouldn't
   // show up without the switch.
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
index 5e03a09..08d0005 100644
--- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
+++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
@@ -42,6 +42,7 @@
 #include "components/proximity_auth/screenlock_bridge.h"
 #include "components/proximity_auth/screenlock_state.h"
 #include "components/proximity_auth/switches.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/browser_context_keyed_api_factory.h"
@@ -841,7 +842,7 @@
       return false;
     }
     key_manager->SignUsingTpmKey(
-        EasyUnlockService::Get(profile)->GetUserEmail(),
+        EasyUnlockService::Get(profile)->GetAccountId(),
         std::string(params->nonce.begin(), params->nonce.end()),
         base::Bind(&EasyUnlockPrivateGetSignInChallengeFunction::OnDone, this,
                    challenge));
@@ -893,22 +894,22 @@
   EasyUnlockService* service =
       EasyUnlockService::Get(Profile::FromBrowserContext(browser_context()));
   std::vector<linked_ptr<easy_unlock_private::UserInfo> > users;
-  std::string user_id = service->GetUserEmail();
-  if (!user_id.empty()) {
+  const AccountId& account_id = service->GetAccountId();
+  if (account_id.is_valid()) {
     users.push_back(
         linked_ptr<easy_unlock_private::UserInfo>(
             new easy_unlock_private::UserInfo()));
-    users[0]->user_id = user_id;
+    users[0]->user_id = account_id.GetUserEmail();
     users[0]->logged_in = service->GetType() == EasyUnlockService::TYPE_REGULAR;
     users[0]->data_ready = users[0]->logged_in ||
                            service->GetRemoteDevices() != NULL;
 
     EasyUnlockService::UserSettings user_settings =
-        EasyUnlockService::GetUserSettings(user_id);
+        EasyUnlockService::GetUserSettings(account_id);
     users[0]->require_close_proximity = user_settings.require_close_proximity;
 
     users[0]->device_user_id = proximity_auth::CalculateDeviceUserId(
-        EasyUnlockService::GetDeviceId(), user_id);
+        EasyUnlockService::GetDeviceId(), account_id.GetUserEmail());
 
     users[0]->ble_discovery_enabled =
         base::CommandLine::ForCurrentProcess()->HasSwitch(
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc
index fceefe9..1475a57 100644
--- a/chrome/browser/extensions/api/identity/identity_apitest.cc
+++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -1657,17 +1657,14 @@
 
   scoped_refptr<Extension> CreateTestExtension(const std::string& id) {
     return ExtensionBuilder()
-        .SetManifest(
-             DictionaryBuilder()
-                 .Set("name", "Test")
-                 .Set("version", "1.0")
-                 .Set(
-                     "oauth2",
-                     DictionaryBuilder()
-                         .Set("client_id", "clientId")
-                         .Set(
-                             "scopes",
-                             ListBuilder().Append("scope1"))))
+        .SetManifest(DictionaryBuilder()
+                         .Set("name", "Test")
+                         .Set("version", "1.0")
+                         .Set("oauth2",
+                              DictionaryBuilder()
+                                  .Set("client_id", "clientId")
+                                  .Set("scopes", std::move(ListBuilder().Append(
+                                                     "scope1")))))
         .SetLocation(Manifest::UNPACKED)
         .SetID(id)
         .Build();
diff --git a/chrome/browser/extensions/api/identity/identity_signin_flow.cc b/chrome/browser/extensions/api/identity/identity_signin_flow.cc
index 74b5f35..6224083 100644
--- a/chrome/browser/extensions/api/identity/identity_signin_flow.cc
+++ b/chrome/browser/extensions/api/identity/identity_signin_flow.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/extensions/api/identity/identity_signin_flow.h"
 
-#include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
@@ -28,12 +27,11 @@
   DCHECK(delegate_);
 
 #if defined(OS_CHROMEOS)
-  // In normal mode (i.e. non-forced app mode), the user has to log out to
+  // In normal mode (i.e. non-kiosk mode), the user has to log out to
   // re-establish credentials. Let the global error popup handle everything.
-  if (!chrome::IsRunningInForcedAppMode()) {
-    delegate_->SigninFailed();
-    return;
-  }
+  // In kiosk mode, interactive sign-in is not supported.
+  delegate_->SigninFailed();
+  return;
 #endif
 
   ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->AddObserver(this);
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api.cc b/chrome/browser/extensions/api/input_ime/input_ime_api.cc
index d357cd4..261f212 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api.cc
@@ -5,457 +5,182 @@
 #include "chrome/browser/extensions/api/input_ime/input_ime_api.h"
 
 #include "base/strings/string_number_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/chromeos/input_method/input_method_engine.h"
-#include "chrome/browser/chromeos/login/lock/screen_locker.h"
-#include "chrome/browser/chromeos/login/session/user_session_manager.h"
-#include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/extensions/api/input_ime.h"
 #include "chrome/common/extensions/api/input_ime/input_components_handler.h"
-#include "extensions/browser/event_router.h"
-#include "extensions/browser/extension_function_registry.h"
 #include "extensions/browser/extension_registry.h"
-#include "extensions/browser/extension_system.h"
-#include "extensions/browser/process_manager.h"
-#include "extensions/common/manifest_handlers/background_info.h"
-#include "ui/base/ime/chromeos/component_extension_ime_manager.h"
-#include "ui/base/ime/chromeos/extension_ime_util.h"
-#include "ui/base/ime/chromeos/input_method_manager.h"
-#include "ui/base/ime/ime_engine_handler_interface.h"
-#include "ui/base/ime/text_input_flags.h"
 
 namespace input_ime = extensions::api::input_ime;
 namespace KeyEventHandled = extensions::api::input_ime::KeyEventHandled;
-namespace DeleteSurroundingText =
-    extensions::api::input_ime::DeleteSurroundingText;
-namespace UpdateMenuItems = extensions::api::input_ime::UpdateMenuItems;
-namespace SendKeyEvents = extensions::api::input_ime::SendKeyEvents;
-namespace HideInputView = extensions::api::input_ime::HideInputView;
-namespace SetMenuItems = extensions::api::input_ime::SetMenuItems;
-namespace SetCursorPosition = extensions::api::input_ime::SetCursorPosition;
-namespace SetCandidates = extensions::api::input_ime::SetCandidates;
-namespace SetCandidateWindowProperties =
-    extensions::api::input_ime::SetCandidateWindowProperties;
-namespace CommitText = extensions::api::input_ime::CommitText;
-namespace ClearComposition = extensions::api::input_ime::ClearComposition;
-namespace SetComposition = extensions::api::input_ime::SetComposition;
 using ui::IMEEngineHandlerInterface;
 
-namespace {
+namespace ui {
 
-const char kErrorEngineNotAvailable[] = "Engine is not available";
-const char kErrorSetMenuItemsFail[] = "Could not create menu Items";
-const char kErrorUpdateMenuItemsFail[] = "Could not update menu Items";
-const char kOnCompositionBoundsChangedEventName[] =
-    "inputMethodPrivate.onCompositionBoundsChanged";
+ImeObserver::ImeObserver(const std::string& extension_id, Profile* profile)
+    : extension_id_(extension_id), profile_(profile) {}
 
-void SetMenuItemToMenu(const input_ime::MenuItem& input,
-                       IMEEngineHandlerInterface::MenuItem* out) {
-  out->modified = 0;
-  out->id = input.id;
-  if (input.label) {
-    out->modified |= IMEEngineHandlerInterface::MENU_ITEM_MODIFIED_LABEL;
-    out->label = *input.label;
-  }
+void ImeObserver::OnFocus(
+    const IMEEngineHandlerInterface::InputContext& context) {
+  if (extension_id_.empty() || !HasListener(input_ime::OnFocus::kEventName))
+    return;
 
-  if (input.style != input_ime::MENU_ITEM_STYLE_NONE) {
-    out->modified |= IMEEngineHandlerInterface::MENU_ITEM_MODIFIED_STYLE;
-    out->style =
-        static_cast<IMEEngineHandlerInterface::MenuItemStyle>(input.style);
-  }
+  input_ime::InputContext context_value;
+  context_value.context_id = context.id;
+  context_value.type =
+      input_ime::ParseInputContextType(ConvertInputContextType(context));
+  context_value.auto_correct = ConvertInputContextAutoCorrect(context);
+  context_value.auto_complete = ConvertInputContextAutoComplete(context);
+  context_value.spell_check = ConvertInputContextSpellCheck(context);
 
-  if (input.visible)
-    out->modified |= IMEEngineHandlerInterface::MENU_ITEM_MODIFIED_VISIBLE;
-  out->visible = input.visible ? *input.visible : true;
+  scoped_ptr<base::ListValue> args(input_ime::OnFocus::Create(context_value));
 
-  if (input.checked)
-    out->modified |= IMEEngineHandlerInterface::MENU_ITEM_MODIFIED_CHECKED;
-  out->checked = input.checked ? *input.checked : false;
-
-  if (input.enabled)
-    out->modified |= IMEEngineHandlerInterface::MENU_ITEM_MODIFIED_ENABLED;
-  out->enabled = input.enabled ? *input.enabled : true;
+  DispatchEventToExtension(extensions::events::INPUT_IME_ON_FOCUS,
+                           input_ime::OnFocus::kEventName, args.Pass());
 }
 
-extensions::InputImeEventRouter* GetInputImeEventRouter(Profile* profile) {
-  if (profile->HasOffTheRecordProfile())
-    profile = profile->GetOffTheRecordProfile();
-  return extensions::InputImeEventRouterFactory::GetInstance()->GetRouter(
-      profile);
+void ImeObserver::OnBlur(int context_id) {
+  if (extension_id_.empty() || !HasListener(input_ime::OnBlur::kEventName))
+    return;
+
+  scoped_ptr<base::ListValue> args(input_ime::OnBlur::Create(context_id));
+
+  DispatchEventToExtension(extensions::events::INPUT_IME_ON_BLUR,
+                           input_ime::OnBlur::kEventName, args.Pass());
 }
 
-}  // namespace
+void ImeObserver::OnKeyEvent(
+    const std::string& component_id,
+    const IMEEngineHandlerInterface::KeyboardEvent& event,
+    IMEEngineHandlerInterface::KeyEventDoneCallback& key_data) {
+  if (extension_id_.empty())
+    return;
 
-namespace chromeos {
-class ImeObserver : public ui::IMEEngineObserver {
- public:
-  explicit ImeObserver(const std::string& extension_id, Profile* profile)
-      : extension_id_(extension_id), profile_(profile) {}
-
-  ~ImeObserver() override {}
-
-  void OnActivate(const std::string& component_id) override {
-    if (extension_id_.empty() ||
-        !HasListener(input_ime::OnActivate::kEventName))
-      return;
-
-    scoped_ptr<base::ListValue> args(input_ime::OnActivate::Create(
-        component_id,
-        input_ime::ParseScreenType(GetCurrentScreenType())));
-
-    DispatchEventToExtension(extensions::events::INPUT_IME_ON_ACTIVATE,
-                             input_ime::OnActivate::kEventName, args.Pass());
+  // If there is no listener for the event, no need to dispatch the event to
+  // extension. Instead, releases the key event for default system behavior.
+  if (!ShouldForwardKeyEvent()) {
+    // Continue processing the key event so that the physical keyboard can
+    // still work.
+    key_data.Run(false);
+    return;
   }
 
-  void OnDeactivated(const std::string& component_id) override {
-    if (extension_id_.empty() ||
-        !HasListener(input_ime::OnDeactivated::kEventName))
-      return;
+  const std::string request_id = extensions::GetInputImeEventRouter(profile_)
+                                     ->AddRequest(component_id, key_data);
 
-    scoped_ptr<base::ListValue> args(
-        input_ime::OnDeactivated::Create(component_id));
-
-    DispatchEventToExtension(extensions::events::INPUT_IME_ON_DEACTIVATED,
-                             input_ime::OnDeactivated::kEventName, args.Pass());
-  }
-
-  void OnFocus(
-      const IMEEngineHandlerInterface::InputContext& context) override {
-    if (extension_id_.empty() || !HasListener(input_ime::OnFocus::kEventName))
-      return;
-
-    input_ime::InputContext context_value;
-    context_value.context_id = context.id;
-    context_value.type =
-        input_ime::ParseInputContextType(ConvertInputContextType(context));
-    context_value.auto_correct = ConvertInputContextAutoCorrect(context);
-    context_value.auto_complete = ConvertInputContextAutoComplete(context);
-    context_value.spell_check = ConvertInputContextSpellCheck(context);
-
-    scoped_ptr<base::ListValue> args(input_ime::OnFocus::Create(context_value));
-
-    DispatchEventToExtension(extensions::events::INPUT_IME_ON_FOCUS,
-                             input_ime::OnFocus::kEventName, args.Pass());
-  }
-
-  void OnBlur(int context_id) override {
-    if (extension_id_.empty() || !HasListener(input_ime::OnBlur::kEventName))
-      return;
-
-    scoped_ptr<base::ListValue> args(input_ime::OnBlur::Create(context_id));
-
-    DispatchEventToExtension(extensions::events::INPUT_IME_ON_BLUR,
-                             input_ime::OnBlur::kEventName, args.Pass());
-  }
-
-  void OnInputContextUpdate(
-      const IMEEngineHandlerInterface::InputContext& context) override {
-    if (extension_id_.empty() ||
-        !HasListener(input_ime::OnInputContextUpdate::kEventName))
-      return;
-
-    input_ime::InputContext context_value;
-    context_value.context_id = context.id;
-    context_value.type =
-        input_ime::ParseInputContextType(ConvertInputContextType(context));
-
-    scoped_ptr<base::ListValue> args(
-        input_ime::OnInputContextUpdate::Create(context_value));
-
-    DispatchEventToExtension(
-        extensions::events::INPUT_IME_ON_INPUT_CONTEXT_UPDATE,
-        input_ime::OnInputContextUpdate::kEventName, args.Pass());
-  }
-
-  bool IsInterestedInKeyEvent() const override {
-    return ShouldForwardKeyEvent();
-  }
-
-  void OnKeyEvent(
-      const std::string& component_id,
-      const IMEEngineHandlerInterface::KeyboardEvent& event,
-      IMEEngineHandlerInterface::KeyEventDoneCallback& key_data) override {
-    if (extension_id_.empty())
-      return;
-
-    // If there is no listener for the event, no need to dispatch the event to
-    // extension. Instead, releases the key event for default system behavior.
-    if (!ShouldForwardKeyEvent()) {
-      // Continue processing the key event so that the physical keyboard can
-      // still work.
-      key_data.Run(false);
-      return;
-    }
-
-    const std::string request_id =
-        GetInputImeEventRouter(profile_)->AddRequest(component_id, key_data);
-
-    input_ime::KeyboardEvent key_data_value;
-    key_data_value.type = input_ime::ParseKeyboardEventType(event.type);
-    key_data_value.request_id = request_id;
-    if (!event.extension_id.empty())
+  input_ime::KeyboardEvent key_data_value;
+  key_data_value.type = input_ime::ParseKeyboardEventType(event.type);
+  key_data_value.request_id = request_id;
+  if (!event.extension_id.empty())
       key_data_value.extension_id.reset(new std::string(event.extension_id));
-    key_data_value.key = event.key;
-    key_data_value.code = event.code;
-    key_data_value.alt_key.reset(new bool(event.alt_key));
-    key_data_value.ctrl_key.reset(new bool(event.ctrl_key));
-    key_data_value.shift_key.reset(new bool(event.shift_key));
-    key_data_value.caps_lock.reset(new bool(event.caps_lock));
+  key_data_value.key = event.key;
+  key_data_value.code = event.code;
+  key_data_value.alt_key.reset(new bool(event.alt_key));
+  key_data_value.ctrl_key.reset(new bool(event.ctrl_key));
+  key_data_value.shift_key.reset(new bool(event.shift_key));
+  key_data_value.caps_lock.reset(new bool(event.caps_lock));
 
-    scoped_ptr<base::ListValue> args(
-        input_ime::OnKeyEvent::Create(component_id, key_data_value));
+  scoped_ptr<base::ListValue> args(
+      input_ime::OnKeyEvent::Create(component_id, key_data_value));
 
-    DispatchEventToExtension(extensions::events::INPUT_IME_ON_KEY_EVENT,
-                             input_ime::OnKeyEvent::kEventName, args.Pass());
+  DispatchEventToExtension(extensions::events::INPUT_IME_ON_KEY_EVENT,
+                           input_ime::OnKeyEvent::kEventName, args.Pass());
+}
+
+void ImeObserver::OnReset(const std::string& component_id) {
+  if (extension_id_.empty() || !HasListener(input_ime::OnReset::kEventName))
+    return;
+
+  scoped_ptr<base::ListValue> args(input_ime::OnReset::Create(component_id));
+
+  DispatchEventToExtension(extensions::events::INPUT_IME_ON_RESET,
+                           input_ime::OnReset::kEventName, args.Pass());
+}
+
+void ImeObserver::OnDeactivated(const std::string& component_id) {
+  if (extension_id_.empty() ||
+      !HasListener(input_ime::OnDeactivated::kEventName))
+    return;
+
+  scoped_ptr<base::ListValue> args(
+      input_ime::OnDeactivated::Create(component_id));
+
+  DispatchEventToExtension(extensions::events::INPUT_IME_ON_DEACTIVATED,
+                           input_ime::OnDeactivated::kEventName, args.Pass());
+}
+
+// TODO(azurewei): This function implementation should be shared on all
+// platforms, while with some changing on the current code on ChromeOS.
+void ImeObserver::OnCompositionBoundsChanged(
+    const std::vector<gfx::Rect>& bounds) {}
+
+bool ImeObserver::ShouldForwardKeyEvent() const {
+  // Only forward key events to extension if there are non-lazy listeners
+  // for onKeyEvent. Because if something wrong with the lazy background
+  // page which doesn't register listener for onKeyEvent, it will not handle
+  // the key events, and therefore, all key events will be eaten.
+  // This is for error-tolerance, and it means that onKeyEvent will never wake
+  // up lazy background page.
+  const extensions::EventListenerMap::ListenerList& listener_list =
+      extensions::EventRouter::Get(profile_)
+          ->listeners()
+          .GetEventListenersByName(input_ime::OnKeyEvent::kEventName);
+  for (extensions::EventListenerMap::ListenerList::const_iterator it =
+           listener_list.begin();
+       it != listener_list.end(); ++it) {
+    if ((*it)->extension_id() == extension_id_ && !(*it)->IsLazy())
+      return true;
   }
+  return false;
+}
 
-  void OnCandidateClicked(
-      const std::string& component_id,
-      int candidate_id,
-      ui::IMEEngineObserver::MouseButtonEvent button) override {
-    if (extension_id_.empty() ||
-        !HasListener(input_ime::OnCandidateClicked::kEventName))
-      return;
+bool ImeObserver::HasListener(const std::string& event_name) const {
+  return extensions::EventRouter::Get(profile_)->HasEventListener(event_name);
+}
 
-    input_ime::MouseButton button_enum = input_ime::MOUSE_BUTTON_NONE;
-    switch (button) {
-      case ui::IMEEngineObserver::MOUSE_BUTTON_MIDDLE:
-        button_enum = input_ime::MOUSE_BUTTON_MIDDLE;
-        break;
-
-      case ui::IMEEngineObserver::MOUSE_BUTTON_RIGHT:
-        button_enum = input_ime::MOUSE_BUTTON_RIGHT;
-        break;
-
-      case ui::IMEEngineObserver::MOUSE_BUTTON_LEFT:
-      // Default to left.
-      default:
-        button_enum = input_ime::MOUSE_BUTTON_LEFT;
-        break;
-    }
-
-    scoped_ptr<base::ListValue> args(input_ime::OnCandidateClicked::Create(
-        component_id, candidate_id, button_enum));
-
-    DispatchEventToExtension(extensions::events::INPUT_IME_ON_CANDIDATE_CLICKED,
-                             input_ime::OnCandidateClicked::kEventName,
-                             args.Pass());
+std::string ImeObserver::ConvertInputContextType(
+    ui::IMEEngineHandlerInterface::InputContext input_context) {
+  std::string input_context_type = "text";
+  switch (input_context.type) {
+    case ui::TEXT_INPUT_TYPE_SEARCH:
+      input_context_type = "search";
+      break;
+    case ui::TEXT_INPUT_TYPE_TELEPHONE:
+      input_context_type = "tel";
+      break;
+    case ui::TEXT_INPUT_TYPE_URL:
+      input_context_type = "url";
+      break;
+    case ui::TEXT_INPUT_TYPE_EMAIL:
+      input_context_type = "email";
+      break;
+    case ui::TEXT_INPUT_TYPE_NUMBER:
+      input_context_type = "number";
+      break;
+    case ui::TEXT_INPUT_TYPE_PASSWORD:
+      input_context_type = "password";
+      break;
+    default:
+      input_context_type = "text";
+      break;
   }
+  return input_context_type;
+}
 
-  void OnMenuItemActivated(const std::string& component_id,
-                           const std::string& menu_id) override {
-    if (extension_id_.empty() ||
-        !HasListener(input_ime::OnMenuItemActivated::kEventName))
-      return;
+bool ImeObserver::ConvertInputContextAutoCorrect(
+    ui::IMEEngineHandlerInterface::InputContext input_context) {
+  return !(input_context.flags & ui::TEXT_INPUT_FLAG_AUTOCORRECT_OFF);
+}
 
-    scoped_ptr<base::ListValue> args(
-        input_ime::OnMenuItemActivated::Create(component_id, menu_id));
+bool ImeObserver::ConvertInputContextAutoComplete(
+    ui::IMEEngineHandlerInterface::InputContext input_context) {
+  return !(input_context.flags & ui::TEXT_INPUT_FLAG_AUTOCOMPLETE_OFF);
+}
 
-    DispatchEventToExtension(
-        extensions::events::INPUT_IME_ON_MENU_ITEM_ACTIVATED,
-        input_ime::OnMenuItemActivated::kEventName, args.Pass());
-  }
+bool ImeObserver::ConvertInputContextSpellCheck(
+    ui::IMEEngineHandlerInterface::InputContext input_context) {
+  return !(input_context.flags & ui::TEXT_INPUT_FLAG_SPELLCHECK_OFF);
+}
 
-  void OnSurroundingTextChanged(const std::string& component_id,
-                                const std::string& text,
-                                int cursor_pos,
-                                int anchor_pos,
-                                int offset_pos) override {
-    if (extension_id_.empty() ||
-        !HasListener(input_ime::OnSurroundingTextChanged::kEventName))
-      return;
-
-    input_ime::OnSurroundingTextChanged::SurroundingInfo info;
-    info.text = text;
-    info.focus = cursor_pos;
-    info.anchor = anchor_pos;
-    info.offset = offset_pos;
-    scoped_ptr<base::ListValue> args(
-        input_ime::OnSurroundingTextChanged::Create(component_id, info));
-
-    DispatchEventToExtension(
-        extensions::events::INPUT_IME_ON_SURROUNDING_TEXT_CHANGED,
-        input_ime::OnSurroundingTextChanged::kEventName, args.Pass());
-  }
-
-  void OnCompositionBoundsChanged(
-      const std::vector<gfx::Rect>& bounds) override {
-    if (extension_id_.empty() ||
-        !HasListener(kOnCompositionBoundsChangedEventName))
-      return;
-
-    // Note: this is a private API event.
-    base::ListValue* bounds_list = new base::ListValue();
-    for (size_t i = 0; i < bounds.size(); ++i) {
-      base::DictionaryValue* bounds_value = new base::DictionaryValue();
-      bounds_value->SetInteger("x", bounds[i].x());
-      bounds_value->SetInteger("y", bounds[i].y());
-      bounds_value->SetInteger("w", bounds[i].width());
-      bounds_value->SetInteger("h", bounds[i].height());
-      bounds_list->Append(bounds_value);
-    }
-
-    if (bounds_list->GetSize() <= 0)
-      return;
-    scoped_ptr<base::ListValue> args(new base::ListValue());
-
-    // The old extension code uses the first parameter to get the bounds of the
-    // first composition character, so for backward compatibility, add it here.
-    base::Value* first_value = NULL;
-    if (bounds_list->Get(0, &first_value))
-      args->Append(first_value->DeepCopy());
-    args->Append(bounds_list);
-
-    DispatchEventToExtension(
-        extensions::events::INPUT_METHOD_PRIVATE_ON_COMPOSITION_BOUNDS_CHANGED,
-        kOnCompositionBoundsChangedEventName, args.Pass());
-  }
-
-  void OnReset(const std::string& component_id) override {
-    if (extension_id_.empty() || !HasListener(input_ime::OnReset::kEventName))
-      return;
-
-    scoped_ptr<base::ListValue> args(input_ime::OnReset::Create(component_id));
-
-    DispatchEventToExtension(extensions::events::INPUT_IME_ON_RESET,
-                             input_ime::OnReset::kEventName, args.Pass());
-  }
-
-  std::string ConvertInputContextType(
-      ui::IMEEngineHandlerInterface::InputContext input_context) {
-    std::string input_context_type = "text";
-    switch (input_context.type) {
-      case ui::TEXT_INPUT_TYPE_SEARCH:
-        input_context_type = "search";
-        break;
-      case ui::TEXT_INPUT_TYPE_TELEPHONE:
-        input_context_type = "tel";
-        break;
-      case ui::TEXT_INPUT_TYPE_URL:
-        input_context_type = "url";
-        break;
-      case ui::TEXT_INPUT_TYPE_EMAIL:
-        input_context_type = "email";
-        break;
-      case ui::TEXT_INPUT_TYPE_NUMBER:
-        input_context_type = "number";
-        break;
-      case ui::TEXT_INPUT_TYPE_PASSWORD:
-        input_context_type = "password";
-        break;
-      default:
-        input_context_type = "text";
-        break;
-    }
-    return input_context_type;
-  }
-
-  bool ConvertInputContextAutoCorrect(
-      ui::IMEEngineHandlerInterface::InputContext input_context) {
-    return !(input_context.flags & ui::TEXT_INPUT_FLAG_AUTOCORRECT_OFF);
-  }
-
-  bool ConvertInputContextAutoComplete(
-      ui::IMEEngineHandlerInterface::InputContext input_context) {
-    return !(input_context.flags & ui::TEXT_INPUT_FLAG_AUTOCOMPLETE_OFF);
-  }
-
-  bool ConvertInputContextSpellCheck(
-      ui::IMEEngineHandlerInterface::InputContext input_context) {
-    return !(input_context.flags & ui::TEXT_INPUT_FLAG_SPELLCHECK_OFF);
-  }
-
- private:
-  void DispatchEventToExtension(
-      extensions::events::HistogramValue histogram_value,
-      const std::string& event_name,
-      scoped_ptr<base::ListValue> args) {
-    if (event_name != input_ime::OnActivate::kEventName) {
-      // For suspended IME extension (e.g. XKB extension), don't awake it by IME
-      // events except onActivate. The IME extension should be awake by other
-      // events (e.g. runtime.onMessage) from its other pages.
-      // This is to save memory for steady state Chrome OS on which the users
-      // don't want any IME features.
-      extensions::ExtensionSystem* extension_system =
-          extensions::ExtensionSystem::Get(profile_);
-      if (extension_system) {
-        const extensions::Extension* extension =
-            extension_system->extension_service()->GetExtensionById(
-                extension_id_, false /* include_disabled */);
-        if (!extension)
-          return;
-        extensions::ProcessManager* process_manager =
-            extensions::ProcessManager::Get(profile_);
-        if (extensions::BackgroundInfo::HasBackgroundPage(extension) &&
-            !process_manager->GetBackgroundHostForExtension(extension_id_)) {
-          return;
-        }
-      }
-    }
-
-    scoped_ptr<extensions::Event> event(
-        new extensions::Event(histogram_value, event_name, args.Pass()));
-    event->restrict_to_browser_context = profile_;
-    extensions::EventRouter::Get(profile_)
-        ->DispatchEventToExtension(extension_id_, event.Pass());
-  }
-
-  // Returns true if the extension is ready to accept key event, otherwise
-  // returns false.
-  bool ShouldForwardKeyEvent() const {
-    // Only forward key events to extension if there are non-lazy listeners
-    // for onKeyEvent. Because if something wrong with the lazy background
-    // page which doesn't register listener for onKeyEvent, it will not handle
-    // the key events, and therefore, all key events will be eaten.
-    // This is for error-tolerance, and it means that onKeyEvent will never wake
-    // up lazy background page.
-    const extensions::EventListenerMap::ListenerList& listener_list =
-        extensions::EventRouter::Get(profile_)
-            ->listeners()
-            .GetEventListenersByName(input_ime::OnKeyEvent::kEventName);
-    for (extensions::EventListenerMap::ListenerList::const_iterator it =
-             listener_list.begin();
-         it != listener_list.end(); ++it) {
-      if ((*it)->extension_id() == extension_id_ && !(*it)->IsLazy())
-        return true;
-    }
-    return false;
-  }
-
-  bool HasListener(const std::string& event_name) const {
-    return extensions::EventRouter::Get(profile_)->HasEventListener(event_name);
-  }
-
-  // The component IME extensions need to know the current screen type (e.g.
-  // lock screen, login screen, etc.) so that its on-screen keyboard page
-  // won't open new windows/pages. See crbug.com/395621.
-  std::string GetCurrentScreenType() {
-    switch (chromeos::input_method::InputMethodManager::Get()
-                ->GetUISessionState()) {
-      case chromeos::input_method::InputMethodManager::STATE_LOGIN_SCREEN:
-        return "login";
-      case chromeos::input_method::InputMethodManager::STATE_LOCK_SCREEN:
-        return "lock";
-      case chromeos::input_method::InputMethodManager::STATE_BROWSER_SCREEN:
-        return UserAddingScreen::Get()->IsRunning() ? "secondary-login"
-                                                    : "normal";
-      case chromeos::input_method::InputMethodManager::STATE_TERMINATING:
-        return "normal";
-    }
-    NOTREACHED() << "New screen type is added. Please add new entry above.";
-    return "normal";
-  }
-
-  std::string extension_id_;
-  Profile* profile_;
-
-  DISALLOW_COPY_AND_ASSIGN(ImeObserver);
-};
-
-}  // namespace chromeos
+}  // namespace ui
 
 namespace extensions {
 
@@ -485,74 +210,6 @@
 InputImeEventRouter::~InputImeEventRouter() {
 }
 
-bool InputImeEventRouter::RegisterImeExtension(
-    const std::string& extension_id,
-    const std::vector<extensions::InputComponentInfo>& input_components) {
-  VLOG(1) << "RegisterImeExtension: " << extension_id;
-
-  if (engine_map_[extension_id])
-    return false;
-
-  chromeos::input_method::InputMethodManager* manager =
-      chromeos::input_method::InputMethodManager::Get();
-  chromeos::ComponentExtensionIMEManager* comp_ext_ime_manager =
-      manager->GetComponentExtensionIMEManager();
-
-  chromeos::input_method::InputMethodDescriptors descriptors;
-  // Only creates descriptors for 3rd party IME extension, because the
-  // descriptors for component IME extensions are managed by InputMethodUtil.
-  if (!comp_ext_ime_manager->IsWhitelistedExtension(extension_id)) {
-    for (std::vector<extensions::InputComponentInfo>::const_iterator it =
-             input_components.begin();
-         it != input_components.end();
-         ++it) {
-      const extensions::InputComponentInfo& component = *it;
-      DCHECK(component.type == extensions::INPUT_COMPONENT_TYPE_IME);
-
-      std::vector<std::string> layouts;
-      layouts.assign(component.layouts.begin(), component.layouts.end());
-      std::vector<std::string> languages;
-      languages.assign(component.languages.begin(), component.languages.end());
-
-      const std::string& input_method_id =
-          chromeos::extension_ime_util::GetInputMethodID(extension_id,
-                                                         component.id);
-      descriptors.push_back(chromeos::input_method::InputMethodDescriptor(
-          input_method_id,
-          component.name,
-          std::string(),  // TODO(uekawa): Set short name.
-          layouts,
-          languages,
-          false,  // 3rd party IMEs are always not for login.
-          component.options_page_url,
-          component.input_view_url));
-    }
-  }
-
-  scoped_ptr<ui::IMEEngineObserver> observer(
-      new chromeos::ImeObserver(extension_id, profile_));
-  chromeos::InputMethodEngine* engine = new chromeos::InputMethodEngine();
-  engine->Initialize(observer.Pass(), extension_id.c_str(), profile_);
-  engine_map_[extension_id] = engine;
-  chromeos::UserSessionManager::GetInstance()
-      ->GetDefaultIMEState(profile_)
-      ->AddInputMethodExtension(extension_id, descriptors, engine);
-
-  return true;
-}
-
-void InputImeEventRouter::UnregisterAllImes(const std::string& extension_id) {
-  std::map<std::string, IMEEngineHandlerInterface*>::iterator it =
-      engine_map_.find(extension_id);
-  if (it != engine_map_.end()) {
-    chromeos::input_method::InputMethodManager::Get()
-        ->GetActiveIMEState()
-        ->RemoveInputMethodExtension(extension_id);
-    delete it->second;
-    engine_map_.erase(it);
-  }
-}
-
 IMEEngineHandlerInterface* InputImeEventRouter::GetEngine(
     const std::string& extension_id,
     const std::string& component_id) {
@@ -598,344 +255,6 @@
   return request_id;
 }
 
-bool InputImeSetCompositionFunction::RunSync() {
-  IMEEngineHandlerInterface* engine =
-      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
-          ->GetActiveEngine(extension_id());
-  if (!engine) {
-    SetResult(new base::FundamentalValue(false));
-    return true;
-  }
-
-  scoped_ptr<SetComposition::Params> parent_params(
-      SetComposition::Params::Create(*args_));
-  const SetComposition::Params::Parameters& params = parent_params->parameters;
-  std::vector<IMEEngineHandlerInterface::SegmentInfo> segments;
-  if (params.segments) {
-    const std::vector<linked_ptr<
-        SetComposition::Params::Parameters::SegmentsType> >&
-            segments_args = *params.segments;
-    for (size_t i = 0; i < segments_args.size(); ++i) {
-      EXTENSION_FUNCTION_VALIDATE(
-          segments_args[i]->style !=
-          input_ime::UNDERLINE_STYLE_NONE);
-      segments.push_back(IMEEngineHandlerInterface::SegmentInfo());
-      segments.back().start = segments_args[i]->start;
-      segments.back().end = segments_args[i]->end;
-      if (segments_args[i]->style ==
-          input_ime::UNDERLINE_STYLE_UNDERLINE) {
-        segments.back().style =
-            IMEEngineHandlerInterface::SEGMENT_STYLE_UNDERLINE;
-      } else if (segments_args[i]->style ==
-                 input_ime::UNDERLINE_STYLE_DOUBLEUNDERLINE) {
-        segments.back().style =
-            IMEEngineHandlerInterface::SEGMENT_STYLE_DOUBLE_UNDERLINE;
-      } else {
-        segments.back().style =
-            IMEEngineHandlerInterface::SEGMENT_STYLE_NO_UNDERLINE;
-      }
-    }
-  }
-
-  int selection_start =
-      params.selection_start ? *params.selection_start : params.cursor;
-  int selection_end =
-      params.selection_end ? *params.selection_end : params.cursor;
-
-  SetResult(new base::FundamentalValue(
-      engine->SetComposition(params.context_id, params.text.c_str(),
-                             selection_start, selection_end, params.cursor,
-                             segments, &error_)));
-  return true;
-}
-
-bool InputImeClearCompositionFunction::RunSync() {
-  IMEEngineHandlerInterface* engine =
-      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
-          ->GetActiveEngine(extension_id());
-  if (!engine) {
-    SetResult(new base::FundamentalValue(false));
-    return true;
-  }
-
-  scoped_ptr<ClearComposition::Params> parent_params(
-      ClearComposition::Params::Create(*args_));
-  const ClearComposition::Params::Parameters& params =
-      parent_params->parameters;
-
-  SetResult(new base::FundamentalValue(
-      engine->ClearComposition(params.context_id, &error_)));
-  return true;
-}
-
-bool InputImeCommitTextFunction::RunSync() {
-  IMEEngineHandlerInterface* engine =
-      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
-          ->GetActiveEngine(extension_id());
-  if (!engine) {
-    SetResult(new base::FundamentalValue(false));
-    return true;
-  }
-
-  scoped_ptr<CommitText::Params> parent_params(
-      CommitText::Params::Create(*args_));
-  const CommitText::Params::Parameters& params =
-      parent_params->parameters;
-
-  SetResult(new base::FundamentalValue(
-      engine->CommitText(params.context_id, params.text.c_str(), &error_)));
-  return true;
-}
-
-bool InputImeHideInputViewFunction::RunAsync() {
-  IMEEngineHandlerInterface* engine =
-      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
-          ->GetActiveEngine(extension_id());
-  if (!engine) {
-    return true;
-  }
-  engine->HideInputView();
-  return true;
-}
-
-bool InputImeSendKeyEventsFunction::RunAsync() {
-  scoped_ptr<SendKeyEvents::Params> parent_params(
-      SendKeyEvents::Params::Create(*args_));
-  const SendKeyEvents::Params::Parameters& params =
-      parent_params->parameters;
-  IMEEngineHandlerInterface* engine =
-      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
-          ->GetActiveEngine(extension_id());
-  if (!engine) {
-    error_ = kErrorEngineNotAvailable;
-    return false;
-  }
-
-  const std::vector<linked_ptr<input_ime::KeyboardEvent> >& key_data =
-      params.key_data;
-  std::vector<IMEEngineHandlerInterface::KeyboardEvent> key_data_out;
-
-  for (size_t i = 0; i < key_data.size(); ++i) {
-    IMEEngineHandlerInterface::KeyboardEvent event;
-    event.type = input_ime::ToString(key_data[i]->type);
-    event.key = key_data[i]->key;
-    event.code = key_data[i]->code;
-    event.key_code = key_data[i]->key_code.get() ? *(key_data[i]->key_code) : 0;
-    if (key_data[i]->alt_key)
-      event.alt_key = *(key_data[i]->alt_key);
-    if (key_data[i]->ctrl_key)
-      event.ctrl_key = *(key_data[i]->ctrl_key);
-    if (key_data[i]->shift_key)
-      event.shift_key = *(key_data[i]->shift_key);
-    if (key_data[i]->caps_lock)
-      event.caps_lock = *(key_data[i]->caps_lock);
-    key_data_out.push_back(event);
-  }
-
-  engine->SendKeyEvents(params.context_id, key_data_out);
-  return true;
-}
-
-bool InputImeSetCandidateWindowPropertiesFunction::RunSync() {
-  scoped_ptr<SetCandidateWindowProperties::Params> parent_params(
-      SetCandidateWindowProperties::Params::Create(*args_));
-  const SetCandidateWindowProperties::Params::Parameters&
-      params = parent_params->parameters;
-
-  IMEEngineHandlerInterface* engine =
-      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
-          ->GetEngine(extension_id(), params.engine_id);
-  if (!engine) {
-    SetResult(new base::FundamentalValue(false));
-    return true;
-  }
-
-  const SetCandidateWindowProperties::Params::Parameters::Properties&
-      properties = params.properties;
-
-  if (properties.visible &&
-      !engine->SetCandidateWindowVisible(*properties.visible, &error_)) {
-    SetResult(new base::FundamentalValue(false));
-    return true;
-  }
-
-  IMEEngineHandlerInterface::CandidateWindowProperty properties_out =
-      engine->GetCandidateWindowProperty();
-  bool modified = false;
-
-  if (properties.cursor_visible) {
-    properties_out.is_cursor_visible = *properties.cursor_visible;
-    modified = true;
-  }
-
-  if (properties.vertical) {
-    properties_out.is_vertical = *properties.vertical;
-    modified = true;
-  }
-
-  if (properties.page_size) {
-    properties_out.page_size = *properties.page_size;
-    modified = true;
-  }
-
-  if (properties.window_position == input_ime::WINDOW_POSITION_COMPOSITION) {
-    properties_out.show_window_at_composition = true;
-    modified = true;
-  } else if (properties.window_position == input_ime::WINDOW_POSITION_CURSOR) {
-    properties_out.show_window_at_composition = false;
-    modified = true;
-  }
-
-  if (properties.auxiliary_text) {
-    properties_out.auxiliary_text = *properties.auxiliary_text;
-    modified = true;
-  }
-
-  if (properties.auxiliary_text_visible) {
-    properties_out.is_auxiliary_text_visible =
-        *properties.auxiliary_text_visible;
-    modified = true;
-  }
-
-  if (modified) {
-    engine->SetCandidateWindowProperty(properties_out);
-  }
-
-  SetResult(new base::FundamentalValue(true));
-
-  return true;
-}
-
-bool InputImeSetCandidatesFunction::RunSync() {
-  IMEEngineHandlerInterface* engine =
-      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
-          ->GetActiveEngine(extension_id());
-  if (!engine) {
-    SetResult(new base::FundamentalValue(false));
-    return true;
-  }
-
-  scoped_ptr<SetCandidates::Params> parent_params(
-      SetCandidates::Params::Create(*args_));
-  const SetCandidates::Params::Parameters& params =
-      parent_params->parameters;
-
-  std::vector<IMEEngineHandlerInterface::Candidate> candidates_out;
-  const std::vector<linked_ptr<
-      SetCandidates::Params::Parameters::CandidatesType> >& candidates_in =
-          params.candidates;
-  for (size_t i = 0; i < candidates_in.size(); ++i) {
-    candidates_out.push_back(IMEEngineHandlerInterface::Candidate());
-    candidates_out.back().value = candidates_in[i]->candidate;
-    candidates_out.back().id = candidates_in[i]->id;
-    if (candidates_in[i]->label)
-      candidates_out.back().label = *candidates_in[i]->label;
-    if (candidates_in[i]->annotation)
-      candidates_out.back().annotation = *candidates_in[i]->annotation;
-    if (candidates_in[i]->usage) {
-      candidates_out.back().usage.title = candidates_in[i]->usage->title;
-      candidates_out.back().usage.body = candidates_in[i]->usage->body;
-    }
-  }
-
-  SetResult(new base::FundamentalValue(
-      engine->SetCandidates(params.context_id, candidates_out, &error_)));
-  return true;
-}
-
-bool InputImeSetCursorPositionFunction::RunSync() {
-  IMEEngineHandlerInterface* engine =
-      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
-          ->GetActiveEngine(extension_id());
-  if (!engine) {
-    SetResult(new base::FundamentalValue(false));
-    return true;
-  }
-
-  scoped_ptr<SetCursorPosition::Params> parent_params(
-      SetCursorPosition::Params::Create(*args_));
-  const SetCursorPosition::Params::Parameters& params =
-      parent_params->parameters;
-
-  SetResult(new base::FundamentalValue(
-      engine->SetCursorPosition(params.context_id, params.candidate_id,
-                                &error_)));
-  return true;
-}
-
-bool InputImeSetMenuItemsFunction::RunSync() {
-  scoped_ptr<SetMenuItems::Params> parent_params(
-      SetMenuItems::Params::Create(*args_));
-  const SetMenuItems::Params::Parameters& params =
-      parent_params->parameters;
-
-  IMEEngineHandlerInterface* engine =
-      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
-          ->GetEngine(extension_id(), params.engine_id);
-  if (!engine) {
-    error_ = kErrorEngineNotAvailable;
-    return false;
-  }
-
-  const std::vector<linked_ptr<input_ime::MenuItem> >& items = params.items;
-  std::vector<IMEEngineHandlerInterface::MenuItem> items_out;
-
-  for (size_t i = 0; i < items.size(); ++i) {
-    items_out.push_back(IMEEngineHandlerInterface::MenuItem());
-    SetMenuItemToMenu(*items[i], &items_out.back());
-  }
-
-  if (!engine->SetMenuItems(items_out))
-    error_ = kErrorSetMenuItemsFail;
-  return true;
-}
-
-bool InputImeUpdateMenuItemsFunction::RunSync() {
-  scoped_ptr<UpdateMenuItems::Params> parent_params(
-      UpdateMenuItems::Params::Create(*args_));
-  const UpdateMenuItems::Params::Parameters& params =
-      parent_params->parameters;
-
-  IMEEngineHandlerInterface* engine =
-      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
-          ->GetEngine(extension_id(), params.engine_id);
-  if (!engine) {
-    error_ = kErrorEngineNotAvailable;
-    return false;
-  }
-
-  const std::vector<linked_ptr<input_ime::MenuItem> >& items = params.items;
-  std::vector<IMEEngineHandlerInterface::MenuItem> items_out;
-
-  for (size_t i = 0; i < items.size(); ++i) {
-    items_out.push_back(IMEEngineHandlerInterface::MenuItem());
-    SetMenuItemToMenu(*items[i], &items_out.back());
-  }
-
-  if (!engine->UpdateMenuItems(items_out))
-    error_ = kErrorUpdateMenuItemsFail;
-  return true;
-}
-
-bool InputImeDeleteSurroundingTextFunction::RunSync() {
-  scoped_ptr<DeleteSurroundingText::Params> parent_params(
-      DeleteSurroundingText::Params::Create(*args_));
-  const DeleteSurroundingText::Params::Parameters& params =
-      parent_params->parameters;
-
-  IMEEngineHandlerInterface* engine =
-      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
-          ->GetEngine(extension_id(), params.engine_id);
-  if (!engine) {
-    error_ = kErrorEngineNotAvailable;
-    return false;
-  }
-
-  engine->DeleteSurroundingText(params.context_id, params.offset, params.length,
-                                &error_);
-  return true;
-}
-
 bool InputImeKeyEventHandledFunction::RunAsync() {
   scoped_ptr<KeyEventHandled::Params> params(
       KeyEventHandled::Params::Create(*args_));
@@ -998,4 +317,11 @@
     engine->Enable(engine->GetActiveComponentId());
 }
 
+InputImeEventRouter* GetInputImeEventRouter(Profile* profile) {
+  if (profile->HasOffTheRecordProfile())
+    profile = profile->GetOffTheRecordProfile();
+  return extensions::InputImeEventRouterFactory::GetInstance()->GetRouter(
+      profile);
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api.h b/chrome/browser/extensions/api/input_ime/input_ime_api.h
index 031a359..d071c17 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api.h
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "base/macros.h"
 #include "base/memory/singleton.h"
 #include "base/scoped_observer.h"
 #include "base/values.h"
@@ -21,12 +22,67 @@
 #include "extensions/common/extension.h"
 #include "ui/base/ime/ime_engine_handler_interface.h"
 #include "ui/base/ime/ime_engine_observer.h"
+#include "ui/base/ime/text_input_flags.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h"
+#endif  // defined(OS_CHROMEOS)
 
 class Profile;
 
 namespace ui {
 class IMEEngineHandlerInterface;
 class IMEEngineObserver;
+
+class ImeObserver : public IMEEngineObserver {
+ public:
+  ImeObserver(const std::string& extension_id, Profile* profile);
+
+  ~ImeObserver() override {}
+
+  // IMEEngineObserver overrides.
+  void OnFocus(const IMEEngineHandlerInterface::InputContext& context) override;
+  void OnBlur(int context_id) override;
+  void OnKeyEvent(
+      const std::string& component_id,
+      const IMEEngineHandlerInterface::KeyboardEvent& event,
+      IMEEngineHandlerInterface::KeyEventDoneCallback& key_data) override;
+  void OnReset(const std::string& component_id) override;
+  void OnDeactivated(const std::string& component_id) override;
+  void OnCompositionBoundsChanged(
+      const std::vector<gfx::Rect>& bounds) override;
+
+ protected:
+  // Helper function used to forward the given event to the |profile_|'s event
+  // router, which dipatches the event the extension with |extension_id_|.
+  virtual void DispatchEventToExtension(
+      extensions::events::HistogramValue histogram_value,
+      const std::string& event_name,
+      scoped_ptr<base::ListValue> args) = 0;
+
+  // Returns true if the extension is ready to accept key event, otherwise
+  // returns false.
+  bool ShouldForwardKeyEvent() const;
+
+  // Returns true if there are any listeners on the given event.
+  bool HasListener(const std::string& event_name) const;
+
+  // Functions used to convert InputContext struct to string
+  std::string ConvertInputContextType(
+      IMEEngineHandlerInterface::InputContext input_context);
+  bool ConvertInputContextAutoCorrect(
+      IMEEngineHandlerInterface::InputContext input_context);
+  bool ConvertInputContextAutoComplete(
+      IMEEngineHandlerInterface::InputContext input_context);
+  bool ConvertInputContextSpellCheck(
+      IMEEngineHandlerInterface::InputContext input_context);
+
+  std::string extension_id_;
+  Profile* profile_;
+
+  DISALLOW_COPY_AND_ASSIGN(ImeObserver);
+};
+
 }  // namespace ui
 
 namespace extensions {
@@ -89,111 +145,6 @@
   DISALLOW_COPY_AND_ASSIGN(InputImeEventRouterFactory);
 };
 
-class InputImeSetCompositionFunction : public SyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("input.ime.setComposition",
-                             INPUT_IME_SETCOMPOSITION)
-
- protected:
-  ~InputImeSetCompositionFunction() override {}
-
-  // ExtensionFunction:
-  bool RunSync() override;
-};
-
-class InputImeClearCompositionFunction : public SyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("input.ime.clearComposition",
-                             INPUT_IME_CLEARCOMPOSITION)
-
- protected:
-  ~InputImeClearCompositionFunction() override {}
-
-  // ExtensionFunction:
-  bool RunSync() override;
-};
-
-class InputImeCommitTextFunction : public SyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("input.ime.commitText", INPUT_IME_COMMITTEXT)
-
- protected:
-  ~InputImeCommitTextFunction() override {}
-
-  // ExtensionFunction:
-  bool RunSync() override;
-};
-
-class InputImeSetCandidateWindowPropertiesFunction
-    : public SyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("input.ime.setCandidateWindowProperties",
-                             INPUT_IME_SETCANDIDATEWINDOWPROPERTIES)
-
- protected:
-  ~InputImeSetCandidateWindowPropertiesFunction() override {}
-
-  // ExtensionFunction:
-  bool RunSync() override;
-};
-
-class InputImeSetCandidatesFunction : public SyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("input.ime.setCandidates", INPUT_IME_SETCANDIDATES)
-
- protected:
-  ~InputImeSetCandidatesFunction() override {}
-
-  // ExtensionFunction:
-  bool RunSync() override;
-};
-
-class InputImeSetCursorPositionFunction : public SyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("input.ime.setCursorPosition",
-                             INPUT_IME_SETCURSORPOSITION)
-
- protected:
-  ~InputImeSetCursorPositionFunction() override {}
-
-  // ExtensionFunction:
-  bool RunSync() override;
-};
-
-class InputImeSetMenuItemsFunction : public SyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("input.ime.setMenuItems", INPUT_IME_SETMENUITEMS)
-
- protected:
-  ~InputImeSetMenuItemsFunction() override {}
-
-  // ExtensionFunction:
-  bool RunSync() override;
-};
-
-class InputImeUpdateMenuItemsFunction : public SyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("input.ime.updateMenuItems",
-                             INPUT_IME_UPDATEMENUITEMS)
-
- protected:
-  ~InputImeUpdateMenuItemsFunction() override {}
-
-  // ExtensionFunction:
-  bool RunSync() override;
-};
-
-class InputImeDeleteSurroundingTextFunction : public SyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("input.ime.deleteSurroundingText",
-                             INPUT_IME_DELETESURROUNDINGTEXT)
- protected:
-  ~InputImeDeleteSurroundingTextFunction() override {}
-
-  // ExtensionFunction:
-  bool RunSync() override;
-};
-
 class InputImeKeyEventHandledFunction : public AsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("input.ime.keyEventHandled",
@@ -206,30 +157,6 @@
   bool RunAsync() override;
 };
 
-class InputImeSendKeyEventsFunction : public AsyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("input.ime.sendKeyEvents",
-                             INPUT_IME_SENDKEYEVENTS)
-
- protected:
-  ~InputImeSendKeyEventsFunction() override {}
-
-  // ExtensionFunction:
-  bool RunAsync() override;
-};
-
-class InputImeHideInputViewFunction : public AsyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("input.ime.hideInputView",
-                             INPUT_IME_HIDEINPUTVIEW)
-
- protected:
-  ~InputImeHideInputViewFunction() override {}
-
-  // ExtensionFunction:
-  bool RunAsync() override;
-};
-
 class InputImeAPI : public BrowserContextKeyedAPI,
                     public ExtensionRegistryObserver,
                     public EventRouter::Observer {
@@ -267,6 +194,8 @@
       extension_registry_observer_;
 };
 
+InputImeEventRouter* GetInputImeEventRouter(Profile* profile);
+
 }  // namespace extensions
 
 #endif  // CHROME_BROWSER_EXTENSIONS_API_INPUT_IME_INPUT_IME_API_H_
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
new file mode 100644
index 0000000..1d6284ad
--- /dev/null
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
@@ -0,0 +1,690 @@
+// 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/extensions/api/input_ime/input_ime_api.h"
+
+#include "chrome/browser/chromeos/input_method/input_method_engine.h"
+#include "chrome/browser/chromeos/login/lock/screen_locker.h"
+#include "chrome/browser/chromeos/login/session/user_session_manager.h"
+#include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/extensions/api/input_ime.h"
+#include "chrome/common/extensions/api/input_ime/input_components_handler.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/common/manifest_handlers/background_info.h"
+#include "ui/base/ime/chromeos/component_extension_ime_manager.h"
+#include "ui/base/ime/chromeos/extension_ime_util.h"
+#include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/ime_engine_handler_interface.h"
+
+namespace input_ime = extensions::api::input_ime;
+namespace DeleteSurroundingText =
+    extensions::api::input_ime::DeleteSurroundingText;
+namespace UpdateMenuItems = extensions::api::input_ime::UpdateMenuItems;
+namespace SendKeyEvents = extensions::api::input_ime::SendKeyEvents;
+namespace HideInputView = extensions::api::input_ime::HideInputView;
+namespace SetMenuItems = extensions::api::input_ime::SetMenuItems;
+namespace SetCursorPosition = extensions::api::input_ime::SetCursorPosition;
+namespace SetCandidates = extensions::api::input_ime::SetCandidates;
+namespace SetCandidateWindowProperties =
+    extensions::api::input_ime::SetCandidateWindowProperties;
+namespace CommitText = extensions::api::input_ime::CommitText;
+namespace ClearComposition = extensions::api::input_ime::ClearComposition;
+namespace SetComposition = extensions::api::input_ime::SetComposition;
+using ui::IMEEngineHandlerInterface;
+
+namespace {
+const char kErrorEngineNotAvailable[] = "Engine is not available";
+const char kErrorSetMenuItemsFail[] = "Could not create menu Items";
+const char kErrorUpdateMenuItemsFail[] = "Could not update menu Items";
+const char kOnCompositionBoundsChangedEventName[] =
+    "inputMethodPrivate.onCompositionBoundsChanged";
+
+void SetMenuItemToMenu(const input_ime::MenuItem& input,
+                       IMEEngineHandlerInterface::MenuItem* out) {
+  out->modified = 0;
+  out->id = input.id;
+  if (input.label) {
+    out->modified |= IMEEngineHandlerInterface::MENU_ITEM_MODIFIED_LABEL;
+    out->label = *input.label;
+  }
+
+  if (input.style != input_ime::MENU_ITEM_STYLE_NONE) {
+    out->modified |= IMEEngineHandlerInterface::MENU_ITEM_MODIFIED_STYLE;
+    out->style =
+        static_cast<IMEEngineHandlerInterface::MenuItemStyle>(input.style);
+  }
+
+  if (input.visible)
+    out->modified |= IMEEngineHandlerInterface::MENU_ITEM_MODIFIED_VISIBLE;
+  out->visible = input.visible ? *input.visible : true;
+
+  if (input.checked)
+    out->modified |= IMEEngineHandlerInterface::MENU_ITEM_MODIFIED_CHECKED;
+  out->checked = input.checked ? *input.checked : false;
+
+  if (input.enabled)
+    out->modified |= IMEEngineHandlerInterface::MENU_ITEM_MODIFIED_ENABLED;
+  out->enabled = input.enabled ? *input.enabled : true;
+}
+
+class ImeObserverChromeOS : public ui::ImeObserver {
+ public:
+  ImeObserverChromeOS(const std::string& extension_id, Profile* profile)
+      : ImeObserver(extension_id, profile) {}
+
+  ~ImeObserverChromeOS() override {}
+
+  // ui::IMEEngineObserver overrides
+  void OnActivate(const std::string& component_id) override {
+    if (extension_id_.empty() ||
+        !HasListener(input_ime::OnActivate::kEventName))
+      return;
+
+    scoped_ptr<base::ListValue> args(input_ime::OnActivate::Create(
+        component_id,
+        input_ime::ParseScreenType(GetCurrentScreenType())));
+
+    DispatchEventToExtension(extensions::events::INPUT_IME_ON_ACTIVATE,
+                             input_ime::OnActivate::kEventName, args.Pass());
+  }
+
+  void OnInputContextUpdate(
+      const IMEEngineHandlerInterface::InputContext& context) override {
+    if (extension_id_.empty() ||
+        !HasListener(input_ime::OnInputContextUpdate::kEventName))
+      return;
+
+    input_ime::InputContext context_value;
+    context_value.context_id = context.id;
+    context_value.type =
+        input_ime::ParseInputContextType(ConvertInputContextType(context));
+
+    scoped_ptr<base::ListValue> args(
+        input_ime::OnInputContextUpdate::Create(context_value));
+
+    DispatchEventToExtension(
+        extensions::events::INPUT_IME_ON_INPUT_CONTEXT_UPDATE,
+        input_ime::OnInputContextUpdate::kEventName, args.Pass());
+  }
+
+  bool IsInterestedInKeyEvent() const override {
+    return ShouldForwardKeyEvent();
+  }
+
+  void OnCandidateClicked(
+      const std::string& component_id,
+      int candidate_id,
+      ui::IMEEngineObserver::MouseButtonEvent button) override {
+    if (extension_id_.empty() ||
+        !HasListener(input_ime::OnCandidateClicked::kEventName))
+      return;
+
+    input_ime::MouseButton button_enum = input_ime::MOUSE_BUTTON_NONE;
+    switch (button) {
+      case ui::IMEEngineObserver::MOUSE_BUTTON_MIDDLE:
+        button_enum = input_ime::MOUSE_BUTTON_MIDDLE;
+        break;
+
+      case ui::IMEEngineObserver::MOUSE_BUTTON_RIGHT:
+        button_enum = input_ime::MOUSE_BUTTON_RIGHT;
+        break;
+
+      case ui::IMEEngineObserver::MOUSE_BUTTON_LEFT:
+      // Default to left.
+      default:
+        button_enum = input_ime::MOUSE_BUTTON_LEFT;
+        break;
+    }
+
+    scoped_ptr<base::ListValue> args(input_ime::OnCandidateClicked::Create(
+        component_id, candidate_id, button_enum));
+
+    DispatchEventToExtension(extensions::events::INPUT_IME_ON_CANDIDATE_CLICKED,
+                             input_ime::OnCandidateClicked::kEventName,
+                             args.Pass());
+  }
+
+  void OnMenuItemActivated(const std::string& component_id,
+                           const std::string& menu_id) override {
+    if (extension_id_.empty() ||
+        !HasListener(input_ime::OnMenuItemActivated::kEventName))
+      return;
+
+    scoped_ptr<base::ListValue> args(
+        input_ime::OnMenuItemActivated::Create(component_id, menu_id));
+
+    DispatchEventToExtension(
+        extensions::events::INPUT_IME_ON_MENU_ITEM_ACTIVATED,
+        input_ime::OnMenuItemActivated::kEventName, args.Pass());
+  }
+
+  void OnSurroundingTextChanged(const std::string& component_id,
+                                const std::string& text,
+                                int cursor_pos,
+                                int anchor_pos,
+                                int offset_pos) override {
+    if (extension_id_.empty() ||
+        !HasListener(input_ime::OnSurroundingTextChanged::kEventName))
+      return;
+
+    input_ime::OnSurroundingTextChanged::SurroundingInfo info;
+    info.text = text;
+    info.focus = cursor_pos;
+    info.anchor = anchor_pos;
+    info.offset = offset_pos;
+    scoped_ptr<base::ListValue> args(
+        input_ime::OnSurroundingTextChanged::Create(component_id, info));
+
+    DispatchEventToExtension(
+        extensions::events::INPUT_IME_ON_SURROUNDING_TEXT_CHANGED,
+        input_ime::OnSurroundingTextChanged::kEventName, args.Pass());
+  }
+
+  void OnCompositionBoundsChanged(
+      const std::vector<gfx::Rect>& bounds) override {
+    if (extension_id_.empty() ||
+        !HasListener(kOnCompositionBoundsChangedEventName))
+      return;
+
+    // Note: this is a private API event.
+    base::ListValue* bounds_list = new base::ListValue();
+    for (size_t i = 0; i < bounds.size(); ++i) {
+      base::DictionaryValue* bounds_value = new base::DictionaryValue();
+      bounds_value->SetInteger("x", bounds[i].x());
+      bounds_value->SetInteger("y", bounds[i].y());
+      bounds_value->SetInteger("w", bounds[i].width());
+      bounds_value->SetInteger("h", bounds[i].height());
+      bounds_list->Append(bounds_value);
+    }
+
+    if (bounds_list->GetSize() <= 0)
+      return;
+    scoped_ptr<base::ListValue> args(new base::ListValue());
+
+    // The old extension code uses the first parameter to get the bounds of the
+    // first composition character, so for backward compatibility, add it here.
+    base::Value* first_value = NULL;
+    if (bounds_list->Get(0, &first_value))
+      args->Append(first_value->DeepCopy());
+    args->Append(bounds_list);
+
+    DispatchEventToExtension(
+        extensions::events::INPUT_METHOD_PRIVATE_ON_COMPOSITION_BOUNDS_CHANGED,
+        kOnCompositionBoundsChangedEventName, args.Pass());
+  }
+
+ private:
+  // ui::ImeObserver overrides.
+  void DispatchEventToExtension(
+      extensions::events::HistogramValue histogram_value,
+      const std::string& event_name,
+      scoped_ptr<base::ListValue> args) override {
+    if (event_name != input_ime::OnActivate::kEventName) {
+      // For suspended IME extension (e.g. XKB extension), don't awake it by IME
+      // events except onActivate. The IME extension should be awake by other
+      // events (e.g. runtime.onMessage) from its other pages.
+      // This is to save memory for steady state Chrome OS on which the users
+      // don't want any IME features.
+      extensions::ExtensionSystem* extension_system =
+          extensions::ExtensionSystem::Get(profile_);
+      if (extension_system) {
+        const extensions::Extension* extension =
+            extension_system->extension_service()->GetExtensionById(
+                extension_id_, false /* include_disabled */);
+        if (!extension)
+          return;
+        extensions::ProcessManager* process_manager =
+            extensions::ProcessManager::Get(profile_);
+        if (extensions::BackgroundInfo::HasBackgroundPage(extension) &&
+            !process_manager->GetBackgroundHostForExtension(extension_id_)) {
+          return;
+        }
+      }
+    }
+
+    scoped_ptr<extensions::Event> event(
+        new extensions::Event(histogram_value, event_name, args.Pass()));
+    event->restrict_to_browser_context = profile_;
+    extensions::EventRouter::Get(profile_)
+        ->DispatchEventToExtension(extension_id_, event.Pass());
+  }
+
+  // The component IME extensions need to know the current screen type (e.g.
+  // lock screen, login screen, etc.) so that its on-screen keyboard page
+  // won't open new windows/pages. See crbug.com/395621.
+  std::string GetCurrentScreenType() {
+    switch (chromeos::input_method::InputMethodManager::Get()
+                ->GetUISessionState()) {
+      case chromeos::input_method::InputMethodManager::STATE_LOGIN_SCREEN:
+        return "login";
+      case chromeos::input_method::InputMethodManager::STATE_LOCK_SCREEN:
+        return "lock";
+      case chromeos::input_method::InputMethodManager::STATE_BROWSER_SCREEN:
+        return chromeos::UserAddingScreen::Get()->IsRunning()
+                   ? "secondary-login"
+                   : "normal";
+      case chromeos::input_method::InputMethodManager::STATE_TERMINATING:
+        return "normal";
+    }
+    NOTREACHED() << "New screen type is added. Please add new entry above.";
+    return "normal";
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(ImeObserverChromeOS);
+};
+
+}  // namespace
+
+namespace extensions {
+
+bool InputImeEventRouter::RegisterImeExtension(
+    const std::string& extension_id,
+    const std::vector<extensions::InputComponentInfo>& input_components) {
+  VLOG(1) << "RegisterImeExtension: " << extension_id;
+
+  if (engine_map_[extension_id])
+    return false;
+
+  chromeos::input_method::InputMethodManager* manager =
+      chromeos::input_method::InputMethodManager::Get();
+  chromeos::ComponentExtensionIMEManager* comp_ext_ime_manager =
+      manager->GetComponentExtensionIMEManager();
+
+  chromeos::input_method::InputMethodDescriptors descriptors;
+  // Only creates descriptors for 3rd party IME extension, because the
+  // descriptors for component IME extensions are managed by InputMethodUtil.
+  if (!comp_ext_ime_manager->IsWhitelistedExtension(extension_id)) {
+    for (std::vector<extensions::InputComponentInfo>::const_iterator it =
+             input_components.begin();
+         it != input_components.end();
+         ++it) {
+      const extensions::InputComponentInfo& component = *it;
+      DCHECK(component.type == extensions::INPUT_COMPONENT_TYPE_IME);
+
+      std::vector<std::string> layouts;
+      layouts.assign(component.layouts.begin(), component.layouts.end());
+      std::vector<std::string> languages;
+      languages.assign(component.languages.begin(), component.languages.end());
+
+      const std::string& input_method_id =
+          chromeos::extension_ime_util::GetInputMethodID(extension_id,
+                                                         component.id);
+      descriptors.push_back(chromeos::input_method::InputMethodDescriptor(
+          input_method_id,
+          component.name,
+          std::string(),  // TODO(uekawa): Set short name.
+          layouts,
+          languages,
+          false,  // 3rd party IMEs are always not for login.
+          component.options_page_url,
+          component.input_view_url));
+    }
+  }
+
+  scoped_ptr<ui::IMEEngineObserver> observer(
+      new ImeObserverChromeOS(extension_id, profile_));
+  chromeos::InputMethodEngine* engine = new chromeos::InputMethodEngine();
+  engine->Initialize(observer.Pass(), extension_id.c_str(), profile_);
+  engine_map_[extension_id] = engine;
+  chromeos::UserSessionManager::GetInstance()
+      ->GetDefaultIMEState(profile_)
+      ->AddInputMethodExtension(extension_id, descriptors, engine);
+
+  return true;
+}
+
+void InputImeEventRouter::UnregisterAllImes(const std::string& extension_id) {
+  std::map<std::string, IMEEngineHandlerInterface*>::iterator it =
+      engine_map_.find(extension_id);
+  if (it != engine_map_.end()) {
+    chromeos::input_method::InputMethodManager::Get()
+        ->GetActiveIMEState()
+        ->RemoveInputMethodExtension(extension_id);
+    delete it->second;
+    engine_map_.erase(it);
+  }
+}
+
+bool InputImeSetCompositionFunction::RunSync() {
+  IMEEngineHandlerInterface* engine =
+      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
+          ->GetActiveEngine(extension_id());
+  if (!engine) {
+    SetResult(new base::FundamentalValue(false));
+    return true;
+  }
+
+  scoped_ptr<SetComposition::Params> parent_params(
+      SetComposition::Params::Create(*args_));
+  const SetComposition::Params::Parameters& params = parent_params->parameters;
+  std::vector<IMEEngineHandlerInterface::SegmentInfo> segments;
+  if (params.segments) {
+    const std::vector<linked_ptr<
+        SetComposition::Params::Parameters::SegmentsType> >&
+            segments_args = *params.segments;
+    for (size_t i = 0; i < segments_args.size(); ++i) {
+      EXTENSION_FUNCTION_VALIDATE(
+          segments_args[i]->style !=
+          input_ime::UNDERLINE_STYLE_NONE);
+      segments.push_back(IMEEngineHandlerInterface::SegmentInfo());
+      segments.back().start = segments_args[i]->start;
+      segments.back().end = segments_args[i]->end;
+      if (segments_args[i]->style ==
+          input_ime::UNDERLINE_STYLE_UNDERLINE) {
+        segments.back().style =
+            IMEEngineHandlerInterface::SEGMENT_STYLE_UNDERLINE;
+      } else if (segments_args[i]->style ==
+                 input_ime::UNDERLINE_STYLE_DOUBLEUNDERLINE) {
+        segments.back().style =
+            IMEEngineHandlerInterface::SEGMENT_STYLE_DOUBLE_UNDERLINE;
+      } else {
+        segments.back().style =
+            IMEEngineHandlerInterface::SEGMENT_STYLE_NO_UNDERLINE;
+      }
+    }
+  }
+
+  int selection_start =
+      params.selection_start ? *params.selection_start : params.cursor;
+  int selection_end =
+      params.selection_end ? *params.selection_end : params.cursor;
+
+  SetResult(new base::FundamentalValue(
+      engine->SetComposition(params.context_id, params.text.c_str(),
+                             selection_start, selection_end, params.cursor,
+                             segments, &error_)));
+  return true;
+}
+
+bool InputImeClearCompositionFunction::RunSync() {
+  IMEEngineHandlerInterface* engine =
+      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
+          ->GetActiveEngine(extension_id());
+  if (!engine) {
+    SetResult(new base::FundamentalValue(false));
+    return true;
+  }
+
+  scoped_ptr<ClearComposition::Params> parent_params(
+      ClearComposition::Params::Create(*args_));
+  const ClearComposition::Params::Parameters& params =
+      parent_params->parameters;
+
+  SetResult(new base::FundamentalValue(
+      engine->ClearComposition(params.context_id, &error_)));
+  return true;
+}
+
+bool InputImeCommitTextFunction::RunSync() {
+  IMEEngineHandlerInterface* engine =
+      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
+          ->GetActiveEngine(extension_id());
+  if (!engine) {
+    SetResult(new base::FundamentalValue(false));
+    return true;
+  }
+
+  scoped_ptr<CommitText::Params> parent_params(
+      CommitText::Params::Create(*args_));
+  const CommitText::Params::Parameters& params =
+      parent_params->parameters;
+
+  SetResult(new base::FundamentalValue(
+      engine->CommitText(params.context_id, params.text.c_str(), &error_)));
+  return true;
+}
+
+bool InputImeHideInputViewFunction::RunAsync() {
+  IMEEngineHandlerInterface* engine =
+      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
+          ->GetActiveEngine(extension_id());
+  if (!engine) {
+    return true;
+  }
+  engine->HideInputView();
+  return true;
+}
+
+bool InputImeSendKeyEventsFunction::RunAsync() {
+  scoped_ptr<SendKeyEvents::Params> parent_params(
+      SendKeyEvents::Params::Create(*args_));
+  const SendKeyEvents::Params::Parameters& params =
+      parent_params->parameters;
+  IMEEngineHandlerInterface* engine =
+      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
+          ->GetActiveEngine(extension_id());
+  if (!engine) {
+    error_ = kErrorEngineNotAvailable;
+    return false;
+  }
+
+  const std::vector<linked_ptr<input_ime::KeyboardEvent> >& key_data =
+      params.key_data;
+  std::vector<IMEEngineHandlerInterface::KeyboardEvent> key_data_out;
+
+  for (size_t i = 0; i < key_data.size(); ++i) {
+    IMEEngineHandlerInterface::KeyboardEvent event;
+    event.type = input_ime::ToString(key_data[i]->type);
+    event.key = key_data[i]->key;
+    event.code = key_data[i]->code;
+    event.key_code = key_data[i]->key_code.get() ? *(key_data[i]->key_code) : 0;
+    if (key_data[i]->alt_key)
+      event.alt_key = *(key_data[i]->alt_key);
+    if (key_data[i]->ctrl_key)
+      event.ctrl_key = *(key_data[i]->ctrl_key);
+    if (key_data[i]->shift_key)
+      event.shift_key = *(key_data[i]->shift_key);
+    if (key_data[i]->caps_lock)
+      event.caps_lock = *(key_data[i]->caps_lock);
+    key_data_out.push_back(event);
+  }
+
+  engine->SendKeyEvents(params.context_id, key_data_out);
+  return true;
+}
+
+bool InputImeSetCandidateWindowPropertiesFunction::RunSync() {
+  scoped_ptr<SetCandidateWindowProperties::Params> parent_params(
+      SetCandidateWindowProperties::Params::Create(*args_));
+  const SetCandidateWindowProperties::Params::Parameters&
+      params = parent_params->parameters;
+
+  IMEEngineHandlerInterface* engine =
+      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
+          ->GetEngine(extension_id(), params.engine_id);
+  if (!engine) {
+    SetResult(new base::FundamentalValue(false));
+    return true;
+  }
+
+  const SetCandidateWindowProperties::Params::Parameters::Properties&
+      properties = params.properties;
+
+  if (properties.visible &&
+      !engine->SetCandidateWindowVisible(*properties.visible, &error_)) {
+    SetResult(new base::FundamentalValue(false));
+    return true;
+  }
+
+  IMEEngineHandlerInterface::CandidateWindowProperty properties_out =
+      engine->GetCandidateWindowProperty();
+  bool modified = false;
+
+  if (properties.cursor_visible) {
+    properties_out.is_cursor_visible = *properties.cursor_visible;
+    modified = true;
+  }
+
+  if (properties.vertical) {
+    properties_out.is_vertical = *properties.vertical;
+    modified = true;
+  }
+
+  if (properties.page_size) {
+    properties_out.page_size = *properties.page_size;
+    modified = true;
+  }
+
+  if (properties.window_position == input_ime::WINDOW_POSITION_COMPOSITION) {
+    properties_out.show_window_at_composition = true;
+    modified = true;
+  } else if (properties.window_position == input_ime::WINDOW_POSITION_CURSOR) {
+    properties_out.show_window_at_composition = false;
+    modified = true;
+  }
+
+  if (properties.auxiliary_text) {
+    properties_out.auxiliary_text = *properties.auxiliary_text;
+    modified = true;
+  }
+
+  if (properties.auxiliary_text_visible) {
+    properties_out.is_auxiliary_text_visible =
+        *properties.auxiliary_text_visible;
+    modified = true;
+  }
+
+  if (modified) {
+    engine->SetCandidateWindowProperty(properties_out);
+  }
+
+  SetResult(new base::FundamentalValue(true));
+
+  return true;
+}
+
+bool InputImeSetCandidatesFunction::RunSync() {
+  IMEEngineHandlerInterface* engine =
+      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
+          ->GetActiveEngine(extension_id());
+  if (!engine) {
+    SetResult(new base::FundamentalValue(false));
+    return true;
+  }
+
+  scoped_ptr<SetCandidates::Params> parent_params(
+      SetCandidates::Params::Create(*args_));
+  const SetCandidates::Params::Parameters& params =
+      parent_params->parameters;
+
+  std::vector<IMEEngineHandlerInterface::Candidate> candidates_out;
+  const std::vector<linked_ptr<
+      SetCandidates::Params::Parameters::CandidatesType> >& candidates_in =
+          params.candidates;
+  for (size_t i = 0; i < candidates_in.size(); ++i) {
+    candidates_out.push_back(IMEEngineHandlerInterface::Candidate());
+    candidates_out.back().value = candidates_in[i]->candidate;
+    candidates_out.back().id = candidates_in[i]->id;
+    if (candidates_in[i]->label)
+      candidates_out.back().label = *candidates_in[i]->label;
+    if (candidates_in[i]->annotation)
+      candidates_out.back().annotation = *candidates_in[i]->annotation;
+    if (candidates_in[i]->usage) {
+      candidates_out.back().usage.title = candidates_in[i]->usage->title;
+      candidates_out.back().usage.body = candidates_in[i]->usage->body;
+    }
+  }
+
+  SetResult(new base::FundamentalValue(
+      engine->SetCandidates(params.context_id, candidates_out, &error_)));
+  return true;
+}
+
+bool InputImeSetCursorPositionFunction::RunSync() {
+  IMEEngineHandlerInterface* engine =
+      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
+          ->GetActiveEngine(extension_id());
+  if (!engine) {
+    SetResult(new base::FundamentalValue(false));
+    return true;
+  }
+
+  scoped_ptr<SetCursorPosition::Params> parent_params(
+      SetCursorPosition::Params::Create(*args_));
+  const SetCursorPosition::Params::Parameters& params =
+      parent_params->parameters;
+
+  SetResult(new base::FundamentalValue(
+      engine->SetCursorPosition(params.context_id, params.candidate_id,
+                                &error_)));
+  return true;
+}
+
+bool InputImeSetMenuItemsFunction::RunSync() {
+  scoped_ptr<SetMenuItems::Params> parent_params(
+      SetMenuItems::Params::Create(*args_));
+  const SetMenuItems::Params::Parameters& params =
+      parent_params->parameters;
+
+  IMEEngineHandlerInterface* engine =
+      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
+          ->GetEngine(extension_id(), params.engine_id);
+  if (!engine) {
+    error_ = kErrorEngineNotAvailable;
+    return false;
+  }
+
+  const std::vector<linked_ptr<input_ime::MenuItem> >& items = params.items;
+  std::vector<IMEEngineHandlerInterface::MenuItem> items_out;
+
+  for (size_t i = 0; i < items.size(); ++i) {
+    items_out.push_back(IMEEngineHandlerInterface::MenuItem());
+    SetMenuItemToMenu(*items[i], &items_out.back());
+  }
+
+  if (!engine->SetMenuItems(items_out))
+    error_ = kErrorSetMenuItemsFail;
+  return true;
+}
+
+bool InputImeUpdateMenuItemsFunction::RunSync() {
+  scoped_ptr<UpdateMenuItems::Params> parent_params(
+      UpdateMenuItems::Params::Create(*args_));
+  const UpdateMenuItems::Params::Parameters& params =
+      parent_params->parameters;
+
+  IMEEngineHandlerInterface* engine =
+      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
+          ->GetEngine(extension_id(), params.engine_id);
+  if (!engine) {
+    error_ = kErrorEngineNotAvailable;
+    return false;
+  }
+
+  const std::vector<linked_ptr<input_ime::MenuItem> >& items = params.items;
+  std::vector<IMEEngineHandlerInterface::MenuItem> items_out;
+
+  for (size_t i = 0; i < items.size(); ++i) {
+    items_out.push_back(IMEEngineHandlerInterface::MenuItem());
+    SetMenuItemToMenu(*items[i], &items_out.back());
+  }
+
+  if (!engine->UpdateMenuItems(items_out))
+    error_ = kErrorUpdateMenuItemsFail;
+  return true;
+}
+
+bool InputImeDeleteSurroundingTextFunction::RunSync() {
+  scoped_ptr<DeleteSurroundingText::Params> parent_params(
+      DeleteSurroundingText::Params::Create(*args_));
+  const DeleteSurroundingText::Params::Parameters& params =
+      parent_params->parameters;
+
+  IMEEngineHandlerInterface* engine =
+      GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()))
+          ->GetEngine(extension_id(), params.engine_id);
+  if (!engine) {
+    error_ = kErrorEngineNotAvailable;
+    return false;
+  }
+
+  engine->DeleteSurroundingText(params.context_id, params.offset, params.length,
+                                &error_);
+  return true;
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h
new file mode 100644
index 0000000..dd115ccf
--- /dev/null
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h
@@ -0,0 +1,143 @@
+// 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_EXTENSIONS_API_INPUT_IME_INPUT_IME_API_CHROMEOS_H_
+#define CHROME_BROWSER_EXTENSIONS_API_INPUT_IME_INPUT_IME_API_CHROMEOS_H_
+
+#include "extensions/browser/extension_function.h"
+
+namespace extensions {
+
+class InputImeSetCompositionFunction : public SyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("input.ime.setComposition",
+                             INPUT_IME_SETCOMPOSITION)
+
+ protected:
+  ~InputImeSetCompositionFunction() override {}
+
+  // ExtensionFunction:
+  bool RunSync() override;
+};
+
+class InputImeClearCompositionFunction : public SyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("input.ime.clearComposition",
+                             INPUT_IME_CLEARCOMPOSITION)
+
+ protected:
+  ~InputImeClearCompositionFunction() override {}
+
+  // ExtensionFunction:
+  bool RunSync() override;
+};
+
+class InputImeCommitTextFunction : public SyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("input.ime.commitText", INPUT_IME_COMMITTEXT)
+
+ protected:
+  ~InputImeCommitTextFunction() override {}
+
+  // ExtensionFunction:
+  bool RunSync() override;
+};
+
+class InputImeSetCandidateWindowPropertiesFunction
+    : public SyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("input.ime.setCandidateWindowProperties",
+                             INPUT_IME_SETCANDIDATEWINDOWPROPERTIES)
+
+ protected:
+  ~InputImeSetCandidateWindowPropertiesFunction() override {}
+
+  // ExtensionFunction:
+  bool RunSync() override;
+};
+
+class InputImeSetCandidatesFunction : public SyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("input.ime.setCandidates", INPUT_IME_SETCANDIDATES)
+
+ protected:
+  ~InputImeSetCandidatesFunction() override {}
+
+  // ExtensionFunction:
+  bool RunSync() override;
+};
+
+class InputImeSetCursorPositionFunction : public SyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("input.ime.setCursorPosition",
+                             INPUT_IME_SETCURSORPOSITION)
+
+ protected:
+  ~InputImeSetCursorPositionFunction() override {}
+
+  // ExtensionFunction:
+  bool RunSync() override;
+};
+
+class InputImeSetMenuItemsFunction : public SyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("input.ime.setMenuItems", INPUT_IME_SETMENUITEMS)
+
+ protected:
+  ~InputImeSetMenuItemsFunction() override {}
+
+  // ExtensionFunction:
+  bool RunSync() override;
+};
+
+class InputImeUpdateMenuItemsFunction : public SyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("input.ime.updateMenuItems",
+                             INPUT_IME_UPDATEMENUITEMS)
+
+ protected:
+  ~InputImeUpdateMenuItemsFunction() override {}
+
+  // ExtensionFunction:
+  bool RunSync() override;
+};
+
+class InputImeDeleteSurroundingTextFunction : public SyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("input.ime.deleteSurroundingText",
+                             INPUT_IME_DELETESURROUNDINGTEXT)
+ protected:
+  ~InputImeDeleteSurroundingTextFunction() override {}
+
+  // ExtensionFunction:
+  bool RunSync() override;
+};
+
+class InputImeSendKeyEventsFunction : public AsyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("input.ime.sendKeyEvents",
+                             INPUT_IME_SENDKEYEVENTS)
+
+ protected:
+  ~InputImeSendKeyEventsFunction() override {}
+
+  // ExtensionFunction:
+  bool RunAsync() override;
+};
+
+class InputImeHideInputViewFunction : public AsyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("input.ime.hideInputView",
+                             INPUT_IME_HIDEINPUTVIEW)
+
+ protected:
+  ~InputImeHideInputViewFunction() override {}
+
+  // ExtensionFunction:
+  bool RunAsync() override;
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_INPUT_IME_INPUT_IME_API_CHROMEOS_H_
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_nonchromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_nonchromeos.cc
new file mode 100644
index 0000000..50329fa3
--- /dev/null
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_nonchromeos.cc
@@ -0,0 +1,62 @@
+// 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.
+
+// This file is for non-chromeos (win & linux) functions, such as
+// chrome.input.ime.activate, chrome.input.ime.createWindow and
+// chrome.input.ime.onSelectionChanged.
+// TODO(azurewei): May refactor the code structure by using delegate or
+// redesign the API to remove this platform-specific file in the future.
+
+#include "chrome/browser/extensions/api/input_ime/input_ime_api.h"
+
+#include "base/command_line.h"
+#include "chrome/common/chrome_switches.h"
+
+namespace {
+
+bool IsInputImeEnabled() {
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnableInputImeAPI);
+}
+
+class ImeObserverNonChromeOS : public ui::ImeObserver {
+ public:
+  ImeObserverNonChromeOS(const std::string& extension_id, Profile* profile)
+      : ImeObserver(extension_id, profile) {}
+
+  ~ImeObserverNonChromeOS() override {}
+
+ private:
+  // ImeObserver overrides.
+  void DispatchEventToExtension(
+      extensions::events::HistogramValue histogram_value,
+      const std::string& event_name,
+      scoped_ptr<base::ListValue> args) override {
+    if (!IsInputImeEnabled()) {
+      return;
+    }
+
+    scoped_ptr<extensions::Event> event(
+        new extensions::Event(histogram_value, event_name, args.Pass()));
+    event->restrict_to_browser_context = profile_;
+    extensions::EventRouter::Get(profile_)
+        ->DispatchEventToExtension(extension_id_, event.Pass());
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(ImeObserverNonChromeOS);
+};
+
+}  // namespace
+
+namespace extensions {
+
+bool InputImeEventRouter::RegisterImeExtension(
+    const std::string& extension_id,
+    const std::vector<extensions::InputComponentInfo>& input_components) {
+  return false;
+}
+
+void InputImeEventRouter::UnregisterAllImes(const std::string& extension_id) {}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc b/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
index 35d1f06..ed6757f58 100644
--- a/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
+++ b/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
@@ -565,11 +565,14 @@
   DetachFakeDevice();
 }
 
-// Test is flaky, it times out frequently on Win7 bots. See crbug.com/567212.
+// These two tests are flaky, they time out frequently on Win7 bots. See
+// crbug.com/567212.
 #if defined(OS_WIN)
 #define MAYBE_PicasaDefaultLocation DISABLED_PicasaDefaultLocation
+#define MAYBE_PicasaCustomLocation DISABLED_PicasaCustomLocation
 #else
 #define MAYBE_PicasaDefaultLocation PicasaDefaultLocation
+#define MAYBE_PicasaCustomLocation PicasaCustomLocation
 #endif
 #if defined(OS_WIN)|| defined(OS_MACOSX)
 IN_PROC_BROWSER_TEST_F(MediaGalleriesPlatformAppBrowserTest,
@@ -588,7 +591,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(MediaGalleriesPlatformAppBrowserTest,
-                       PicasaCustomLocation) {
+                       MAYBE_PicasaCustomLocation) {
   base::ScopedTempDir custom_picasa_app_data_root;
   ASSERT_TRUE(custom_picasa_app_data_root.CreateUniqueTempDir());
   ensure_media_directories_exists()->SetCustomPicasaAppDataPath(
diff --git a/chrome/browser/extensions/api/omnibox/omnibox_unittest.cc b/chrome/browser/extensions/api/omnibox/omnibox_unittest.cc
index db224035..51006e0d 100644
--- a/chrome/browser/extensions/api/omnibox/omnibox_unittest.cc
+++ b/chrome/browser/extensions/api/omnibox/omnibox_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/values.h"
 #include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
 #include "chrome/common/extensions/api/omnibox.h"
@@ -41,21 +43,24 @@
 // +       ddd
 // = nmmmmndddn
 TEST(ExtensionOmniboxTest, DescriptionStylesSimple) {
-  scoped_ptr<base::ListValue> list = ListBuilder()
-      .Append(42)
-      .Append(ListBuilder()
-        .Append(DictionaryBuilder()
-          .Set("content", "content")
-          .Set("description", "description")
-          .Set("descriptionStyles", ListBuilder()
-            .Append(DictionaryBuilder()
-              .Set("type", "match")
-              .Set("offset", 1)
-              .Set("length", 4))
-            .Append(DictionaryBuilder()
-              .Set("type", "dim")
-              .Set("offset", 6)
-              .Set("length", 3))))).Build();
+  scoped_ptr<base::ListValue> list =
+      ListBuilder()
+          .Append(42)
+          .Append(std::move(ListBuilder().Append(
+              DictionaryBuilder()
+                  .Set("content", "content")
+                  .Set("description", "description")
+                  .Set("descriptionStyles",
+                       std::move(ListBuilder()
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "match")
+                                                 .Set("offset", 1)
+                                                 .Set("length", 4))
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "dim")
+                                                 .Set("offset", 6)
+                                                 .Set("length", 3)))))))
+          .Build();
 
   ACMatchClassifications styles_expected;
   styles_expected.push_back(ACMatchClassification(0, kNone));
@@ -72,21 +77,24 @@
       *params->suggest_results[0]));
 
   // Same input, but swap the order. Ensure it still works.
-  scoped_ptr<base::ListValue> swap_list = ListBuilder()
-      .Append(42)
-      .Append(ListBuilder()
-        .Append(DictionaryBuilder()
-          .Set("content", "content")
-          .Set("description", "description")
-          .Set("descriptionStyles", ListBuilder()
-            .Append(DictionaryBuilder()
-              .Set("type", "dim")
-              .Set("offset", 6)
-              .Set("length", 3))
-            .Append(DictionaryBuilder()
-              .Set("type", "match")
-              .Set("offset", 1)
-              .Set("length", 4))))).Build();
+  scoped_ptr<base::ListValue> swap_list =
+      ListBuilder()
+          .Append(42)
+          .Append(std::move(ListBuilder().Append(
+              DictionaryBuilder()
+                  .Set("content", "content")
+                  .Set("description", "description")
+                  .Set("descriptionStyles",
+                       std::move(ListBuilder()
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "dim")
+                                                 .Set("offset", 6)
+                                                 .Set("length", 3))
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "match")
+                                                 .Set("offset", 1)
+                                                 .Set("length", 4)))))))
+          .Build();
 
   scoped_ptr<SendSuggestions::Params> swapped_params(
       SendSuggestions::Params::Create(*swap_list));
@@ -104,33 +112,36 @@
 // +  dd
 // = 3773unnnn66
 TEST(ExtensionOmniboxTest, DescriptionStylesCombine) {
-  scoped_ptr<base::ListValue> list = ListBuilder()
-      .Append(42)
-      .Append(ListBuilder()
-        .Append(DictionaryBuilder()
-          .Set("content", "content")
-          .Set("description", "description")
-          .Set("descriptionStyles", ListBuilder()
-            .Append(DictionaryBuilder()
-              .Set("type", "url")
-              .Set("offset", 0)
-              .Set("length", 5))
-            .Append(DictionaryBuilder()
-              .Set("type", "dim")
-              .Set("offset", 9)
-              .Set("length", 2))
-            .Append(DictionaryBuilder()
-              .Set("type", "match")
-              .Set("offset", 9)
-              .Set("length", 2))
-            .Append(DictionaryBuilder()
-              .Set("type", "match")
-              .Set("offset", 0)
-              .Set("length", 4))
-            .Append(DictionaryBuilder()
-              .Set("type", "dim")
-              .Set("offset", 1)
-              .Set("length", 2))))).Build();
+  scoped_ptr<base::ListValue> list =
+      ListBuilder()
+          .Append(42)
+          .Append(std::move(ListBuilder().Append(
+              DictionaryBuilder()
+                  .Set("content", "content")
+                  .Set("description", "description")
+                  .Set("descriptionStyles",
+                       std::move(ListBuilder()
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "url")
+                                                 .Set("offset", 0)
+                                                 .Set("length", 5))
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "dim")
+                                                 .Set("offset", 9)
+                                                 .Set("length", 2))
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "match")
+                                                 .Set("offset", 9)
+                                                 .Set("length", 2))
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "match")
+                                                 .Set("offset", 0)
+                                                 .Set("length", 4))
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "dim")
+                                                 .Set("offset", 1)
+                                                 .Set("length", 2)))))))
+          .Build();
 
   ACMatchClassifications styles_expected;
   styles_expected.push_back(ACMatchClassification(0, kUrl | kMatch));
@@ -149,33 +160,36 @@
 
   // Try moving the "dim/match" style pair at offset 9. Output should be the
   // same.
-  scoped_ptr<base::ListValue> moved_list = ListBuilder()
-      .Append(42)
-      .Append(ListBuilder()
-        .Append(DictionaryBuilder()
-          .Set("content", "content")
-          .Set("description", "description")
-          .Set("descriptionStyles", ListBuilder()
-            .Append(DictionaryBuilder()
-              .Set("type", "url")
-              .Set("offset", 0)
-              .Set("length", 5))
-            .Append(DictionaryBuilder()
-              .Set("type", "match")
-              .Set("offset", 0)
-              .Set("length", 4))
-            .Append(DictionaryBuilder()
-              .Set("type", "dim")
-              .Set("offset", 9)
-              .Set("length", 2))
-            .Append(DictionaryBuilder()
-              .Set("type", "match")
-              .Set("offset", 9)
-              .Set("length", 2))
-            .Append(DictionaryBuilder()
-              .Set("type", "dim")
-              .Set("offset", 1)
-              .Set("length", 2))))).Build();
+  scoped_ptr<base::ListValue> moved_list =
+      ListBuilder()
+          .Append(42)
+          .Append(std::move(ListBuilder().Append(
+              DictionaryBuilder()
+                  .Set("content", "content")
+                  .Set("description", "description")
+                  .Set("descriptionStyles",
+                       std::move(ListBuilder()
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "url")
+                                                 .Set("offset", 0)
+                                                 .Set("length", 5))
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "match")
+                                                 .Set("offset", 0)
+                                                 .Set("length", 4))
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "dim")
+                                                 .Set("offset", 9)
+                                                 .Set("length", 2))
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "match")
+                                                 .Set("offset", 9)
+                                                 .Set("length", 2))
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "dim")
+                                                 .Set("offset", 1)
+                                                 .Set("length", 2)))))))
+          .Build();
 
   scoped_ptr<SendSuggestions::Params> moved_params(
       SendSuggestions::Params::Create(*moved_list));
@@ -193,33 +207,36 @@
 // + ddd
 // = 77777nnnnn
 TEST(ExtensionOmniboxTest, DescriptionStylesCombine2) {
-  scoped_ptr<base::ListValue> list = ListBuilder()
-      .Append(42)
-      .Append(ListBuilder()
-        .Append(DictionaryBuilder()
-          .Set("content", "content")
-          .Set("description", "description")
-          .Set("descriptionStyles", ListBuilder()
-            .Append(DictionaryBuilder()
-              .Set("type", "url")
-              .Set("offset", 0)
-              .Set("length", 5))
-            .Append(DictionaryBuilder()
-              .Set("type", "match")
-              .Set("offset", 0)
-              .Set("length", 5))
-            .Append(DictionaryBuilder()
-              .Set("type", "match")
-              .Set("offset", 0)
-              .Set("length", 3))
-            .Append(DictionaryBuilder()
-              .Set("type", "dim")
-              .Set("offset", 2)
-              .Set("length", 3))
-            .Append(DictionaryBuilder()
-              .Set("type", "dim")
-              .Set("offset", 0)
-              .Set("length", 3))))).Build();
+  scoped_ptr<base::ListValue> list =
+      ListBuilder()
+          .Append(42)
+          .Append(std::move(ListBuilder().Append(
+              DictionaryBuilder()
+                  .Set("content", "content")
+                  .Set("description", "description")
+                  .Set("descriptionStyles",
+                       std::move(ListBuilder()
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "url")
+                                                 .Set("offset", 0)
+                                                 .Set("length", 5))
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "match")
+                                                 .Set("offset", 0)
+                                                 .Set("length", 5))
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "match")
+                                                 .Set("offset", 0)
+                                                 .Set("length", 3))
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "dim")
+                                                 .Set("offset", 2)
+                                                 .Set("length", 3))
+                                     .Append(DictionaryBuilder()
+                                                 .Set("type", "dim")
+                                                 .Set("offset", 0)
+                                                 .Set("length", 3)))))))
+          .Build();
 
   ACMatchClassifications styles_expected;
   styles_expected.push_back(ACMatchClassification(0, kUrl | kMatch | kDim));
@@ -242,30 +259,33 @@
 // = 77777nnnnn
 TEST(ExtensionOmniboxTest, DefaultSuggestResult) {
   // Default suggestions should not have a content parameter.
-  scoped_ptr<base::ListValue> list = ListBuilder()
-      .Append(DictionaryBuilder()
-        .Set("description", "description")
-        .Set("descriptionStyles", ListBuilder()
+  scoped_ptr<base::ListValue> list =
+      ListBuilder()
           .Append(DictionaryBuilder()
-            .Set("type", "url")
-            .Set("offset", 0)
-            .Set("length", 5))
-          .Append(DictionaryBuilder()
-            .Set("type", "match")
-            .Set("offset", 0)
-            .Set("length", 5))
-          .Append(DictionaryBuilder()
-            .Set("type", "match")
-            .Set("offset", 0)
-            .Set("length", 3))
-          .Append(DictionaryBuilder()
-            .Set("type", "dim")
-            .Set("offset", 2)
-            .Set("length", 3))
-          .Append(DictionaryBuilder()
-            .Set("type", "dim")
-            .Set("offset", 0)
-            .Set("length", 3)))).Build();
+                      .Set("description", "description")
+                      .Set("descriptionStyles",
+                           std::move(ListBuilder()
+                                         .Append(DictionaryBuilder()
+                                                     .Set("type", "url")
+                                                     .Set("offset", 0)
+                                                     .Set("length", 5))
+                                         .Append(DictionaryBuilder()
+                                                     .Set("type", "match")
+                                                     .Set("offset", 0)
+                                                     .Set("length", 5))
+                                         .Append(DictionaryBuilder()
+                                                     .Set("type", "match")
+                                                     .Set("offset", 0)
+                                                     .Set("length", 3))
+                                         .Append(DictionaryBuilder()
+                                                     .Set("type", "dim")
+                                                     .Set("offset", 2)
+                                                     .Set("length", 3))
+                                         .Append(DictionaryBuilder()
+                                                     .Set("type", "dim")
+                                                     .Set("offset", 0)
+                                                     .Set("length", 3)))))
+          .Build();
 
   scoped_ptr<SetDefaultSuggestion::Params> params(
       SetDefaultSuggestion::Params::Create(*list));
diff --git a/chrome/browser/extensions/api/preference/preference_api.cc b/chrome/browser/extensions/api/preference/preference_api.cc
index 7dae55e9..b43a833 100644
--- a/chrome/browser/extensions/api/preference/preference_api.cc
+++ b/chrome/browser/extensions/api/preference/preference_api.cc
@@ -75,7 +75,7 @@
 
 PrefMappingEntry kPrefMapping[] = {
     {"spdy_proxy.enabled",
-     data_reduction_proxy::prefs::kDataReductionProxyEnabled,
+     prefs::kDataSaverEnabled,
      APIPermission::kDataReductionProxy, APIPermission::kDataReductionProxy},
     {"data_reduction.daily_original_length",
      data_reduction_proxy::prefs::kDailyHttpOriginalContentLength,
diff --git a/chrome/browser/extensions/api/preferences_private/preferences_private_apitest.cc b/chrome/browser/extensions/api/preferences_private/preferences_private_apitest.cc
index 57c7350..ceadc84 100644
--- a/chrome/browser/extensions/api/preferences_private/preferences_private_apitest.cc
+++ b/chrome/browser/extensions/api/preferences_private/preferences_private_apitest.cc
@@ -48,27 +48,9 @@
 class FakeProfileSyncService : public ProfileSyncService {
  public:
   explicit FakeProfileSyncService(Profile* profile)
-      : ProfileSyncService(
-            make_scoped_ptr(new browser_sync::ChromeSyncClient(profile)),
-            make_scoped_ptr<SigninManagerWrapper>(NULL),
-            ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
-            browser_sync::MANUAL_START,
-            base::Bind(&EmptyNetworkTimeUpdate),
-            profile->GetPath(),
-            profile->GetRequestContext(),
-            profile->GetDebugName(),
-            chrome::GetChannel(),
-            content::BrowserThread::GetMessageLoopProxyForThread(
-                content::BrowserThread::DB),
-            content::BrowserThread::GetMessageLoopProxyForThread(
-                content::BrowserThread::FILE),
-            content::BrowserThread::GetBlockingPool()),
+      : ProfileSyncService(CreateProfileSyncServiceParamsForTest(profile)),
         sync_initialized_(true),
-        initialized_state_violation_(false) {
-    static_cast<browser_sync::ChromeSyncClient*>(GetSyncClient())
-        ->SetSyncApiComponentFactoryForTesting(
-            make_scoped_ptr(new SyncApiComponentFactoryMock()));
-  }
+        initialized_state_violation_(false) {}
 
   ~FakeProfileSyncService() override {}
 
diff --git a/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.cc b/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.cc
index f93b1ef61..e63932b1 100644
--- a/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.cc
+++ b/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.cc
@@ -79,8 +79,8 @@
     }
     proximity_auth::ScreenlockBridge::Get()->Lock();
   } else {
-    proximity_auth::ScreenlockBridge::Get()->Unlock(
-        service->proximity_auth_client()->GetAuthenticatedUsername());
+    proximity_auth::ScreenlockBridge::Get()->Unlock(AccountId::FromUserEmail(
+        service->proximity_auth_client()->GetAuthenticatedUsername()));
   }
   SendResponse(error_.empty());
   return true;
@@ -127,8 +127,7 @@
 }
 
 void ScreenlockPrivateEventRouter::OnFocusedUserChanged(
-    const std::string& user_id) {
-}
+    const AccountId& account_id) {}
 
 void ScreenlockPrivateEventRouter::DispatchEvent(
     events::HistogramValue histogram_value,
diff --git a/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.h b/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.h
index 7e284b095..04bbda9 100644
--- a/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.h
+++ b/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.h
@@ -67,16 +67,16 @@
   GetFactoryInstance();
   void Shutdown() override;
 
+ private:
+  friend class BrowserContextKeyedAPIFactory<ScreenlockPrivateEventRouter>;
+
   // proximity_auth::ScreenlockBridge::Observer
   void OnScreenDidLock(proximity_auth::ScreenlockBridge::LockHandler::ScreenType
                            screen_type) override;
   void OnScreenDidUnlock(
       proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type)
       override;
-  void OnFocusedUserChanged(const std::string& user_id) override;
-
- private:
-  friend class BrowserContextKeyedAPIFactory<ScreenlockPrivateEventRouter>;
+  void OnFocusedUserChanged(const AccountId& account_id) override;
 
   // BrowserContextKeyedAPI
   static const char* service_name() {
diff --git a/chrome/browser/extensions/api/screenlock_private/screenlock_private_apitest.cc b/chrome/browser/extensions/api/screenlock_private/screenlock_private_apitest.cc
index e402931..87464cb 100644
--- a/chrome/browser/extensions/api/screenlock_private/screenlock_private_apitest.cc
+++ b/chrome/browser/extensions/api/screenlock_private/screenlock_private_apitest.cc
@@ -56,8 +56,8 @@
         g_browser_process->profile_manager()->GetProfileInfoCache();
     size_t index = info_cache.GetIndexOfProfileWithPath(profile()->GetPath());
     ASSERT_NE(std::string::npos, index);
-    info_cache.SetAuthInfoOfProfileAtIndex(index, kTestGaiaId,
-                                           base::UTF8ToUTF16(kTestUser));
+    info_cache.SetAuthInfoOfProfileAtIndex(
+        index, kTestGaiaId, base::UTF8ToUTF16(test_account_id_.GetUserEmail()));
     ExtensionApiTest::SetUpOnMainThread();
   }
 
@@ -78,9 +78,10 @@
     const std::string& content = *content::Details<std::string>(details).ptr();
     if (content == kAttemptClickAuthMessage) {
       proximity_auth::ScreenlockBridge::Get()->lock_handler()->SetAuthType(
-          kTestUser, proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK,
+          test_account_id_,
+          proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK,
           base::string16());
-      EasyUnlockService::Get(profile())->AttemptAuth(kTestUser);
+      EasyUnlockService::Get(profile())->AttemptAuth(test_account_id_);
     }
   }
 
@@ -90,6 +91,8 @@
   }
 
  private:
+  const AccountId test_account_id_ =
+      AccountId::FromUserEmailGaiaId(kTestUser, kTestGaiaId);
   content::NotificationRegistrar registrar_;
 
   DISALLOW_COPY_AND_ASSIGN(ScreenlockPrivateApiTest);
diff --git a/chrome/browser/extensions/api/sessions/sessions_apitest.cc b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
index c53b02b..2343a8d 100644
--- a/chrome/browser/extensions/api/sessions/sessions_apitest.cc
+++ b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/sync/chrome_sync_client.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/browser/sync/profile_sync_test_util.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -138,8 +139,10 @@
               "device_id")));
 
   Profile* profile = static_cast<Profile*>(context);
-  ProfileSyncServiceMock* sync_service = new ProfileSyncServiceMock(
-      make_scoped_ptr(new browser_sync::ChromeSyncClient(profile)), profile);
+  ProfileSyncServiceMock* sync_service =
+      new ProfileSyncServiceMock(CreateProfileSyncServiceParamsForTest(
+          make_scoped_ptr(new browser_sync::ChromeSyncClient(profile)),
+          profile));
   static_cast<browser_sync::ChromeSyncClient*>(sync_service->GetSyncClient())
       ->SetSyncApiComponentFactoryForTesting(factory.Pass());
   return make_scoped_ptr(sync_service);
diff --git a/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api_unittest.cc b/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api_unittest.cc
index 34ad282..e64820e 100644
--- a/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api_unittest.cc
+++ b/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api_unittest.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/browser/sync/profile_sync_test_util.h"
 #include "components/sync_driver/device_info.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "extensions/common/extension.h"
@@ -138,7 +139,7 @@
     public ProfileSyncServiceMock {
  public:
   explicit ProfileSyncServiceMockForExtensionTests(Profile* p)
-      : ProfileSyncServiceMock(p) {}
+      : ProfileSyncServiceMock(CreateProfileSyncServiceParamsForTest(p)) {}
   ~ProfileSyncServiceMockForExtensionTests() {}
 
   MOCK_METHOD0(Shutdown, void());
diff --git a/chrome/browser/extensions/api/storage/managed_value_store_cache.cc b/chrome/browser/extensions/api/storage/managed_value_store_cache.cc
index b6b1272..55179585 100644
--- a/chrome/browser/extensions/api/storage/managed_value_store_cache.cc
+++ b/chrome/browser/extensions/api/storage/managed_value_store_cache.cc
@@ -75,7 +75,6 @@
   void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
                                   const Extension* extension,
                                   bool is_update,
-                                  bool from_ephemeral,
                                   const std::string& old_name) override;
   void OnExtensionUninstalled(content::BrowserContext* browser_context,
                               const Extension* extension,
@@ -122,7 +121,6 @@
     content::BrowserContext* browser_context,
     const Extension* extension,
     bool is_update,
-    bool from_ephemeral,
     const std::string& old_name) {
   // Some extensions are installed on the first run before the ExtensionSystem
   // becomes ready. Wait until all of them are ready before registering the
diff --git a/chrome/browser/extensions/api/storage/settings_apitest.cc b/chrome/browser/extensions/api/storage/settings_apitest.cc
index 9ac951e..1fd45507 100644
--- a/chrome/browser/extensions/api/storage/settings_apitest.cc
+++ b/chrome/browser/extensions/api/storage/settings_apitest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/json/json_writer.h"
 #include "base/memory/ref_counted.h"
@@ -491,23 +493,26 @@
 
 IN_PROC_BROWSER_TEST_F(ExtensionSettingsApiTest, ManagedStorage) {
   // Set policies for the test extension.
-  scoped_ptr<base::DictionaryValue> policy = extensions::DictionaryBuilder()
-      .Set("string-policy", "value")
-      .Set("int-policy", -123)
-      .Set("double-policy", 456e7)
-      .SetBoolean("boolean-policy", true)
-      .Set("list-policy", extensions::ListBuilder()
-          .Append("one")
-          .Append("two")
-          .Append("three"))
-      .Set("dict-policy", extensions::DictionaryBuilder()
-          .Set("list", extensions::ListBuilder()
-              .Append(extensions::DictionaryBuilder()
-                  .Set("one", 1)
-                  .Set("two", 2))
-              .Append(extensions::DictionaryBuilder()
-                  .Set("three", 3))))
-      .Build();
+  scoped_ptr<base::DictionaryValue> policy =
+      extensions::DictionaryBuilder()
+          .Set("string-policy", "value")
+          .Set("int-policy", -123)
+          .Set("double-policy", 456e7)
+          .SetBoolean("boolean-policy", true)
+          .Set("list-policy",
+               std::move(
+                   extensions::ListBuilder().Append("one").Append("two").Append(
+                       "three")))
+          .Set("dict-policy",
+               extensions::DictionaryBuilder().Set(
+                   "list",
+                   std::move(extensions::ListBuilder()
+                                 .Append(extensions::DictionaryBuilder()
+                                             .Set("one", 1)
+                                             .Set("two", 2))
+                                 .Append(extensions::DictionaryBuilder().Set(
+                                     "three", 3)))))
+          .Build();
   SetPolicies(*policy);
   // Now run the extension.
   ASSERT_TRUE(RunExtensionTest("settings/managed_storage")) << message_;
diff --git a/chrome/browser/extensions/api/streams_private/streams_private_manifest_unittest.cc b/chrome/browser/extensions/api/streams_private/streams_private_manifest_unittest.cc
index c30947c..77c9667 100644
--- a/chrome/browser/extensions/api/streams_private/streams_private_manifest_unittest.cc
+++ b/chrome/browser/extensions/api/streams_private/streams_private_manifest_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/strings/string_number_conversions.h"
 #include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
 #include "extensions/common/constants.h"
@@ -29,12 +31,12 @@
   scoped_refptr<const Extension> extension =
       ExtensionBuilder()
           .SetID(extension_misc::kQuickOfficeExtensionId)
-          .SetManifest(
-               DictionaryBuilder()
-                   .Set("name", "MIME type handler test")
-                   .Set("version", "1.0.0")
-                   .Set("manifest_version", 2)
-                   .Set("mime_types", ListBuilder().Append("text/plain")))
+          .SetManifest(DictionaryBuilder()
+                           .Set("name", "MIME type handler test")
+                           .Set("version", "1.0.0")
+                           .Set("manifest_version", 2)
+                           .Set("mime_types",
+                                std::move(ListBuilder().Append("text/plain"))))
           .Build();
 
   ASSERT_TRUE(extension.get());
@@ -49,12 +51,12 @@
        MimeTypesHandlerMIMETypesNotWhitelisted) {
   scoped_refptr<const Extension> extension =
       ExtensionBuilder()
-          .SetManifest(
-               DictionaryBuilder()
-                   .Set("name", "MIME types test")
-                   .Set("version", "1.0.0")
-                   .Set("manifest_version", 2)
-                   .Set("mime_types", ListBuilder().Append("text/plain")))
+          .SetManifest(DictionaryBuilder()
+                           .Set("name", "MIME types test")
+                           .Set("version", "1.0.0")
+                           .Set("manifest_version", 2)
+                           .Set("mime_types",
+                                std::move(ListBuilder().Append("text/plain"))))
           .Build();
 
   ASSERT_TRUE(extension.get());
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
index f1276432..9fda275 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
@@ -31,7 +31,6 @@
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
-#include "extensions/browser/extension_util.h"
 #include "extensions/common/extension.h"
 #include "net/base/load_flags.h"
 #include "net/url_request/url_request.h"
@@ -207,8 +206,10 @@
 
   InstallTracker* tracker = InstallTracker::Get(browser_context());
   DCHECK(tracker);
-  if (util::IsExtensionInstalledPermanently(details().id, browser_context()) ||
-      tracker->GetActiveInstall(details().id)) {
+  bool is_installed =
+      extensions::ExtensionRegistry::Get(browser_context())->GetExtensionById(
+          details().id, extensions::ExtensionRegistry::EVERYTHING) != nullptr;
+  if (is_installed || tracker->GetActiveInstall(details().id)) {
     return RespondNow(BuildResponse(
         api::webstore_private::RESULT_ALREADY_INSTALLED,
         kAlreadyInstalledError));
@@ -426,26 +427,6 @@
         approval_->enable_launcher);
   }
 
-  // If the target extension has already been installed ephemerally and is
-  // up to date, it can be promoted to a regular installed extension and
-  // downloading from the Web Store is not necessary.
-  const Extension* extension = ExtensionRegistry::Get(browser_context())->
-      GetExtensionById(params->expected_id, ExtensionRegistry::EVERYTHING);
-  if (extension && approval_->dummy_extension.get() &&
-      util::IsEphemeralApp(extension->id(), browser_context()) &&
-      extension->version()->CompareTo(*approval_->dummy_extension->version()) >=
-          0) {
-    install_ui::ShowPostInstallUIForApproval(
-        browser_context(), *approval_, extension);
-
-    ExtensionService* extension_service =
-        ExtensionSystem::Get(browser_context())->extension_service();
-    extension_service->PromoteEphemeralApp(extension, false);
-    OnInstallSuccess(extension->id());
-    VLOG(1) << "Install success, sending response";
-    return RespondNow(NoArguments());
-  }
-
   // Balanced in OnExtensionInstallSuccess() or OnExtensionInstallFailure().
   AddRef();
 
@@ -544,7 +525,10 @@
   BundleInstaller::ItemList items;
   for (const auto& entry : params_->contents) {
     // Skip already-installed items.
-    if (util::IsExtensionInstalledPermanently(entry->id, browser_context()) ||
+    bool is_installed =
+        extensions::ExtensionRegistry::Get(browser_context())->GetExtensionById(
+            entry->id, extensions::ExtensionRegistry::EVERYTHING) != nullptr;
+    if (is_installed ||
         InstallTracker::Get(browser_context())->GetActiveInstall(entry->id)) {
       continue;
     }
diff --git a/chrome/browser/extensions/app_data_migrator_unittest.cc b/chrome/browser/extensions/app_data_migrator_unittest.cc
index a9d1e32..ba7d4a9 100644
--- a/chrome/browser/extensions/app_data_migrator_unittest.cc
+++ b/chrome/browser/extensions/app_data_migrator_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <string>
+#include <utility>
 
 #include "base/callback_forward.h"
 #include "base/threading/sequenced_worker_pool.h"
@@ -74,29 +75,31 @@
   if (platform_app) {
     app = ExtensionBuilder()
               .SetManifest(
-                   DictionaryBuilder()
-                       .Set("name", "test app")
-                       .Set("version", "1")
-                       .Set("app", DictionaryBuilder().Set(
-                                       "background",
-                                       DictionaryBuilder().Set(
-                                           "scripts", ListBuilder().Append(
-                                                          "background.js"))))
-                       .Set("permissions",
-                            ListBuilder().Append("unlimitedStorage")))
+                  DictionaryBuilder()
+                      .Set("name", "test app")
+                      .Set("version", "1")
+                      .Set("app",
+                           DictionaryBuilder().Set(
+                               "background",
+                               DictionaryBuilder().Set(
+                                   "scripts", std::move(ListBuilder().Append(
+                                                  "background.js")))))
+                      .Set("permissions",
+                           std::move(ListBuilder().Append("unlimitedStorage"))))
               .Build();
   } else {
-    app = ExtensionBuilder()
-              .SetManifest(DictionaryBuilder()
-                               .Set("name", "test app")
-                               .Set("version", "1")
-                               .Set("app", DictionaryBuilder().Set(
-                                               "launch",
-                                               DictionaryBuilder().Set(
-                                                   "local_path", "index.html")))
-                               .Set("permissions",
-                                    ListBuilder().Append("unlimitedStorage")))
-              .Build();
+    app =
+        ExtensionBuilder()
+            .SetManifest(
+                DictionaryBuilder()
+                    .Set("name", "test app")
+                    .Set("version", "1")
+                    .Set("app", DictionaryBuilder().Set(
+                                    "launch", DictionaryBuilder().Set(
+                                                  "local_path", "index.html")))
+                    .Set("permissions",
+                         std::move(ListBuilder().Append("unlimitedStorage"))))
+            .Build();
   }
   return app;
 }
diff --git a/chrome/browser/extensions/blob_reader.cc b/chrome/browser/extensions/blob_reader.cc
index dbcc212..43edf0e1 100644
--- a/chrome/browser/extensions/blob_reader.cc
+++ b/chrome/browser/extensions/blob_reader.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/extensions/blob_reader.h"
 
+#include <limits>
+
 #include "base/format_macros.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -35,11 +37,11 @@
 
 BlobReader::~BlobReader() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); }
 
-void BlobReader::SetByteRange(int64 offset, int64 length) {
+void BlobReader::SetByteRange(int64_t offset, int64_t length) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   CHECK_GE(offset, 0);
   CHECK_GT(length, 0);
-  CHECK_LE(offset, kint64max - length);
+  CHECK_LE(offset, std::numeric_limits<int64_t>::max() - length);
 
   net::HttpRequestHeaders headers;
   headers.SetHeader(
@@ -58,7 +60,7 @@
 void BlobReader::OnURLFetchComplete(const net::URLFetcher* source) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   scoped_ptr<std::string> response(new std::string);
-  int64 first = 0, last = 0, length = 0;
+  int64_t first = 0, last = 0, length = 0;
   source->GetResponseAsString(response.get());
   source->GetResponseHeaders()->GetContentRange(&first, &last, &length);
   callback_.Run(response.Pass(), length);
diff --git a/chrome/browser/extensions/blob_reader.h b/chrome/browser/extensions/blob_reader.h
index bc500377..0e0c2d2 100644
--- a/chrome/browser/extensions/blob_reader.h
+++ b/chrome/browser/extensions/blob_reader.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_BLOB_READER_H_
 #define CHROME_BROWSER_EXTENSIONS_BLOB_READER_H_
 
+#include <stdint.h>
+
 #include <string>
 
 #include "base/callback.h"
@@ -26,15 +28,14 @@
   // is the total size of the Blob, and may be larger than |blob_data->size()|.
   // |blob_total_size| is -1 if it cannot be determined.
   typedef base::Callback<void(scoped_ptr<std::string> blob_data,
-                              int64 blob_total_size)>
-      BlobReadCallback;
+                              int64_t blob_total_size)> BlobReadCallback;
 
   BlobReader(Profile* profile,
              const std::string& blob_uuid,
              BlobReadCallback callback);
   ~BlobReader() override;
 
-  void SetByteRange(int64 offset, int64 length);
+  void SetByteRange(int64_t offset, int64_t length);
 
   void Start();
 
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h
index c5e61d3..598858f8 100644
--- a/chrome/browser/extensions/crx_installer.h
+++ b/chrome/browser/extensions/crx_installer.h
@@ -198,9 +198,6 @@
   void set_install_immediately(bool val) {
     set_install_flag(kInstallFlagInstallImmediately, val);
   }
-  void set_is_ephemeral(bool val) {
-    set_install_flag(kInstallFlagIsEphemeral, val);
-  }
   void set_do_not_sync(bool val) {
     set_install_flag(kInstallFlagDoNotSync, val);
   }
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index a510d742..300035fb 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -422,7 +422,6 @@
                                   Manifest::INTERNAL,
                                   browser(),
                                   Extension::NO_FLAGS,
-                                  false,
                                   false);
 }
 
@@ -431,7 +430,7 @@
     int expected_change) {
   return InstallOrUpdateExtension(
       std::string(), path, INSTALL_UI_TYPE_AUTO_CONFIRM, expected_change,
-      Manifest::INTERNAL, browser(), Extension::FROM_WEBSTORE, true, false);
+      Manifest::INTERNAL, browser(), Extension::FROM_WEBSTORE, true);
 }
 
 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
@@ -446,8 +445,7 @@
                                   Manifest::INTERNAL,
                                   browser(),
                                   Extension::NO_FLAGS,
-                                  true,
-                                  false);
+                                  true);
 }
 
 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
@@ -464,8 +462,7 @@
                                   Manifest::INTERNAL,
                                   browser,
                                   creation_flags,
-                                  true,
-                                  false);
+                                  true);
 }
 
 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
@@ -481,8 +478,7 @@
                                   install_source,
                                   browser(),
                                   Extension::NO_FLAGS,
-                                  true,
-                                  false);
+                                  true);
 }
 
 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
@@ -493,8 +489,7 @@
     Manifest::Location install_source,
     Browser* browser,
     Extension::InitFromValueFlags creation_flags,
-    bool install_immediately,
-    bool is_ephemeral) {
+    bool install_immediately) {
   ExtensionService* service =
       extensions::ExtensionSystem::Get(profile())->extension_service();
   ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
@@ -528,7 +523,6 @@
     installer->set_creation_flags(creation_flags);
     installer->set_install_source(install_source);
     installer->set_install_immediately(install_immediately);
-    installer->set_is_ephemeral(is_ephemeral);
     if (!installer->is_gallery_install()) {
       installer->set_off_store_install_allow_reason(
           extensions::CrxInstaller::OffStoreInstallAllowedInTest);
diff --git a/chrome/browser/extensions/extension_browsertest.h b/chrome/browser/extensions/extension_browsertest.h
index 65d1d92e..328a915 100644
--- a/chrome/browser/extensions/extension_browsertest.h
+++ b/chrome/browser/extensions/extension_browsertest.h
@@ -201,26 +201,9 @@
                                     install_source,
                                     browser(),
                                     creation_flags,
-                                    false,
                                     false);
   }
 
-  const extensions::Extension* InstallEphemeralAppWithSourceAndFlags(
-      const base::FilePath& path,
-      int expected_change,
-      extensions::Manifest::Location install_source,
-      extensions::Extension::InitFromValueFlags creation_flags) {
-    return InstallOrUpdateExtension(std::string(),
-                                    path,
-                                    INSTALL_UI_TYPE_NONE,
-                                    expected_change,
-                                    install_source,
-                                    browser(),
-                                    creation_flags,
-                                    false,
-                                    true);
-  }
-
   // Begins install process but simulates a user cancel.
   const extensions::Extension* StartInstallButCancel(
       const base::FilePath& path) {
@@ -375,8 +358,7 @@
       extensions::Manifest::Location install_source,
       Browser* browser,
       extensions::Extension::InitFromValueFlags creation_flags,
-      bool wait_for_idle,
-      bool is_ephemeral);
+      bool wait_for_idle);
 
   // Make the current channel "dev" for the duration of the test.
   extensions::ScopedCurrentChannel current_channel_;
diff --git a/chrome/browser/extensions/extension_context_menu_model_unittest.cc b/chrome/browser/extensions/extension_context_menu_model_unittest.cc
index c1469db..8f25568 100644
--- a/chrome/browser/extensions/extension_context_menu_model_unittest.cc
+++ b/chrome/browser/extensions/extension_context_menu_model_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/extensions/extension_context_menu_model.h"
 
+#include <utility>
+
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/extensions/active_script_controller.h"
@@ -159,7 +161,8 @@
       .Set("manifest_version", 2)
       .Set(action_key, DictionaryBuilder().Pass());
   if (!host_permission.empty())
-    manifest.Set("permissions", ListBuilder().Append(host_permission));
+    manifest.Set("permissions",
+                 std::move(ListBuilder().Append(host_permission)));
   scoped_refptr<const Extension> extension =
       ExtensionBuilder()
           .SetManifest(manifest.Pass())
diff --git a/chrome/browser/extensions/extension_disabled_ui.cc b/chrome/browser/extensions/extension_disabled_ui.cc
index 640af2ff..69970c77 100644
--- a/chrome/browser/extensions/extension_disabled_ui.cc
+++ b/chrome/browser/extensions/extension_disabled_ui.cc
@@ -486,11 +486,6 @@
 void AddExtensionDisabledError(ExtensionService* service,
                                const Extension* extension,
                                bool is_remote_install) {
-  // Do not display notifications for ephemeral apps that have been disabled.
-  // Instead, a prompt will be shown the next time the app is launched.
-  if (util::IsEphemeralApp(extension->id(), service->profile()))
-    return;
-
   extensions::ExtensionResource image = extensions::IconsInfo::GetIconResource(
       extension, kIconSize, ExtensionIconSet::MATCH_BIGGER);
   gfx::Size size(kIconSize, kIconSize);
diff --git a/chrome/browser/extensions/extension_disabled_ui_browsertest.cc b/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
index 7c16a03..9b8bb66 100644
--- a/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
+++ b/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
@@ -26,6 +26,7 @@
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/test_extension_registry_observer.h"
 #include "extensions/common/extension.h"
+#include "extensions/test/extension_test_message_listener.h"
 #include "net/url_request/test_url_request_interceptor.h"
 #include "sync/protocol/extension_specifics.pb.h"
 #include "sync/protocol/sync.pb.h"
@@ -129,10 +130,14 @@
   ASSERT_TRUE(GetExtensionDisabledGlobalError());
   const size_t size_before = registry_->enabled_extensions().size();
 
+  ExtensionTestMessageListener listener("v2.onInstalled", false);
+  listener.set_failure_message("FAILED");
   service_->GrantPermissionsAndEnableExtension(extension);
   EXPECT_EQ(size_before + 1, registry_->enabled_extensions().size());
   EXPECT_EQ(0u, registry_->disabled_extensions().size());
   ASSERT_FALSE(GetExtensionDisabledGlobalError());
+  // Expect onInstalled event to fire.
+  EXPECT_TRUE(listener.WaitUntilSatisfied());
 }
 
 // Tests uninstalling an extension that was disabled due to higher permissions.
diff --git a/chrome/browser/extensions/extension_install_prompt.cc b/chrome/browser/extensions/extension_install_prompt.cc
index 9a90a37..619f600 100644
--- a/chrome/browser/extensions/extension_install_prompt.cc
+++ b/chrome/browser/extensions/extension_install_prompt.cc
@@ -206,8 +206,6 @@
       return "EXTERNAL_INSTALL_PROMPT";
     case ExtensionInstallPrompt::POST_INSTALL_PERMISSIONS_PROMPT:
       return "POST_INSTALL_PERMISSIONS_PROMPT";
-    case ExtensionInstallPrompt::LAUNCH_PROMPT:
-      return "LAUNCH_PROMPT";
     case ExtensionInstallPrompt::REMOTE_INSTALL_PROMPT:
       return "REMOTE_INSTALL_PROMPT";
     case ExtensionInstallPrompt::REPAIR_PROMPT:
@@ -216,6 +214,9 @@
       return "DELEGATED_PERMISSIONS_PROMPT";
     case ExtensionInstallPrompt::DELEGATED_BUNDLE_PERMISSIONS_PROMPT:
       return "DELEGATED_BUNDLE_PERMISSIONS_PROMPT";
+    case ExtensionInstallPrompt::LAUNCH_PROMPT_DEPRECATED:
+      NOTREACHED();
+      // fall through:
     case ExtensionInstallPrompt::UNSET_PROMPT_TYPE:
     case ExtensionInstallPrompt::NUM_PROMPT_TYPES:
       break;
@@ -407,6 +408,13 @@
          type_ == POST_INSTALL_PERMISSIONS_PROMPT;
 }
 
+bool ExtensionInstallPrompt::Prompt::ShouldUseTabModalDialog() const {
+  // For inline install, we want the install prompt to be tab modal so that the
+  // dialog is always clearly associated with the page that made the inline
+  // install request.
+  return type_ == INLINE_INSTALL_PROMPT;
+}
+
 void ExtensionInstallPrompt::Prompt::AppendRatingStars(
     StarAppender appender, void* data) const {
   CHECK(appender);
@@ -727,13 +735,8 @@
       profile_ &&
       extensions::ExtensionPrefs::Get(profile_)->HasDisableReason(
           extension->id(), extensions::Extension::DISABLE_REMOTE_INSTALL);
-  bool is_ephemeral =
-      extensions::util::IsEphemeralApp(extension->id(), profile_);
-
   PromptType type = UNSET_PROMPT_TYPE;
-  if (is_ephemeral)
-    type = LAUNCH_PROMPT;
-  else if (is_remote_install)
+  if (is_remote_install)
     type = REMOTE_INSTALL_PROMPT;
   else
     type = RE_ENABLE_PROMPT;
@@ -900,7 +903,6 @@
     case INLINE_INSTALL_PROMPT:
     case EXTERNAL_INSTALL_PROMPT:
     case INSTALL_PROMPT:
-    case LAUNCH_PROMPT:
     case POST_INSTALL_PERMISSIONS_PROMPT:
     case REMOTE_INSTALL_PROMPT:
     case REPAIR_PROMPT:
@@ -913,6 +915,7 @@
       prompt_->set_bundle(bundle_);
       break;
     }
+    case LAUNCH_PROMPT_DEPRECATED:
     default:
       NOTREACHED() << "Unknown message";
       return;
diff --git a/chrome/browser/extensions/extension_install_prompt.h b/chrome/browser/extensions/extension_install_prompt.h
index f558877..6cf7320 100644
--- a/chrome/browser/extensions/extension_install_prompt.h
+++ b/chrome/browser/extensions/extension_install_prompt.h
@@ -63,7 +63,7 @@
     PERMISSIONS_PROMPT,
     EXTERNAL_INSTALL_PROMPT,
     POST_INSTALL_PERMISSIONS_PROMPT,
-    LAUNCH_PROMPT,
+    LAUNCH_PROMPT_DEPRECATED,
     REMOTE_INSTALL_PROMPT,
     REPAIR_PROMPT,
     DELEGATED_PERMISSIONS_PROMPT,
@@ -128,6 +128,8 @@
 
     bool ShouldShowPermissions() const;
 
+    bool ShouldUseTabModalDialog() const;
+
     // Getters for webstore metadata. Only populated when the type is
     // INLINE_INSTALL_PROMPT, EXTERNAL_INSTALL_PROMPT, or REPAIR_PROMPT.
 
diff --git a/chrome/browser/extensions/extension_install_prompt_unittest.cc b/chrome/browser/extensions/extension_install_prompt_unittest.cc
index 82c723f1..8eb35c1a 100644
--- a/chrome/browser/extensions/extension_install_prompt_unittest.cc
+++ b/chrome/browser/extensions/extension_install_prompt_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
@@ -98,15 +100,18 @@
       FeatureSwitch::scripts_require_action(), true);
 
   scoped_refptr<const Extension> extension =
-      ExtensionBuilder().SetManifest(
-          DictionaryBuilder().Set("name", "foo")
-                             .Set("version", "1.0")
-                             .Set("manifest_version", 2)
-                             .Set("description", "Random Ext")
-                             .Set("permissions",
-                                  ListBuilder().Append("http://*/*")
-                                               .Append("http://www.google.com/")
-                                               .Append("tabs"))).Build();
+      ExtensionBuilder()
+          .SetManifest(DictionaryBuilder()
+                           .Set("name", "foo")
+                           .Set("version", "1.0")
+                           .Set("manifest_version", 2)
+                           .Set("description", "Random Ext")
+                           .Set("permissions",
+                                std::move(ListBuilder()
+                                              .Append("http://*/*")
+                                              .Append("http://www.google.com/")
+                                              .Append("tabs"))))
+          .Build();
 
   content::TestWebContentsFactory factory;
   ExtensionInstallPrompt prompt(factory.CreateWebContents(profile()));
@@ -127,15 +132,17 @@
 TEST_F(ExtensionInstallPromptUnitTest,
        DelegatedPromptShowsOptionalPermissions) {
   scoped_refptr<const Extension> extension =
-      ExtensionBuilder().SetManifest(
-          DictionaryBuilder().Set("name", "foo")
-                             .Set("version", "1.0")
-                             .Set("manifest_version", 2)
-                             .Set("description", "Random Ext")
-                             .Set("permissions",
-                                  ListBuilder().Append("clipboardRead"))
-                             .Set("optional_permissions",
-                                  ListBuilder().Append("tabs"))).Build();
+      ExtensionBuilder()
+          .SetManifest(DictionaryBuilder()
+                           .Set("name", "foo")
+                           .Set("version", "1.0")
+                           .Set("manifest_version", 2)
+                           .Set("description", "Random Ext")
+                           .Set("permissions", std::move(ListBuilder().Append(
+                                                   "clipboardRead")))
+                           .Set("optional_permissions",
+                                std::move(ListBuilder().Append("tabs"))))
+          .Build();
 
   content::TestWebContentsFactory factory;
   ExtensionInstallPrompt prompt(factory.CreateWebContents(profile()));
diff --git a/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
index 4af1301aa..54b732e 100644
--- a/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
+++ b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
 #include "base/strings/string_number_conversions.h"
@@ -197,15 +199,15 @@
       const std::string& id,
       Manifest::Location location) {
     ExtensionBuilder builder;
-    builder.SetManifest(DictionaryBuilder()
-                            .Set("name", std::string("Extension " + index))
-                            .Set("version", "1.0")
-                            .Set("manifest_version", 2)
-                            .Set("chrome_settings_overrides",
-                                 DictionaryBuilder().Set(
-                                     "startup_pages",
-                                     ListBuilder().Append(
-                                         "http://www.google.com"))));
+    builder.SetManifest(
+        DictionaryBuilder()
+            .Set("name", std::string("Extension " + index))
+            .Set("version", "1.0")
+            .Set("manifest_version", 2)
+            .Set("chrome_settings_overrides",
+                 DictionaryBuilder().Set("startup_pages",
+                                         std::move(ListBuilder().Append(
+                                             "http://www.google.com")))));
     builder.SetLocation(location);
     builder.SetID(id);
     service_->AddExtension(builder.Build().get());
@@ -242,12 +244,12 @@
       const std::string& id,
       Manifest::Location location) {
     ExtensionBuilder builder;
-    builder.SetManifest(DictionaryBuilder()
-                            .Set("name", std::string("Extension " + index))
-                            .Set("version", "1.0")
-                            .Set("manifest_version", 2)
-                            .Set("permissions",
-                                 ListBuilder().Append("proxy")));
+    builder.SetManifest(
+        DictionaryBuilder()
+            .Set("name", std::string("Extension " + index))
+            .Set("version", "1.0")
+            .Set("manifest_version", 2)
+            .Set("permissions", std::move(ListBuilder().Append("proxy"))));
 
     builder.SetLocation(location);
     builder.SetID(id);
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index e8023b3b..0664cfb4 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -566,10 +566,8 @@
   if (extension && extension->was_installed_by_custodian())
     creation_flags |= Extension::WAS_INSTALLED_BY_CUSTODIAN;
 
-  if (extension) {
-    installer->set_is_ephemeral(extension_prefs_->IsEphemeralApp(id));
+  if (extension)
     installer->set_do_not_sync(extension_prefs_->DoNotSync(id));
-  }
 
   installer->set_creation_flags(creation_flags);
 
@@ -1512,12 +1510,9 @@
           extensions::ExtensionSystem::Get(GetBrowserContext())->app_sorting();
       app_sorting->SetExtensionVisible(
           extension->id(),
-          extension->ShouldDisplayInNewTabPage() &&
-              !extension_prefs_->IsEphemeralApp(extension->id()));
-      if (!extension_prefs_->IsEphemeralApp(extension->id())) {
-        app_sorting->EnsureValidOrdinals(extension->id(),
-                                         syncer::StringOrdinal());
-      }
+          extension->ShouldDisplayInNewTabPage());
+      app_sorting->EnsureValidOrdinals(extension->id(),
+                                       syncer::StringOrdinal());
     }
 
     registry_->AddEnabled(extension);
@@ -1691,6 +1686,10 @@
       pending_extension_manager()->GetById(id);
   if (pending_extension_info) {
     if (!pending_extension_info->ShouldAllowInstall(extension)) {
+      // Hack for crbug.com/558299, see comment on DeleteThemeDoNotUse.
+      if (extension->is_theme() && pending_extension_info->is_from_sync())
+        ExtensionSyncService::Get(profile_)->DeleteThemeDoNotUse(*extension);
+
       pending_extension_manager()->Remove(id);
 
       LOG(WARNING) << "ShouldAllowInstall() returned false for "
@@ -1762,12 +1761,6 @@
                               extension->GetType(), 100);
     UMA_HISTOGRAM_ENUMERATION("Extensions.UpdateSource",
                               extension->location(), Manifest::NUM_LOCATIONS);
-
-    // A fully installed app cannot be demoted to an ephemeral app.
-    if ((install_flags & extensions::kInstallFlagIsEphemeral) &&
-        !extension_prefs_->IsEphemeralApp(id)) {
-      install_flags &= ~static_cast<int>(extensions::kInstallFlagIsEphemeral);
-    }
   }
 
   const Extension::State initial_state =
@@ -1857,7 +1850,6 @@
     const syncer::StringOrdinal& page_ordinal,
     const std::string& install_parameter) {
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  bool was_ephemeral = extension_prefs_->IsEphemeralApp(extension->id());
   extension_prefs_->OnExtensionInstalled(
       extension, initial_state, page_ordinal, install_flags, install_parameter);
   delayed_installs_.Remove(extension->id());
@@ -1869,11 +1861,11 @@
     app_data_migrator_->DoMigrationAndReply(
         old, extension,
         base::Bind(&ExtensionService::FinishInstallation, AsWeakPtr(),
-                   make_scoped_refptr(extension), was_ephemeral));
+                   make_scoped_refptr(extension)));
     return;
   }
 
-  FinishInstallation(extension, was_ephemeral);
+  FinishInstallation(extension);
 }
 
 void ExtensionService::MaybeFinishDelayedInstallation(
@@ -1918,15 +1910,14 @@
   CHECK(extension.get());
   delayed_installs_.Remove(extension_id);
 
-  bool was_ephemeral = extension_prefs_->IsEphemeralApp(extension->id());
   if (!extension_prefs_->FinishDelayedInstallInfo(extension_id))
     NOTREACHED();
 
-  FinishInstallation(extension.get(), was_ephemeral);
+  FinishInstallation(extension.get());
 }
 
 void ExtensionService::FinishInstallation(
-    const Extension* extension, bool was_ephemeral) {
+    const Extension* extension) {
   const extensions::Extension* existing_extension =
       GetInstalledExtension(extension->id());
   bool is_update = false;
@@ -1935,11 +1926,8 @@
     is_update = true;
     old_name = existing_extension->name();
   }
-  bool from_ephemeral =
-      was_ephemeral && !extension_prefs_->IsEphemeralApp(extension->id());
-
   registry_->TriggerOnWillBeInstalled(
-      extension, is_update, from_ephemeral, old_name);
+      extension, is_update, old_name);
 
   // Unpacked extensions default to allowing file access, but if that has been
   // overridden, don't reset the value.
@@ -1959,72 +1947,6 @@
     MaybeFinishDelayedInstallations();
 }
 
-void ExtensionService::PromoteEphemeralApp(
-    const extensions::Extension* extension, bool is_from_sync) {
-  DCHECK(GetInstalledExtension(extension->id()) &&
-         extension_prefs_->IsEphemeralApp(extension->id()));
-
-  if (extension->RequiresSortOrdinal()) {
-    AppSorting* app_sorting =
-        extensions::ExtensionSystem::Get(GetBrowserContext())->app_sorting();
-    app_sorting->SetExtensionVisible(extension->id(),
-                                     extension->ShouldDisplayInNewTabPage());
-
-    if (!is_from_sync) {
-      // Reset the sort ordinals of the app to ensure it is added to the default
-      // position, like newly installed apps would.
-      app_sorting->ClearOrdinals(extension->id());
-    }
-
-    app_sorting->EnsureValidOrdinals(extension->id(), syncer::StringOrdinal());
-  }
-
-  // Remove the ephemeral flags from the preferences.
-  extension_prefs_->OnEphemeralAppPromoted(extension->id());
-
-  // Fire install-related events to allow observers to handle the promotion
-  // of the ephemeral app.
-  registry_->TriggerOnWillBeInstalled(
-      extension,
-      true /* is update */,
-      true /* from ephemeral */,
-      extension->name() /* old name */);
-
-  if (registry_->enabled_extensions().Contains(extension->id())) {
-    // If the app is already enabled and loaded, fire the load events to allow
-    // observers to handle the promotion of the ephemeral app.
-    content::NotificationService::current()->Notify(
-        extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
-        content::Source<Profile>(profile_),
-        content::Details<const Extension>(extension));
-
-    registry_->TriggerOnLoaded(extension);
-  } else {
-    // Cached ephemeral apps may be updated and disabled due to permissions
-    // increase. The app can be enabled (as long as no other disable reasons
-    // exist) as the install was user-acknowledged.
-    int disable_mask = Extension::DISABLE_NONE;
-    if (!is_from_sync)
-      disable_mask |= Extension::DISABLE_PERMISSIONS_INCREASE;
-
-    int other_disable_reasons =
-        extension_prefs_->GetDisableReasons(extension->id()) & ~disable_mask;
-    if (!other_disable_reasons) {
-      if (extension_prefs_->DidExtensionEscalatePermissions(extension->id()))
-        GrantPermissionsAndEnableExtension(extension);
-      else
-        EnableExtension(extension->id());
-    }
-  }
-
-  registry_->TriggerOnInstalled(extension, true);
-
-  if (!is_from_sync) {
-    ExtensionSyncService::Get(profile_)->SyncExtensionChangeIfNeeded(
-        *extension);
-  }
-}
-
 const Extension* ExtensionService::GetPendingExtensionUpdate(
     const std::string& id) const {
   return delayed_installs_.GetByID(id);
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index c7536efec..4cd10fe5 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -336,13 +336,6 @@
   // Checks for delayed installation for all pending installs.
   void MaybeFinishDelayedInstallations();
 
-  // Promotes an ephemeral app to a regular installed app. Ephemeral apps
-  // are already installed in extension system (albiet transiently) and only
-  // need to be exposed in the UI. Set |is_from_sync| to true if the
-  // install was initiated via sync.
-  void PromoteEphemeralApp(
-      const extensions::Extension* extension, bool is_from_sync);
-
   // ExtensionHost of background page calls this method right after its render
   // view has been created.
   void DidCreateRenderViewForBackgroundPage(extensions::ExtensionHost* host);
@@ -447,7 +440,7 @@
   }
 
   void FinishInstallationForTest(const extensions::Extension* extension) {
-    FinishInstallation(extension, false /* not ephemeral */);
+    FinishInstallation(extension);
   }
 #endif
 
@@ -549,10 +542,8 @@
       const extensions::Extension* extension,
       extensions::UnloadedExtensionInfo::Reason reason);
 
-  // Common helper to finish installing the given extension. |was_ephemeral|
-  // should be true if the extension was previously installed and ephemeral.
-  void FinishInstallation(const extensions::Extension* extension,
-                          bool was_ephemeral);
+  // Common helper to finish installing the given extension.
+  void FinishInstallation(const extensions::Extension* extension);
 
   // Disables the extension if the privilege level has increased
   // (e.g., due to an upgrade).
diff --git a/chrome/browser/extensions/extension_service_sync_unittest.cc b/chrome/browser/extensions/extension_service_sync_unittest.cc
index b41fe0c6..d9da886 100644
--- a/chrome/browser/extensions/extension_service_sync_unittest.cc
+++ b/chrome/browser/extensions/extension_service_sync_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <map>
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -1408,6 +1409,40 @@
   }
 }
 
+// Regression test for crbug.com/558299
+TEST_F(ExtensionServiceSyncTest, DontSyncThemes) {
+  InitializeEmptyExtensionService();
+
+  // The user has enabled sync.
+  ProfileSyncServiceFactory::GetForProfile(profile())->SetSyncSetupCompleted();
+  // Make sure ExtensionSyncService is created, so it'll be notified of changes.
+  extension_sync_service();
+
+  service()->Init();
+  ASSERT_TRUE(service()->is_ready());
+
+  syncer::FakeSyncChangeProcessor* processor =
+      new syncer::FakeSyncChangeProcessor;
+  extension_sync_service()->MergeDataAndStartSyncing(
+      syncer::EXTENSIONS,
+      syncer::SyncDataList(),
+      make_scoped_ptr(processor),
+      make_scoped_ptr(new syncer::SyncErrorFactoryMock));
+
+  processor->changes().clear();
+
+  // Sanity check: Installing an extension should result in a sync change.
+  InstallCRX(data_dir().AppendASCII("good.crx"), INSTALL_NEW);
+  EXPECT_EQ(1u, processor->changes().size());
+
+  processor->changes().clear();
+
+  // Installing a theme should not result in a sync change (themes are handled
+  // separately by ThemeSyncableService).
+  InstallCRX(data_dir().AppendASCII("theme.crx"), INSTALL_NEW);
+  EXPECT_TRUE(processor->changes().empty());
+}
+
 #if defined(ENABLE_SUPERVISED_USERS)
 
 class ExtensionServiceTestSupervised : public ExtensionServiceSyncTest,
@@ -1800,16 +1835,17 @@
   const std::string kName("extension");
   scoped_refptr<const Extension> extension =
       extensions::ExtensionBuilder()
-      .SetLocation(Manifest::INTERNAL)
-      .SetManifest(
-          extensions::DictionaryBuilder()
-              .Set("name", kName)
-              .Set("description", "foo")
-              .Set("manifest_version", 2)
-              .Set("version", "1.0")
-              .Set("permissions", extensions::ListBuilder().Append("*://*/*")))
-      .SetID(crx_file::id_util::GenerateId(kName))
-      .Build();
+          .SetLocation(Manifest::INTERNAL)
+          .SetManifest(
+              extensions::DictionaryBuilder()
+                  .Set("name", kName)
+                  .Set("description", "foo")
+                  .Set("manifest_version", 2)
+                  .Set("version", "1.0")
+                  .Set("permissions",
+                       std::move(extensions::ListBuilder().Append("*://*/*"))))
+          .SetID(crx_file::id_util::GenerateId(kName))
+          .Build();
 
   // Install and enable it.
   service()->AddExtension(extension.get());
diff --git a/chrome/browser/extensions/extension_service_test_with_install.cc b/chrome/browser/extensions/extension_service_test_with_install.cc
index 7f6e37f8..f2cedef 100644
--- a/chrome/browser/extensions/extension_service_test_with_install.cc
+++ b/chrome/browser/extensions/extension_service_test_with_install.cc
@@ -399,7 +399,6 @@
     content::BrowserContext* browser_context,
     const Extension* extension,
     bool is_update,
-    bool from_ephemeral,
     const std::string& old_name) {
   installed_ = extension;
   was_update_ = is_update;
diff --git a/chrome/browser/extensions/extension_service_test_with_install.h b/chrome/browser/extensions/extension_service_test_with_install.h
index b9bb169..0ad20eb 100644
--- a/chrome/browser/extensions/extension_service_test_with_install.h
+++ b/chrome/browser/extensions/extension_service_test_with_install.h
@@ -122,7 +122,6 @@
   void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
                                   const Extension* extension,
                                   bool is_update,
-                                  bool from_ephemeral,
                                   const std::string& old_name) override;
 
   // TODO(treib,devlin): Make these private and add accessors as needed.
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index 355da39..72c553b3 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -949,7 +949,6 @@
   void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
                                   const Extension* extension,
                                   bool is_update,
-                                  bool from_ephemeral,
                                   const std::string& old_name) override {
     last_extension_installed = extension->id();
   }
diff --git a/chrome/browser/extensions/extension_storage_monitor.cc b/chrome/browser/extensions/extension_storage_monitor.cc
index 7da8fef7..25581ed 100644
--- a/chrome/browser/extensions/extension_storage_monitor.cc
+++ b/chrome/browser/extensions/extension_storage_monitor.cc
@@ -46,11 +46,9 @@
 // The rate at which we would like to observe storage events.
 const int kStorageEventRateSec = 30;
 
-// Set the thresholds for the first notification. Ephemeral apps have a lower
-// threshold than installed extensions and apps. Once a threshold is exceeded,
+// Set the thresholds for the first notification. Once a threshold is exceeded,
 // it will be doubled to throttle notifications.
 const int64 kMBytes = 1024 * 1024;
-const int64 kEphemeralAppInitialThreshold = 250 * kMBytes;
 const int64 kExtensionInitialThreshold = 1000 * kMBytes;
 
 // Notifications have an ID so that we can update them.
@@ -277,7 +275,6 @@
     content::BrowserContext* context)
     : enable_for_all_extensions_(false),
       initial_extension_threshold_(kExtensionInitialThreshold),
-      initial_ephemeral_threshold_(kEphemeralAppInitialThreshold),
       observer_rate_(base::TimeDelta::FromSeconds(kStorageEventRateSec)),
       context_(context),
       extension_prefs_(ExtensionPrefs::Get(context)),
@@ -324,11 +321,8 @@
     content::BrowserContext* browser_context,
     const Extension* extension,
     bool is_update,
-    bool from_ephemeral,
     const std::string& old_name) {
-  // If an ephemeral app was promoted to a regular installed app, we may need to
-  // increase its next threshold.
-  if (!from_ephemeral || !ShouldMonitorStorageFor(extension))
+  if (!ShouldMonitorStorageFor(extension))
     return;
 
   if (!enable_for_all_extensions_) {
@@ -494,12 +488,8 @@
   if (!ShouldMonitorStorageFor(extension))
     return;
 
-  // First apply this feature only to experimental ephemeral apps. If it works
-  // well, roll it out to all extensions and apps.
-  bool should_enforce =
-      (enable_for_all_extensions_ ||
-       extension_prefs_->IsEphemeralApp(extension->id())) &&
-      IsStorageNotificationEnabled(extension->id());
+  bool should_enforce = (enable_for_all_extensions_) &&
+                        IsStorageNotificationEnabled(extension->id());
 
   bool for_metrics = ShouldGatherMetricsFor(extension);
 
@@ -616,9 +606,7 @@
   if (next_threshold == 0) {
     // The next threshold is written to the prefs after the initial threshold is
     // exceeded.
-    next_threshold = extension_prefs_->IsEphemeralApp(extension_id)
-                         ? initial_ephemeral_threshold_
-                         : initial_extension_threshold_;
+    next_threshold = initial_extension_threshold_;
   }
   return next_threshold;
 }
diff --git a/chrome/browser/extensions/extension_storage_monitor.h b/chrome/browser/extensions/extension_storage_monitor.h
index d739851..df3b8ef 100644
--- a/chrome/browser/extensions/extension_storage_monitor.h
+++ b/chrome/browser/extensions/extension_storage_monitor.h
@@ -65,7 +65,6 @@
   void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
                                   const Extension* extension,
                                   bool is_update,
-                                  bool from_ephemeral,
                                   const std::string& old_name) override;
   void OnExtensionUninstalled(content::BrowserContext* browser_context,
                               const Extension* extension,
@@ -118,10 +117,8 @@
   bool enable_for_all_extensions_;
 
   // The first notification is shown after the initial threshold is exceeded.
-  // Ephemeral apps have a lower threshold than fully installed extensions.
   // A lower threshold is set by tests.
   int64 initial_extension_threshold_;
-  int64 initial_ephemeral_threshold_;
 
   // The rate at which we would like to receive storage updates
   // from QuotaManager. Overridden in tests.
diff --git a/chrome/browser/extensions/extension_storage_monitor_browsertest.cc b/chrome/browser/extensions/extension_storage_monitor_browsertest.cc
index 1865a13..10b7c25 100644
--- a/chrome/browser/extensions/extension_storage_monitor_browsertest.cc
+++ b/chrome/browser/extensions/extension_storage_monitor_browsertest.cc
@@ -97,11 +97,6 @@
     return storage_monitor_->initial_extension_threshold_;
   }
 
-  int64 GetInitialEphemeralThreshold() {
-    CHECK(storage_monitor_);
-    return storage_monitor_->initial_ephemeral_threshold_;
-  }
-
   void DisableForInstalledExtensions() {
     CHECK(storage_monitor_);
     storage_monitor_->enable_for_all_extensions_ = false;
@@ -114,19 +109,6 @@
     return extension;
   }
 
-  const Extension* InitWriteDataEphemeralApp() {
-    // The threshold for installed extensions should be higher than ephemeral
-    // apps.
-    storage_monitor_->initial_extension_threshold_ =
-        storage_monitor_->initial_ephemeral_threshold_ * 4;
-
-    base::FilePath path = test_data_dir_.AppendASCII(kWriteDataApp);
-    const Extension* extension = InstallEphemeralAppWithSourceAndFlags(
-        path, 1, Manifest::INTERNAL, Extension::NO_FLAGS);
-    EXPECT_TRUE(extension);
-    return extension;
-  }
-
   std::string GetNotificationId(const std::string& extension_id) {
     return monitor()->GetNotificationId(extension_id);
   }
@@ -160,7 +142,6 @@
     // to trigger notifications in these tests.
     storage_monitor_->enable_for_all_extensions_ = true;
     storage_monitor_->initial_extension_threshold_ = kInitialUsageThreshold;
-    storage_monitor_->initial_ephemeral_threshold_ = kInitialUsageThreshold;
 
     // To ensure storage events are dispatched from QuotaManager immediately.
     storage_monitor_->observer_rate_ = base::TimeDelta();
@@ -257,52 +238,6 @@
   WriteBytesNotExpectingNotification(extension, next_data_size);
 }
 
-// Verify that thresholds for ephemeral apps are reset when they are
-// promoted to regular installed apps.
-IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, EphemeralAppLowUsage) {
-  const Extension* extension = InitWriteDataEphemeralApp();
-  ASSERT_TRUE(extension);
-  WriteBytesExpectingNotification(extension, GetInitialEphemeralThreshold());
-
-  // Store the number of bytes until the next threshold is reached.
-  int64 next_threshold = GetNextStorageThreshold(extension->id());
-  int64 next_data_size = next_threshold - GetInitialEphemeralThreshold();
-  ASSERT_GT(next_data_size, 0);
-  EXPECT_GE(GetInitialExtensionThreshold(), next_threshold);
-
-  // Promote the ephemeral app.
-  ExtensionService* service =
-      ExtensionSystem::Get(profile())->extension_service();
-  service->PromoteEphemeralApp(extension, false);
-
-  // The next threshold should now be equal to the initial threshold for
-  // extensions (which is higher than the initial threshold for ephemeral apps).
-  EXPECT_EQ(GetInitialExtensionThreshold(),
-            GetNextStorageThreshold(extension->id()));
-
-  // Since the threshold was increased, a notification should not be
-  // triggered.
-  WriteBytesNotExpectingNotification(extension, next_data_size);
-}
-
-// Verify that thresholds for ephemeral apps are not reset when they are
-// promoted to regular installed apps if their usage is higher than the initial
-// threshold for installed extensions.
-IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, EphemeralAppWithHighUsage) {
-  const Extension* extension = InitWriteDataEphemeralApp();
-  ASSERT_TRUE(extension);
-  WriteBytesExpectingNotification(extension, GetInitialExtensionThreshold());
-  int64 saved_next_threshold = GetNextStorageThreshold(extension->id());
-
-  // Promote the ephemeral app.
-  ExtensionService* service =
-      ExtensionSystem::Get(profile())->extension_service();
-  service->PromoteEphemeralApp(extension, false);
-
-  // The next threshold should not have changed.
-  EXPECT_EQ(saved_next_threshold, GetNextStorageThreshold(extension->id()));
-}
-
 // Ensure that monitoring is disabled for installed extensions if
 // |enable_for_all_extensions_| is false. This test can be removed if monitoring
 // is eventually enabled for all extensions.
diff --git a/chrome/browser/extensions/extension_sync_service.cc b/chrome/browser/extensions/extension_sync_service.cc
index 29c6f90..c94a634 100644
--- a/chrome/browser/extensions/extension_sync_service.cc
+++ b/chrome/browser/extensions/extension_sync_service.cc
@@ -87,6 +87,14 @@
          (type == syncer::APPS && extension.is_app());
 }
 
+// Predicate for PendingExtensionManager.
+// TODO(treib,devlin): The !is_theme check shouldn't be necessary anymore after
+// all the bad data from crbug.com/558299 has been cleaned up, after M52 or so.
+bool ShouldAllowInstall(const Extension* extension) {
+  return !extension->is_theme() &&
+         extensions::sync_helper::IsSyncable(extension);
+}
+
 syncer::SyncDataList ToSyncerSyncDataList(
     const std::vector<ExtensionSyncData>& data) {
   syncer::SyncDataList result;
@@ -145,7 +153,7 @@
 
 void ExtensionSyncService::SyncExtensionChangeIfNeeded(
     const Extension& extension) {
-  if (ignore_updates_ || !extensions::util::ShouldSync(&extension, profile_))
+  if (ignore_updates_ || !ShouldSync(extension))
     return;
 
   syncer::ModelType type =
@@ -307,6 +315,7 @@
   syncer::ModelType type = extension_sync_data.is_app() ? syncer::APPS
                                                         : syncer::EXTENSIONS;
   const std::string& id = extension_sync_data.id();
+  SyncBundle* bundle = GetSyncBundle(type);
   // Note: |extension| may be null if it hasn't been installed yet.
   const Extension* extension =
       ExtensionRegistry::Get(profile_)->GetInstalledExtension(id);
@@ -314,10 +323,20 @@
   // case is where an app becomes an extension or vice versa, and we end up with
   // a zombie extension that won't go away.
   // TODO(treib): Is this still true?
-  if (extension && !IsCorrectSyncType(*extension, type))
+  if (extension && !IsCorrectSyncType(*extension, type)) {
+    // Special hack: There was a bug where themes incorrectly ended up in the
+    // syncer::EXTENSIONS type. If we get incoming sync data for a theme, clean
+    // it up. crbug.com/558299
+    // TODO(treib,devlin): Remove this after M52 or so.
+    if (extension->is_theme()) {
+      // First tell the bundle about the extension, so that it won't just ignore
+      // the deletion.
+      bundle->ApplySyncData(extension_sync_data);
+      bundle->PushSyncDeletion(id, extension_sync_data.GetSyncData());
+    }
     return;
+  }
 
-  SyncBundle* bundle = GetSyncBundle(type);
   // Forward to the bundle. This will just update the list of synced extensions.
   bundle->ApplySyncData(extension_sync_data);
 
@@ -438,12 +457,6 @@
       extension_prefs->ReplaceDisableReasons(id, disable_reasons);
   }
 
-  // If the target extension has already been installed ephemerally, it can
-  // be promoted to a regular installed extension and downloading from the Web
-  // Store is not necessary.
-  if (extension && extensions::util::IsEphemeralApp(id, profile_))
-    extension_service()->PromoteEphemeralApp(extension, true);
-
   // Update the incognito flag.
   extensions::util::SetIsIncognitoEnabled(
       id, profile_, extension_sync_data.incognito_enabled());
@@ -492,7 +505,7 @@
             id,
             extension_sync_data.update_url(),
             extension_sync_data.version(),
-            extensions::sync_helper::IsSyncable,
+            ShouldAllowInstall,
             extension_sync_data.remote_install(),
             extension_sync_data.installed_by_custodian())) {
       LOG(WARNING) << "Could not add pending extension for " << id;
@@ -502,7 +515,7 @@
       // extension), so that GetAllSyncData() continues to send it.
     }
     // Track pending extensions so that we can return them in GetAllSyncData().
-    bundle->AddPendingExtensionData(id, extension_sync_data);
+    bundle->AddPendingExtensionData(extension_sync_data);
     check_for_updates = true;
   }
 
@@ -567,6 +580,12 @@
   flare_ = flare;
 }
 
+void ExtensionSyncService::DeleteThemeDoNotUse(const Extension& theme) {
+  DCHECK(theme.is_theme());
+  GetSyncBundle(syncer::EXTENSIONS)->PushSyncDeletion(
+      theme.id(), CreateSyncData(theme).GetSyncData());
+}
+
 ExtensionService* ExtensionSyncService::extension_service() const {
   return ExtensionSystem::Get(profile_)->extension_service();
 }
@@ -595,8 +614,9 @@
   DCHECK_EQ(profile_, browser_context);
   // Don't bother syncing if the extension will be re-installed momentarily.
   if (reason == extensions::UNINSTALL_REASON_REINSTALL ||
-      !extensions::util::ShouldSync(extension, profile_))
+      !ShouldSync(*extension)) {
     return;
+  }
 
   // TODO(tim): If we get here and IsSyncing is false, this will cause
   // "back from the dead" style bugs, because sync will add-back the extension
@@ -681,7 +701,7 @@
     std::vector<ExtensionSyncData>* sync_data_list) const {
   for (const scoped_refptr<const Extension>& extension : extensions) {
     if (IsCorrectSyncType(*extension, type) &&
-        extensions::util::ShouldSync(extension.get(), profile_) &&
+        ShouldSync(*extension) &&
         (include_everything ||
          ExtensionPrefs::Get(profile_)->NeedsSync(extension->id()))) {
       // We should never have pending data for an installed extension.
@@ -690,3 +710,9 @@
     }
   }
 }
+
+bool ExtensionSyncService::ShouldSync(const Extension& extension) const {
+  // Themes are handled by the ThemeSyncableService.
+  return extensions::util::ShouldSync(&extension, profile_) &&
+         !extension.is_theme();
+}
diff --git a/chrome/browser/extensions/extension_sync_service.h b/chrome/browser/extensions/extension_sync_service.h
index 1135bd0..59c042e 100644
--- a/chrome/browser/extensions/extension_sync_service.h
+++ b/chrome/browser/extensions/extension_sync_service.h
@@ -67,6 +67,12 @@
   void SetSyncStartFlareForTesting(
       const syncer::SyncableService::StartSyncFlare& flare);
 
+  // Special hack: There was a bug where themes incorrectly ended up in the
+  // syncer::EXTENSIONS type. This is for cleaning up the data. crbug.com/558299
+  // DO NOT USE FOR ANYTHING ELSE!
+  // TODO(treib,devlin): Remove this after M52 or so.
+  void DeleteThemeDoNotUse(const extensions::Extension& theme);
+
  private:
   FRIEND_TEST_ALL_PREFIXES(TwoClientAppsSyncTest, UnexpectedLaunchType);
   FRIEND_TEST_ALL_PREFIXES(ExtensionDisabledGlobalErrorTest,
@@ -117,6 +123,11 @@
       bool include_everything,
       std::vector<extensions::ExtensionSyncData>* sync_data_list) const;
 
+  // Returns whether the given extension should be synced by this class.
+  // Filters out unsyncable extensions as well as themes (which are handled by
+  // ThemeSyncableService instead).
+  bool ShouldSync(const extensions::Extension& extension) const;
+
   // The normal profile associated with this ExtensionSyncService.
   Profile* profile_;
 
diff --git a/chrome/browser/extensions/extension_ui_util.cc b/chrome/browser/extensions/extension_ui_util.cc
index 4cf4fa8..55c72fcb 100644
--- a/chrome/browser/extensions/extension_ui_util.cc
+++ b/chrome/browser/extensions/extension_ui_util.cc
@@ -31,8 +31,7 @@
 
 bool ShouldDisplayInAppLauncher(const Extension* extension,
                                 content::BrowserContext* context) {
-  return CanDisplayInAppLauncher(extension, context) &&
-         !util::IsEphemeralApp(extension->id(), context);
+  return CanDisplayInAppLauncher(extension, context);
 }
 
 bool CanDisplayInAppLauncher(const Extension* extension,
@@ -44,20 +43,17 @@
 bool ShouldDisplayInNewTabPage(const Extension* extension,
                                content::BrowserContext* context) {
   return extension->ShouldDisplayInNewTabPage() &&
-      !IsBlockedByPolicy(extension, context) &&
-      !util::IsEphemeralApp(extension->id(), context);
+      !IsBlockedByPolicy(extension, context);
 }
 
 bool ShouldDisplayInExtensionSettings(const Extension* extension,
                                       content::BrowserContext* context) {
-  return extension->ShouldDisplayInExtensionSettings() &&
-      !util::IsEphemeralApp(extension->id(), context);
+  return extension->ShouldDisplayInExtensionSettings();
 }
 
 bool ShouldNotBeVisible(const Extension* extension,
                         content::BrowserContext* context) {
-  return extension->ShouldNotBeVisible() ||
-      util::IsEphemeralApp(extension->id(), context);
+  return extension->ShouldNotBeVisible();
 }
 
 }  // namespace ui_util
diff --git a/chrome/browser/extensions/extension_util.cc b/chrome/browser/extensions/extension_util.cc
index d2d3065..7fe28854e 100644
--- a/chrome/browser/extensions/extension_util.cc
+++ b/chrome/browser/extensions/extension_util.cc
@@ -276,7 +276,6 @@
 bool ShouldSync(const Extension* extension,
                 content::BrowserContext* context) {
   return sync_helper::IsSyncable(extension) &&
-         !util::IsEphemeralApp(extension->id(), context) &&
          !ExtensionPrefs::Get(context)->DoNotSync(extension->id());
 }
 
diff --git a/chrome/browser/extensions/location_bar_controller_unittest.cc b/chrome/browser/extensions/location_bar_controller_unittest.cc
index dfc4c439..e89db7b 100644
--- a/chrome/browser/extensions/location_bar_controller_unittest.cc
+++ b/chrome/browser/extensions/location_bar_controller_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <string>
+#include <utility>
 
 #include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
@@ -69,9 +70,9 @@
                                 const std::string& name) {
     DictionaryBuilder manifest;
     manifest.Set("name", name)
-            .Set("version", "1.0.0")
-            .Set("manifest_version", 2)
-            .Set("permissions", ListBuilder().Append("tabs"));
+        .Set("version", "1.0.0")
+        .Set("manifest_version", 2)
+        .Set("permissions", std::move(ListBuilder().Append("tabs")));
     if (has_page_actions) {
       manifest.Set("page_action", DictionaryBuilder()
               .Set("default_title", "Hello"));
diff --git a/chrome/browser/extensions/permission_messages_unittest.cc b/chrome/browser/extensions/permission_messages_unittest.cc
index 895bc2d..c2a9530 100644
--- a/chrome/browser/extensions/permission_messages_unittest.cc
+++ b/chrome/browser/extensions/permission_messages_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -48,13 +50,14 @@
   ~PermissionMessagesUnittest() override {}
 
  protected:
-  void CreateAndInstallAppWithPermissions(ListBuilder& required_permissions,
-                                          ListBuilder& optional_permissions) {
+  void CreateAndInstallAppWithPermissions(ListBuilder required_permissions,
+                                          ListBuilder optional_permissions) {
     app_ = test_util::BuildApp(ExtensionBuilder().Pass())
                .MergeManifest(
-                    DictionaryBuilder()
-                        .Set("permissions", required_permissions)
-                        .Set("optional_permissions", optional_permissions))
+                   DictionaryBuilder()
+                       .Set("permissions", std::move(required_permissions))
+                       .Set("optional_permissions",
+                            std::move(optional_permissions)))
                .SetID(crx_file::id_util::GenerateId("app"))
                .SetLocation(Manifest::INTERNAL)
                .Build();
@@ -62,13 +65,14 @@
   }
 
   void CreateAndInstallExtensionWithPermissions(
-      ListBuilder& required_permissions,
-      ListBuilder& optional_permissions) {
+      ListBuilder required_permissions,
+      ListBuilder optional_permissions) {
     app_ = test_util::BuildExtension(ExtensionBuilder().Pass())
                .MergeManifest(
-                    DictionaryBuilder()
-                        .Set("permissions", required_permissions)
-                        .Set("optional_permissions", optional_permissions))
+                   DictionaryBuilder()
+                       .Set("permissions", std::move(required_permissions))
+                       .Set("optional_permissions",
+                            std::move(optional_permissions)))
                .SetID(crx_file::id_util::GenerateId("extension"))
                .SetLocation(Manifest::INTERNAL)
                .Build();
@@ -129,8 +133,7 @@
 // other (the 'history' permission has superset permissions).
 TEST_F(PermissionMessagesUnittest, HistoryHidesTabsMessage) {
   CreateAndInstallExtensionWithPermissions(
-      ListBuilder().Append("tabs").Append("history").Pass(),
-      ListBuilder().Pass());
+      std::move(ListBuilder().Append("tabs").Append("history")), ListBuilder());
 
   ASSERT_EQ(1U, required_permissions().size());
   EXPECT_EQ(
@@ -144,8 +147,8 @@
 // permission, only the new coalesced message is displayed.
 TEST_F(PermissionMessagesUnittest, MixedPermissionMessagesCoalesceOnceGranted) {
   CreateAndInstallExtensionWithPermissions(
-      ListBuilder().Append("tabs").Pass(),
-      ListBuilder().Append("history").Pass());
+      std::move(ListBuilder().Append("tabs")),
+      std::move(ListBuilder().Append("history")));
 
   ASSERT_EQ(1U, required_permissions().size());
   EXPECT_EQ(
@@ -183,8 +186,8 @@
 TEST_F(PermissionMessagesUnittest,
        AntiTest_PromptCanRequestSubsetOfAlreadyGrantedPermissions) {
   CreateAndInstallExtensionWithPermissions(
-      ListBuilder().Append("history").Pass(),
-      ListBuilder().Append("tabs").Pass());
+      std::move(ListBuilder().Append("history")),
+      std::move(ListBuilder().Append("tabs")));
 
   ASSERT_EQ(1U, required_permissions().size());
   EXPECT_EQ(
@@ -224,8 +227,8 @@
 TEST_F(PermissionMessagesUnittest,
        AntiTest_PromptCanBeEmptyButCausesChangeInPermissions) {
   CreateAndInstallExtensionWithPermissions(
-      ListBuilder().Append("tabs").Pass(),
-      ListBuilder().Append("sessions").Pass());
+      std::move(ListBuilder().Append("tabs")),
+      std::move(ListBuilder().Append("sessions")));
 
   ASSERT_EQ(1U, required_permissions().size());
   EXPECT_EQ(
diff --git a/chrome/browser/extensions/process_manager_browsertest.cc b/chrome/browser/extensions/process_manager_browsertest.cc
index d1e3013..ea8626c4 100644
--- a/chrome/browser/extensions/process_manager_browsertest.cc
+++ b/chrome/browser/extensions/process_manager_browsertest.cc
@@ -102,9 +102,10 @@
         // To allow ExecuteScript* to work.
         .Set("content_security_policy",
              "script-src 'self' 'unsafe-eval'; object-src 'self'")
-        .Set("sandbox", DictionaryBuilder().Set(
-                            "pages", ListBuilder().Append("sandboxed.html")))
-        .Set("web_accessible_resources", ListBuilder().Append("*"));
+        .Set("sandbox",
+             DictionaryBuilder().Set(
+                 "pages", std::move(ListBuilder().Append("sandboxed.html"))))
+        .Set("web_accessible_resources", std::move(ListBuilder().Append("*")));
 
     if (has_background_process) {
       manifest.Set("background", DictionaryBuilder().Set("page", "bg.html"));
diff --git a/chrome/browser/extensions/scripting_permissions_modifier_unittest.cc b/chrome/browser/extensions/scripting_permissions_modifier_unittest.cc
index 1b1a71da..6b37a5d 100644
--- a/chrome/browser/extensions/scripting_permissions_modifier_unittest.cc
+++ b/chrome/browser/extensions/scripting_permissions_modifier_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/extensions/extension_service_test_base.h"
 #include "chrome/browser/extensions/extension_util.h"
@@ -40,19 +42,19 @@
   }
 
   DictionaryBuilder script;
-  script.Set("matches", scriptable_host_list.Pass())
-      .Set("js", ListBuilder().Append("foo.js"));
+  script.Set("matches", std::move(scriptable_host_list))
+      .Set("js", std::move(ListBuilder().Append("foo.js")));
 
   return ExtensionBuilder()
       .SetLocation(location)
-      .SetManifest(
-          DictionaryBuilder()
-              .Set("name", name)
-              .Set("description", "foo")
-              .Set("manifest_version", 2)
-              .Set("version", "0.1.2.3")
-              .Set("content_scripts", ListBuilder().Append(script.Pass()))
-              .Set("permissions", explicit_host_list.Pass()))
+      .SetManifest(DictionaryBuilder()
+                       .Set("name", name)
+                       .Set("description", "foo")
+                       .Set("manifest_version", 2)
+                       .Set("version", "0.1.2.3")
+                       .Set("content_scripts",
+                            std::move(ListBuilder().Append(script.Pass())))
+                       .Set("permissions", std::move(explicit_host_list)))
       .SetID(crx_file::id_util::GenerateId(name))
       .Build();
 }
diff --git a/chrome/browser/extensions/service_worker_apitest.cc b/chrome/browser/extensions/service_worker_apitest.cc
index 0d7a9a97..fbfc5614 100644
--- a/chrome/browser/extensions/service_worker_apitest.cc
+++ b/chrome/browser/extensions/service_worker_apitest.cc
@@ -24,6 +24,7 @@
 #include "content/public/test/background_sync_test_util.h"
 #include "content/public/test/browser_test_utils.h"
 #include "extensions/browser/extension_host.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/process_manager.h"
 #include "extensions/test/background_page_watcher.h"
 #include "extensions/test/extension_test_message_listener.h"
@@ -214,6 +215,44 @@
       error);
 }
 
+IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
+  base::ScopedTempDir scoped_temp_dir;
+  ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+  base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
+                                .AppendASCII("update")
+                                .AppendASCII("service_worker.pem");
+  base::FilePath path_v1 = PackExtensionWithOptions(
+      test_data_dir_.AppendASCII("service_worker")
+          .AppendASCII("update")
+          .AppendASCII("v1"),
+      scoped_temp_dir.path().AppendASCII("v1.crx"), pem_path, base::FilePath());
+  base::FilePath path_v2 = PackExtensionWithOptions(
+      test_data_dir_.AppendASCII("service_worker")
+          .AppendASCII("update")
+          .AppendASCII("v2"),
+      scoped_temp_dir.path().AppendASCII("v2.crx"), pem_path, base::FilePath());
+  const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
+
+  ExtensionTestMessageListener listener_v1("Pong from version 1", false);
+  listener_v1.set_failure_message("FAILURE_V1");
+  // Install version 1.0 of the extension.
+  ASSERT_TRUE(InstallExtension(path_v1, 1));
+  EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
+                  ->enabled_extensions()
+                  .GetByID(kId));
+  EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
+
+  ExtensionTestMessageListener listener_v2("Pong from version 2", false);
+  listener_v2.set_failure_message("FAILURE_V2");
+
+  // Update to version 2.0.
+  EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
+  EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
+                  ->enabled_extensions()
+                  .GetByID(kId));
+  EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
+}
+
 IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, FetchArbitraryPaths) {
   const Extension* extension =
       StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
diff --git a/chrome/browser/extensions/shared_module_service_unittest.cc b/chrome/browser/extensions/shared_module_service_unittest.cc
index 79baa35efa..0f1d1e3 100644
--- a/chrome/browser/extensions/shared_module_service_unittest.cc
+++ b/chrome/browser/extensions/shared_module_service_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/extensions/shared_module_service.h"
 
+#include <utility>
+
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
@@ -36,8 +38,8 @@
          .Set("version", version)
          .Set("manifest_version", 2);
   if (!import_id.empty()) {
-    builder.Set("import",
-                ListBuilder().Append(DictionaryBuilder().Set("id", import_id)));
+    builder.Set("import", std::move(ListBuilder().Append(
+                              DictionaryBuilder().Set("id", import_id))));
   }
   scoped_ptr<base::DictionaryValue> manifest = builder.Build();
 
@@ -128,8 +130,9 @@
           .Set("version", "1.0")
           .Set("manifest_version", 2)
           .Set("export",
-               DictionaryBuilder().Set("resources",
-                                       ListBuilder().Append("foo.js"))).Build();
+               DictionaryBuilder().Set(
+                   "resources", std::move(ListBuilder().Append("foo.js"))))
+          .Build();
   scoped_refptr<Extension> shared_module =
       ExtensionBuilder()
           .SetManifest(manifest.Pass())
@@ -168,8 +171,9 @@
           .Set("version", "1.0")
           .Set("manifest_version", 2)
           .Set("export",
-               DictionaryBuilder().Set("resources",
-                                       ListBuilder().Append("foo.js"))).Build();
+               DictionaryBuilder().Set(
+                   "resources", std::move(ListBuilder().Append("foo.js"))))
+          .Build();
   scoped_refptr<Extension> shared_module_1 =
       ExtensionBuilder()
           .SetManifest(manifest_1.Pass())
@@ -184,8 +188,9 @@
           .Set("version", "1.0")
           .Set("manifest_version", 2)
           .Set("export",
-               DictionaryBuilder().Set("resources",
-                                       ListBuilder().Append("foo.js"))).Build();
+               DictionaryBuilder().Set(
+                   "resources", std::move(ListBuilder().Append("foo.js"))))
+          .Build();
   scoped_refptr<Extension> shared_module_2 =
       ExtensionBuilder()
           .SetManifest(manifest_2.Pass())
@@ -244,11 +249,11 @@
           .Set("version", "1.0")
           .Set("manifest_version", 2)
           .Set("export",
-               DictionaryBuilder().Set("whitelist",
-                                       ListBuilder()
-                                           .Append(whitelisted_id))
-                                  .Set("resources",
-                                       ListBuilder().Append("*"))).Build();
+               DictionaryBuilder()
+                   .Set("whitelist",
+                        std::move(ListBuilder().Append(whitelisted_id)))
+                   .Set("resources", std::move(ListBuilder().Append("*"))))
+          .Build();
   scoped_refptr<Extension> shared_module =
       ExtensionBuilder()
           .SetManifest(manifest.Pass())
diff --git a/chrome/browser/extensions/sync_bundle.cc b/chrome/browser/extensions/sync_bundle.cc
index 42bcf9e..dd79337 100644
--- a/chrome/browser/extensions/sync_bundle.cc
+++ b/chrome/browser/extensions/sync_bundle.cc
@@ -80,9 +80,9 @@
 }
 
 void SyncBundle::AddPendingExtensionData(
-    const std::string& id,
     const ExtensionSyncData& extension_sync_data) {
-  pending_sync_data_.insert(std::make_pair(id, extension_sync_data));
+  pending_sync_data_.insert(std::make_pair(extension_sync_data.id(),
+                                           extension_sync_data));
 }
 
 std::vector<ExtensionSyncData> SyncBundle::GetPendingExtensionData() const {
diff --git a/chrome/browser/extensions/sync_bundle.h b/chrome/browser/extensions/sync_bundle.h
index 2e34a10..944812a 100644
--- a/chrome/browser/extensions/sync_bundle.h
+++ b/chrome/browser/extensions/sync_bundle.h
@@ -59,9 +59,8 @@
   // locally.
   bool HasPendingExtensionData(const std::string& id) const;
 
-  // Adds pending data for the extension with the given |id|.
-  void AddPendingExtensionData(const std::string& id,
-                               const ExtensionSyncData& sync_data);
+  // Adds pending data for the given extension.
+  void AddPendingExtensionData(const ExtensionSyncData& extension_sync_data);
 
   // Returns a vector of all the pending extension data.
   std::vector<ExtensionSyncData> GetPendingExtensionData() const;
diff --git a/chrome/browser/extensions/test_extension_environment.cc b/chrome/browser/extensions/test_extension_environment.cc
index 7044795e2..b9c80bc 100644
--- a/chrome/browser/extensions/test_extension_environment.cc
+++ b/chrome/browser/extensions/test_extension_environment.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/extensions/test_extension_environment.h"
 
+#include <utility>
+
 #include "base/command_line.h"
 #include "base/json/json_writer.h"
 #include "base/run_loop.h"
@@ -59,8 +61,8 @@
       .Set("app", extensions::DictionaryBuilder().Set(
                       "background",
                       extensions::DictionaryBuilder().Set(
-                          "scripts",
-                          extensions::ListBuilder().Append("background.js"))))
+                          "scripts", std::move(extensions::ListBuilder().Append(
+                                         "background.js")))))
       .Build();
 }
 
diff --git a/chrome/browser/extensions/updater/extension_updater.cc b/chrome/browser/extensions/updater/extension_updater.cc
index 569cea8b7..da7611d 100644
--- a/chrome/browser/extensions/updater/extension_updater.cc
+++ b/chrome/browser/extensions/updater/extension_updater.cc
@@ -655,7 +655,6 @@
     content::BrowserContext* browser_context,
     const Extension* extension,
     bool is_update,
-    bool from_ephemeral,
     const std::string& old_name) {
   throttle_info_.erase(extension->id());
 }
diff --git a/chrome/browser/extensions/updater/extension_updater.h b/chrome/browser/extensions/updater/extension_updater.h
index 5d95d05..e5cebd4 100644
--- a/chrome/browser/extensions/updater/extension_updater.h
+++ b/chrome/browser/extensions/updater/extension_updater.h
@@ -221,7 +221,6 @@
   void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
                                   const Extension* extension,
                                   bool is_update,
-                                  bool from_ephemeral,
                                   const std::string& old_name) override;
 
   // Send a notification that update checks are starting.
diff --git a/chrome/browser/extensions/webstore_installer_browsertest.cc b/chrome/browser/extensions/webstore_installer_browsertest.cc
index a4cfca8..3a77e3c 100644
--- a/chrome/browser/extensions/webstore_installer_browsertest.cc
+++ b/chrome/browser/extensions/webstore_installer_browsertest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/extensions/webstore_installer.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -112,13 +114,13 @@
 
 IN_PROC_BROWSER_TEST_F(WebstoreInstallerBrowserTest, WebstoreInstall) {
   scoped_ptr<base::DictionaryValue> manifest(
-      DictionaryBuilder().Set("name", kExtensionName)
-                         .Set("description", "Foo")
-                         .Set("manifest_version", 2)
-                         .Set("version", "1.0")
-                         .Set("permissions",
-                              ListBuilder().Append("tabs"))
-                         .Build());
+      DictionaryBuilder()
+          .Set("name", kExtensionName)
+          .Set("description", "Foo")
+          .Set("manifest_version", 2)
+          .Set("version", "1.0")
+          .Set("permissions", std::move(ListBuilder().Append("tabs")))
+          .Build());
 
   content::WebContents* active_web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -153,13 +155,13 @@
 
 IN_PROC_BROWSER_TEST_F(WebstoreInstallerBrowserTest, SimultaneousInstall) {
   scoped_ptr<base::DictionaryValue> manifest(
-      DictionaryBuilder().Set("name", kExtensionName)
-                         .Set("description", "Foo")
-                         .Set("manifest_version", 2)
-                         .Set("version", "1.0")
-                         .Set("permissions",
-                              ListBuilder().Append("tabs"))
-                         .Build());
+      DictionaryBuilder()
+          .Set("name", kExtensionName)
+          .Set("description", "Foo")
+          .Set("manifest_version", 2)
+          .Set("version", "1.0")
+          .Set("permissions", std::move(ListBuilder().Append("tabs")))
+          .Build());
 
   content::WebContents* active_web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
diff --git a/chrome/browser/extensions/webstore_standalone_installer.cc b/chrome/browser/extensions/webstore_standalone_installer.cc
index 760cb00e..84565c9 100644
--- a/chrome/browser/extensions/webstore_standalone_installer.cc
+++ b/chrome/browser/extensions/webstore_standalone_installer.cc
@@ -18,7 +18,6 @@
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
-#include "extensions/browser/extension_util.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_urls.h"
 #include "url/gurl.h"
@@ -209,28 +208,6 @@
       // Don't install a blacklisted extension.
       install_result = webstore_install::BLACKLISTED;
       install_message = kExtensionIsBlacklisted;
-    } else if (util::IsEphemeralApp(installed_extension->id(), profile_)) {
-      // If the target extension has already been installed ephemerally and is
-      // up to date, it can be promoted to a regular installed extension and
-      // downloading from the Web Store is not necessary.
-      scoped_refptr<const Extension> extension_to_install =
-          GetLocalizedExtensionForDisplay();
-      if (!extension_to_install.get()) {
-        CompleteInstall(webstore_install::INVALID_MANIFEST,
-                        kInvalidManifestError);
-        return;
-      }
-
-      if (installed_extension->version()->CompareTo(
-              *extension_to_install->version()) < 0) {
-        // If the existing extension is out of date, proceed with the install
-        // to update the extension.
-        done = false;
-      } else {
-        install_ui::ShowPostInstallUIForApproval(
-            profile_, *approval, installed_extension);
-        extension_service->PromoteEphemeralApp(installed_extension, false);
-      }
     } else if (!extension_service->IsExtensionEnabled(id_)) {
       // If the extension is installed but disabled, and not blacklisted,
       // enable it.
diff --git a/chrome/browser/extensions/webstore_startup_installer_browsertest.cc b/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
index e87138e..badcddc7 100644
--- a/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
+++ b/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/command_line.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -136,16 +138,20 @@
 
   // We're forced to construct a hosted app dynamically because we need the
   // app to run on a declared URL, but we don't know the port ahead of time.
-  scoped_refptr<const Extension> hosted_app = ExtensionBuilder()
-      .SetManifest(DictionaryBuilder()
-          .Set("name", "hosted app")
-          .Set("version", "1")
-          .Set("app", DictionaryBuilder()
-              .Set("urls", ListBuilder().Append(kInstallUrl.spec()))
-              .Set("launch", DictionaryBuilder()
-                  .Set("web_url", kInstallUrl.spec())))
-          .Set("manifest_version", 2))
-      .Build();
+  scoped_refptr<const Extension> hosted_app =
+      ExtensionBuilder()
+          .SetManifest(
+              DictionaryBuilder()
+                  .Set("name", "hosted app")
+                  .Set("version", "1")
+                  .Set("app",
+                       DictionaryBuilder()
+                           .Set("urls", std::move(ListBuilder().Append(
+                                            kInstallUrl.spec())))
+                           .Set("launch", DictionaryBuilder().Set(
+                                              "web_url", kInstallUrl.spec())))
+                  .Set("manifest_version", 2))
+          .Build();
   ASSERT_TRUE(hosted_app.get());
 
   ExtensionService* extension_service =
diff --git a/chrome/browser/extensions/zipfile_installer_unittest.cc b/chrome/browser/extensions/zipfile_installer_unittest.cc
index a42b9c5..d4421e64 100644
--- a/chrome/browser/extensions/zipfile_installer_unittest.cc
+++ b/chrome/browser/extensions/zipfile_installer_unittest.cc
@@ -46,7 +46,6 @@
   void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
                                   const Extension* extension,
                                   bool is_update,
-                                  bool from_ephemeral,
                                   const std::string& old_name) override {
     last_extension_installed = extension->id();
     quit_closure_.Run();
diff --git a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
index 67c026a..809497a 100644
--- a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
+++ b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
@@ -12,8 +12,8 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/common/channel_info.h"
+#include "chrome/common/pref_names.h"
 #include "components/browser_sync/browser/profile_sync_service.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
 #include "components/sync_driver/about_sync_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/browser/extension_registry.h"
@@ -172,10 +172,9 @@
 void ChromeInternalLogSource::PopulateDataReductionProxyLogs(
     SystemLogsResponse* response) {
   PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
-  bool is_data_reduction_proxy_enabled = prefs->HasPrefPath(
-          data_reduction_proxy::prefs::kDataReductionProxyEnabled) &&
-      prefs->GetBoolean(
-          data_reduction_proxy::prefs::kDataReductionProxyEnabled);
+  bool is_data_reduction_proxy_enabled =
+      prefs->HasPrefPath(prefs::kDataSaverEnabled) &&
+      prefs->GetBoolean(prefs::kDataSaverEnabled);
   (*response)[kDataReductionProxyKey] = is_data_reduction_proxy_enabled ?
       "enabled" : "disabled";
 }
diff --git a/chrome/browser/geolocation/geolocation_infobar_delegate_android.cc b/chrome/browser/geolocation/geolocation_infobar_delegate_android.cc
index 3cffcc44..73de4aca4 100644
--- a/chrome/browser/geolocation/geolocation_infobar_delegate_android.cc
+++ b/chrome/browser/geolocation/geolocation_infobar_delegate_android.cc
@@ -28,6 +28,7 @@
     const std::string& display_languages,
     const PermissionSetCallback& callback)
     : PermissionInfobarDelegate(requesting_frame,
+                                content::PermissionType::GEOLOCATION,
                                 CONTENT_SETTINGS_TYPE_GEOLOCATION,
                                 callback),
       requesting_frame_(requesting_frame),
diff --git a/chrome/browser/geolocation/geolocation_permission_context.cc b/chrome/browser/geolocation/geolocation_permission_context.cc
index bb29c88..df581638 100644
--- a/chrome/browser/geolocation/geolocation_permission_context.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context.cc
@@ -10,15 +10,15 @@
 #include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/geolocation_provider.h"
+#include "content/public/browser/permission_type.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 
-
-GeolocationPermissionContext::GeolocationPermissionContext(
-    Profile* profile)
-    : PermissionContextBase(profile, CONTENT_SETTINGS_TYPE_GEOLOCATION),
-      extensions_context_(profile) {
-}
+GeolocationPermissionContext::GeolocationPermissionContext(Profile* profile)
+    : PermissionContextBase(profile,
+                            content::PermissionType::GEOLOCATION,
+                            CONTENT_SETTINGS_TYPE_GEOLOCATION),
+      extensions_context_(profile) {}
 
 GeolocationPermissionContext::~GeolocationPermissionContext() {
 }
diff --git a/chrome/browser/guest_view/OWNERS b/chrome/browser/guest_view/OWNERS
index c92691f..fa9ece6d 100644
--- a/chrome/browser/guest_view/OWNERS
+++ b/chrome/browser/guest_view/OWNERS
@@ -1 +1,2 @@
 fsamuel@chromium.org
+lfg@chromium.org
diff --git a/chrome/browser/hang_monitor/hung_plugin_action.cc b/chrome/browser/hang_monitor/hung_plugin_action.cc
index 8214286..feff61d9 100644
--- a/chrome/browser/hang_monitor/hung_plugin_action.cc
+++ b/chrome/browser/hang_monitor/hung_plugin_action.cc
@@ -8,6 +8,7 @@
 
 #include "base/metrics/histogram.h"
 #include "base/version.h"
+#include "base/win/win_util.h"
 #include "chrome/browser/ui/simple_message_box.h"
 #include "chrome/common/logging_chrome.h"
 #include "chrome/grit/generated_resources.h"
@@ -123,11 +124,8 @@
         // exists. The property is deleted if the window becomes
         // responsive.
         continue_hang_detection = false;
-#pragma warning(disable:4311)
-        int child_window_message_timeout =
-            reinterpret_cast<int>(GetProp(
-                hung_window, HungWindowDetector::kHungChildWindowTimeout));
-#pragma warning(default:4311)
+        int child_window_message_timeout = base::win::HandleToUint32(
+            GetProp(hung_window, HungWindowDetector::kHungChildWindowTimeout));
         if (child_window_message_timeout) {
           child_window_message_timeout *= 2;
 #pragma warning(disable:4312)
diff --git a/chrome/browser/hang_monitor/hung_window_detector.cc b/chrome/browser/hang_monitor/hung_window_detector.cc
index d58e36a..47e253f0 100644
--- a/chrome/browser/hang_monitor/hung_window_detector.cc
+++ b/chrome/browser/hang_monitor/hung_window_detector.cc
@@ -8,6 +8,7 @@
 #include <atlbase.h>
 
 #include "base/logging.h"
+#include "base/win/win_util.h"
 #include "chrome/browser/hang_monitor/hang_crash_dump_win.h"
 #include "content/public/common/result_codes.h"
 
@@ -88,10 +89,8 @@
     // The message timeout for a child window starts of with a default
     // value specified by the message_response_timeout_ member. It is
     // tracked by a property on the child window.
-#pragma warning(disable:4311)
-    int child_window_message_timeout =
-        reinterpret_cast<int>(GetProp(child_window, kHungChildWindowTimeout));
-#pragma warning(default:4311)
+    int child_window_message_timeout = base::win::HandleToUint32(
+        GetProp(child_window, kHungChildWindowTimeout));
     if (!child_window_message_timeout) {
       child_window_message_timeout = message_response_timeout_;
     }
diff --git a/chrome/browser/history/web_history_service_unittest.cc b/chrome/browser/history/web_history_service_unittest.cc
index 4ea045ab..b656e193 100644
--- a/chrome/browser/history/web_history_service_unittest.cc
+++ b/chrome/browser/history/web_history_service_unittest.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/browser/sync/profile_sync_test_util.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/browser_sync/browser/profile_sync_service.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
@@ -222,7 +222,7 @@
 
   void SetUp() override {
     ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-      &profile_, &ProfileSyncServiceMock::BuildMockProfileSyncService);
+        &profile_, &BuildMockProfileSyncService);
     // Use SetTestingFactoryAndUse to force creation and initialization.
     WebHistoryServiceFactory::GetInstance()->SetTestingFactoryAndUse(
       &profile_, &BuildWebHistoryService);
@@ -250,7 +250,6 @@
   }
 
  private:
-
   content::TestBrowserThreadBundle thread_bundle_;
   TestingProfile profile_;
 
diff --git a/chrome/browser/internal_auth.cc b/chrome/browser/internal_auth.cc
index 84d543c2..f97baeca 100644
--- a/chrome/browser/internal_auth.cc
+++ b/chrome/browser/internal_auth.cc
@@ -4,8 +4,11 @@
 
 #include "chrome/browser/internal_auth.h"
 
+#include <stdint.h>
+
 #include <algorithm>
 #include <deque>
+#include <limits>
 
 #include "base/base64.h"
 #include "base/lazy_instance.h"
@@ -26,7 +29,7 @@
 // Size of a tick in microseconds. This determines upper bound for average
 // number of passports generated per time unit. This bound equals to
 // (kMicrosecondsPerSecond / TickUs) calls per second.
-const int64 kTickUs = 10000;
+const int64_t kTickUs = 10000;
 
 // Verification window size in ticks; that means any passport expires in
 // (kVerificationWindowTicks * TickUs / kMicrosecondsPerSecond) seconds.
@@ -77,11 +80,10 @@
 const size_t kPassportSize =
     BASE64_PER_RAW(kHMACSizeInBytes) + kTickStringLength;
 
-int64 GetCurrentTick() {
-  int64 tick = base::Time::Now().ToInternalValue() / kTickUs;
-  if (tick < kVerificationWindowTicks ||
-      tick < kKeyRegenerationHardTicks ||
-      tick > kint64max - kKeyRegenerationHardTicks) {
+int64_t GetCurrentTick() {
+  int64_t tick = base::Time::Now().ToInternalValue() / kTickUs;
+  if (tick < kVerificationWindowTicks || tick < kKeyRegenerationHardTicks ||
+      tick > std::numeric_limits<int64_t>::max() - kKeyRegenerationHardTicks) {
     return 0;
   }
   return tick;
@@ -142,7 +144,7 @@
 
 void CreatePassport(const std::string& domain,
                     const VarValueMap& map,
-                    int64 tick,
+                    int64_t tick,
                     const crypto::HMAC* engine,
                     std::string* out) {
   DCHECK(engine);
@@ -200,8 +202,8 @@
       const std::string& passport,
       const std::string& domain,
       const VarValueMap& map) {
-    int64 current_tick = GetCurrentTick();
-    int64 tick = PreVerifyPassport(passport, domain, current_tick);
+    int64_t current_tick = GetCurrentTick();
+    int64_t tick = PreVerifyPassport(passport, domain, current_tick);
     if (tick == 0)
       return false;
     if (!IsVarValueMapSane(map))
@@ -221,8 +223,8 @@
     }
 
     // Record used tick to prevent reuse.
-    std::deque<int64>::iterator it = std::lower_bound(
-        used_ticks_.begin(), used_ticks_.end(), tick);
+    std::deque<int64_t>::iterator it =
+        std::lower_bound(used_ticks_.begin(), used_ticks_.end(), tick);
     DCHECK(it == used_ticks_.end() || *it != tick);
     used_ticks_.insert(it, tick);
 
@@ -261,10 +263,9 @@
   }
 
   // Returns tick bound to given passport on success or zero on failure.
-  int64 PreVerifyPassport(
-    const std::string& passport,
-    const std::string& domain,
-    int64 current_tick) {
+  int64_t PreVerifyPassport(const std::string& passport,
+                            const std::string& domain,
+                            int64_t current_tick) {
     if (passport.size() != kPassportSize ||
         !base::IsStringASCII(passport) ||
         !IsDomainSane(domain) ||
@@ -279,7 +280,7 @@
     std::string tick_decimal =
         passport.substr(BASE64_PER_RAW(kHMACSizeInBytes));
     DCHECK(tick_decimal.size() == kTickStringLength);
-    int64 tick = 0;
+    int64_t tick = 0;
     if (!base::StringToInt64(tick_decimal, &tick) ||
         tick <= dark_tick_ ||
         tick > key_change_tick_ + kKeyRegenerationHardTicks ||
@@ -302,16 +303,16 @@
   scoped_ptr<crypto::HMAC> old_engine_;
 
   // Tick at a time of recent key regeneration.
-  int64 key_change_tick_;
+  int64_t key_change_tick_;
 
   // Keeps track of ticks of successfully verified passports to prevent their
   // reuse. Size of this container is kept reasonably low by purging outdated
   // ticks.
-  std::deque<int64> used_ticks_;
+  std::deque<int64_t> used_ticks_;
 
   // Some ticks before |dark_tick_| were purged from |used_ticks_| container.
   // That means that we must not trust any tick less than or equal to dark tick.
-  int64 dark_tick_;
+  int64_t dark_tick_;
 
   DISALLOW_COPY_AND_ASSIGN(InternalAuthVerificationService);
 };
@@ -348,7 +349,7 @@
   }
 
   // Returns zero on failure.
-  int64 GetUnusedTick(const std::string& domain) {
+  int64_t GetUnusedTick(const std::string& domain) {
     DCHECK(CalledOnValidThread());
     if (engine_ == NULL) {
       NOTREACHED();
@@ -357,7 +358,7 @@
     if (!IsDomainSane(domain))
       return 0;
 
-    int64 current_tick = GetCurrentTick();
+    int64_t current_tick = GetCurrentTick();
     if (!used_ticks_.empty() && used_ticks_.back() > current_tick)
       current_tick = used_ticks_.back();
     for (bool first_iteration = true;; first_iteration = false) {
@@ -378,9 +379,8 @@
       // Average speed of GeneratePassport calls exceeds limit.
       return 0;
     }
-    for (int64 tick = current_tick;
-        tick > current_tick - kGenerationWindowTicks;
-        --tick) {
+    for (int64_t tick = current_tick;
+         tick > current_tick - kGenerationWindowTicks; --tick) {
       int idx = static_cast<int>(used_ticks_.size()) -
           static_cast<int>(current_tick - tick + 1);
       if (idx < 0 || used_ticks_[idx] != tick) {
@@ -393,8 +393,9 @@
     return 0;
   }
 
-  std::string GeneratePassport(
-      const std::string& domain, const VarValueMap& map, int64 tick) {
+  std::string GeneratePassport(const std::string& domain,
+                               const VarValueMap& map,
+                               int64_t tick) {
     DCHECK(CalledOnValidThread());
     if (tick == 0) {
       tick = GetUnusedTick(domain);
@@ -417,8 +418,8 @@
   }
 
   scoped_ptr<crypto::HMAC> engine_;
-  int64 key_regeneration_tick_;
-  std::deque<int64> used_ticks_;
+  int64_t key_regeneration_tick_;
+  std::deque<int64_t> used_ticks_;
 
   DISALLOW_COPY_AND_ASSIGN(InternalAuthGenerationService);
 };
diff --git a/chrome/browser/internal_auth.h b/chrome/browser/internal_auth.h
index aa30333..9f5df11a7 100644
--- a/chrome/browser/internal_auth.h
+++ b/chrome/browser/internal_auth.h
@@ -8,8 +8,8 @@
 #include <map>
 #include <string>
 
-#include "base/basictypes.h"
 #include "base/gtest_prod_util.h"
+#include "base/macros.h"
 
 namespace chrome {
 
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index cc33dc19..8808ac4 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -1170,6 +1170,8 @@
       &params->quic_close_sessions_on_ip_change);
   globals.quic_idle_connection_timeout_seconds.CopyToIfSet(
       &params->quic_idle_connection_timeout_seconds);
+  globals.quic_disable_preconnect_if_0rtt.CopyToIfSet(
+      &params->quic_disable_preconnect_if_0rtt);
 
   globals.origin_to_force_quic_on.CopyToIfSet(
       &params->origin_to_force_quic_on);
@@ -1307,6 +1309,8 @@
       globals->quic_idle_connection_timeout_seconds.set(
           idle_connection_timeout_seconds);
     }
+    globals->quic_disable_preconnect_if_0rtt.set(
+        ShouldQuicDisablePreConnectIfZeroRtt(quic_trial_params));
   }
 
   size_t max_packet_length = GetQuicMaxPacketLength(command_line,
@@ -1559,6 +1563,13 @@
   return 0;
 }
 
+bool IOThread::ShouldQuicDisablePreConnectIfZeroRtt(
+    const VariationParameters& quic_trial_params) {
+  return base::LowerCaseEqualsASCII(
+      GetVariationParam(quic_trial_params, "disable_preconnect_if_0rtt"),
+      "true");
+}
+
 size_t IOThread::GetQuicMaxPacketLength(
     const base::CommandLine& command_line,
     const VariationParameters& quic_trial_params) {
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h
index e8b4ac3..d95d7ee5 100644
--- a/chrome/browser/io_thread.h
+++ b/chrome/browser/io_thread.h
@@ -232,6 +232,7 @@
     Optional<net::HostPortPair> origin_to_force_quic_on;
     Optional<bool> quic_close_sessions_on_ip_change;
     Optional<int> quic_idle_connection_timeout_seconds;
+    Optional<bool> quic_disable_preconnect_if_0rtt;
     bool enable_user_alternate_protocol_ports;
     // NetErrorTabHelper uses |dns_probe_service| to send DNS probes when a
     // main frame load fails with a DNS error in order to provide more useful
@@ -450,6 +451,10 @@
   static int GetQuicIdleConnectionTimeoutSeconds(
       const VariationParameters& quic_trial_params);
 
+  // Returns true if PreConnect should be disabled if QUIC can do 0RTT.
+  static bool ShouldQuicDisablePreConnectIfZeroRtt(
+      const VariationParameters& quic_trial_params);
+
   // Returns the maximum length for QUIC packets, based on any flags in
   // |command_line| or the field trial.  Returns 0 if there is an error
   // parsing any of the options, or if the default value should be used.
diff --git a/chrome/browser/io_thread_unittest.cc b/chrome/browser/io_thread_unittest.cc
index 9ba5f4822..1635fc35 100644
--- a/chrome/browser/io_thread_unittest.cc
+++ b/chrome/browser/io_thread_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/at_exit.h"
 #include "base/command_line.h"
 #include "base/metrics/field_trial.h"
 #include "base/prefs/pref_registry_simple.h"
@@ -231,6 +232,7 @@
   EXPECT_FALSE(params.quic_close_sessions_on_ip_change);
   EXPECT_EQ(net::kIdleConnectionTimeoutSeconds,
             params.quic_idle_connection_timeout_seconds);
+  EXPECT_FALSE(params.quic_disable_preconnect_if_0rtt);
   EXPECT_FALSE(IOThread::ShouldEnableQuicForDataReductionProxy());
 }
 
@@ -336,6 +338,15 @@
   EXPECT_EQ(300, params.quic_idle_connection_timeout_seconds);
 }
 
+TEST_F(IOThreadTest, QuicDisablePreConnectIfZeroRtt) {
+  field_trial_group_ = "Enabled";
+  field_trial_params_["disable_preconnect_if_0rtt"] = "true";
+  ConfigureQuicGlobals();
+  net::HttpNetworkSession::Params params;
+  InitializeNetworkSessionParams(&params);
+  EXPECT_TRUE(params.quic_disable_preconnect_if_0rtt);
+}
+
 TEST_F(IOThreadTest, PacketLengthFromFieldTrialParams) {
   field_trial_group_ = "Enabled";
   field_trial_params_["max_packet_length"] = "1450";
@@ -659,6 +670,7 @@
   }
 
  private:
+  base::ShadowingAtExitManager at_exit_manager_;
   content::TestBrowserThreadBundle thread_bundle_;
   TestingPrefServiceSimple pref_service_;
 #if defined(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/local_discovery/privet_url_fetcher.cc b/chrome/browser/local_discovery/privet_url_fetcher.cc
index eea13f06..f8cf391 100644
--- a/chrome/browser/local_discovery/privet_url_fetcher.cc
+++ b/chrome/browser/local_discovery/privet_url_fetcher.cc
@@ -4,7 +4,10 @@
 
 #include "chrome/browser/local_discovery/privet_url_fetcher.h"
 
+#include <stdint.h>
+
 #include <algorithm>
+#include <limits>
 
 #include "base/bind.h"
 #include "base/debug/dump_without_crashing.h"
@@ -175,10 +178,8 @@
     if (request_type_ == net::URLFetcher::POST) {
       if (!upload_file_path_.empty()) {
         url_fetcher_->SetUploadFilePath(
-            upload_content_type_,
-            upload_file_path_,
-            0 /*offset*/,
-            kuint64max /*length*/,
+            upload_content_type_, upload_file_path_, 0 /*offset*/,
+            std::numeric_limits<uint64_t>::max() /*length*/,
             content::BrowserThread::GetMessageLoopProxyForThread(
                 content::BrowserThread::FILE));
       } else {
diff --git a/chrome/browser/media/media_stream_camera_permission_context_factory.cc b/chrome/browser/media/media_stream_camera_permission_context_factory.cc
index dc402b8..b48c182 100644
--- a/chrome/browser/media/media_stream_camera_permission_context_factory.cc
+++ b/chrome/browser/media/media_stream_camera_permission_context_factory.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/permission_type.h"
 
 MediaStreamCameraPermissionContextFactory::
     MediaStreamCameraPermissionContextFactory()
@@ -22,7 +23,8 @@
 MediaStreamCameraPermissionContextFactory::BuildServiceInstanceFor(
     content::BrowserContext* profile) const {
   return new MediaStreamDevicePermissionContext(
-      static_cast<Profile*>(profile), CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
+      static_cast<Profile*>(profile), content::PermissionType::VIDEO_CAPTURE,
+      CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
 }
 
 // static
diff --git a/chrome/browser/media/media_stream_device_permission_context.cc b/chrome/browser/media/media_stream_device_permission_context.cc
index a1d2006..87638cf 100644
--- a/chrome/browser/media/media_stream_device_permission_context.cc
+++ b/chrome/browser/media/media_stream_device_permission_context.cc
@@ -13,8 +13,9 @@
 
 MediaStreamDevicePermissionContext::MediaStreamDevicePermissionContext(
     Profile* profile,
+    const content::PermissionType permission_type,
     const ContentSettingsType content_settings_type)
-    : PermissionContextBase(profile, content_settings_type),
+    : PermissionContextBase(profile, permission_type, content_settings_type),
       content_settings_type_(content_settings_type) {
   DCHECK(content_settings_type_ == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC ||
          content_settings_type_ == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
diff --git a/chrome/browser/media/media_stream_device_permission_context.h b/chrome/browser/media/media_stream_device_permission_context.h
index 8166f6f..75722477 100644
--- a/chrome/browser/media/media_stream_device_permission_context.h
+++ b/chrome/browser/media/media_stream_device_permission_context.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "chrome/browser/permissions/permission_context_base.h"
 #include "components/content_settings/core/common/content_settings_types.h"
+#include "content/public/browser/permission_type.h"
 
 // Common class which handles the mic and camera permissions.
 // MediaStreamMicPermissionContextFactory and
@@ -17,6 +18,7 @@
  public:
   MediaStreamDevicePermissionContext(
       Profile* profile,
+      const content::PermissionType permission_type,
       const ContentSettingsType content_settings_type);
   ~MediaStreamDevicePermissionContext() override;
 
diff --git a/chrome/browser/media/media_stream_device_permission_context_unittest.cc b/chrome/browser/media/media_stream_device_permission_context_unittest.cc
index 4a942f64..0cfdce3 100644
--- a/chrome/browser/media/media_stream_device_permission_context_unittest.cc
+++ b/chrome/browser/media/media_stream_device_permission_context_unittest.cc
@@ -13,6 +13,7 @@
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
+#include "content/public/browser/permission_type.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/mock_render_process_host.h"
 #include "content/public/test/web_contents_tester.h"
@@ -27,7 +28,12 @@
  public:
   TestPermissionContext(Profile* profile,
                         const ContentSettingsType permission_type)
-      : MediaStreamDevicePermissionContext(profile, permission_type) {}
+      : MediaStreamDevicePermissionContext(
+            profile,
+            permission_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA
+                ? content::PermissionType::VIDEO_CAPTURE
+                : content::PermissionType::AUDIO_CAPTURE,
+            permission_type) {}
 
   ~TestPermissionContext() override {}
 };
diff --git a/chrome/browser/media/media_stream_devices_controller.cc b/chrome/browser/media/media_stream_devices_controller.cc
index 44f449b..35f7df0c 100644
--- a/chrome/browser/media/media_stream_devices_controller.cc
+++ b/chrome/browser/media/media_stream_devices_controller.cc
@@ -29,6 +29,7 @@
 #include "components/content_settings/core/common/content_settings_pattern.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/permission_type.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_widget_host_view.h"
@@ -53,33 +54,32 @@
 
 // Returns true if the given ContentSettingsType is being requested in
 // |request|.
-bool ContentTypeIsRequested(ContentSettingsType type,
+bool ContentTypeIsRequested(content::PermissionType type,
                             const content::MediaStreamRequest& request) {
   if (request.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY)
     return true;
 
-  if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)
+  if (type == content::PermissionType::AUDIO_CAPTURE)
     return request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE;
 
-  if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)
+  if (type == content::PermissionType::VIDEO_CAPTURE)
     return request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE;
 
   return false;
 }
 
 using PermissionActionCallback =
-    base::Callback<void(ContentSettingsType, const GURL&)>;
+    base::Callback<void(content::PermissionType, const GURL&)>;
 
 // Calls |action_function| for each permission requested by |request|.
 void RecordPermissionAction(const content::MediaStreamRequest& request,
                             PermissionActionCallback callback) {
-  if (ContentTypeIsRequested(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
-                             request)) {
-    callback.Run(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
+  if (ContentTypeIsRequested(content::PermissionType::VIDEO_CAPTURE, request)) {
+    callback.Run(content::PermissionType::VIDEO_CAPTURE,
                  request.security_origin);
   }
-  if (ContentTypeIsRequested(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, request)) {
-    callback.Run(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
+  if (ContentTypeIsRequested(content::PermissionType::AUDIO_CAPTURE, request)) {
+    callback.Run(content::PermissionType::AUDIO_CAPTURE,
                  request.security_origin);
   }
 }
@@ -551,7 +551,15 @@
     return CONTENT_SETTING_BLOCK;
   }
 
-  if (ContentTypeIsRequested(content_type, request)) {
+  content::PermissionType permission_type;
+  if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) {
+    permission_type = content::PermissionType::AUDIO_CAPTURE;
+  } else {
+    DCHECK(content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
+    permission_type = content::PermissionType::VIDEO_CAPTURE;
+  }
+
+  if (ContentTypeIsRequested(permission_type, request)) {
     bool is_insecure_pepper_request =
         request.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY &&
         request.security_origin.SchemeIs(url::kHttpScheme);
diff --git a/chrome/browser/media/media_stream_devices_controller_browsertest.cc b/chrome/browser/media/media_stream_devices_controller_browsertest.cc
index 05dee3692..7feb51c7 100644
--- a/chrome/browser/media/media_stream_devices_controller_browsertest.cc
+++ b/chrome/browser/media/media_stream_devices_controller_browsertest.cc
@@ -725,10 +725,10 @@
                        RequestAndKillSwitchMicCam) {
   std::map<std::string, std::string> params;
   params[PermissionUtil::GetPermissionString(
-      CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)] =
+      content::PermissionType::AUDIO_CAPTURE)] =
       PermissionContextBase::kPermissionsKillSwitchBlockedValue;
   params[PermissionUtil::GetPermissionString(
-      CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)] =
+      content::PermissionType::VIDEO_CAPTURE)] =
       PermissionContextBase::kPermissionsKillSwitchBlockedValue;
   variations::AssociateVariationParams(
       PermissionContextBase::kPermissionsKillSwitchFieldStudy,
diff --git a/chrome/browser/media/media_stream_mic_permission_context_factory.cc b/chrome/browser/media/media_stream_mic_permission_context_factory.cc
index 4463d09..97d54f5 100644
--- a/chrome/browser/media/media_stream_mic_permission_context_factory.cc
+++ b/chrome/browser/media/media_stream_mic_permission_context_factory.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/permission_type.h"
 
 MediaStreamMicPermissionContextFactory::MediaStreamMicPermissionContextFactory()
     : PermissionContextFactoryBase(
@@ -20,7 +21,8 @@
 KeyedService* MediaStreamMicPermissionContextFactory::BuildServiceInstanceFor(
     content::BrowserContext* profile) const {
   return new MediaStreamDevicePermissionContext(
-      static_cast<Profile*>(profile), CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
+      static_cast<Profile*>(profile), content::PermissionType::AUDIO_CAPTURE,
+      CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
 }
 
 // static
diff --git a/chrome/browser/media/midi_permission_context.cc b/chrome/browser/media/midi_permission_context.cc
index d2162e7..f4987df5 100644
--- a/chrome/browser/media/midi_permission_context.cc
+++ b/chrome/browser/media/midi_permission_context.cc
@@ -7,11 +7,13 @@
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/permissions/permission_request_id.h"
 #include "content/public/browser/child_process_security_policy.h"
+#include "content/public/browser/permission_type.h"
 #include "url/gurl.h"
 
 MidiPermissionContext::MidiPermissionContext(Profile* profile)
-    : PermissionContextBase(profile, CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
-}
+    : PermissionContextBase(profile,
+                            content::PermissionType::MIDI_SYSEX,
+                            CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {}
 
 MidiPermissionContext::~MidiPermissionContext() {
 }
diff --git a/chrome/browser/media/midi_permission_infobar_delegate_android.cc b/chrome/browser/media/midi_permission_infobar_delegate_android.cc
index 44954b04..94c8f52 100644
--- a/chrome/browser/media/midi_permission_infobar_delegate_android.cc
+++ b/chrome/browser/media/midi_permission_infobar_delegate_android.cc
@@ -16,20 +16,21 @@
     InfoBarService* infobar_service,
     const GURL& requesting_frame,
     const std::string& display_languages,
-    ContentSettingsType type,
     const PermissionSetCallback& callback) {
   return infobar_service->AddInfoBar(
       infobar_service->CreateConfirmInfoBar(scoped_ptr<ConfirmInfoBarDelegate>(
           new MidiPermissionInfoBarDelegateAndroid(
-              requesting_frame, display_languages, type, callback))));
+              requesting_frame, display_languages, callback))));
 }
 
 MidiPermissionInfoBarDelegateAndroid::MidiPermissionInfoBarDelegateAndroid(
     const GURL& requesting_frame,
     const std::string& display_languages,
-    ContentSettingsType type,
     const PermissionSetCallback& callback)
-    : PermissionInfobarDelegate(requesting_frame, type, callback),
+    : PermissionInfobarDelegate(requesting_frame,
+                                content::PermissionType::MIDI_SYSEX,
+                                CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
+                                callback),
       requesting_frame_(requesting_frame),
       display_languages_(display_languages) {}
 
diff --git a/chrome/browser/media/midi_permission_infobar_delegate_android.h b/chrome/browser/media/midi_permission_infobar_delegate_android.h
index d8ddcbf9..b332eeb 100644
--- a/chrome/browser/media/midi_permission_infobar_delegate_android.h
+++ b/chrome/browser/media/midi_permission_infobar_delegate_android.h
@@ -24,13 +24,11 @@
   static infobars::InfoBar* Create(InfoBarService* infobar_service,
                                    const GURL& requesting_frame,
                                    const std::string& display_languages,
-                                   ContentSettingsType type,
                                    const PermissionSetCallback& callback);
 
  private:
   MidiPermissionInfoBarDelegateAndroid(const GURL& requesting_frame,
                                        const std::string& display_languages,
-                                       ContentSettingsType type,
                                        const PermissionSetCallback& callback);
   ~MidiPermissionInfoBarDelegateAndroid() override;
 
diff --git a/chrome/browser/media/protected_media_identifier_infobar_delegate_android.cc b/chrome/browser/media/protected_media_identifier_infobar_delegate_android.cc
index b184dae..ddf049cb 100644
--- a/chrome/browser/media/protected_media_identifier_infobar_delegate_android.cc
+++ b/chrome/browser/media/protected_media_identifier_infobar_delegate_android.cc
@@ -32,6 +32,7 @@
         const PermissionSetCallback& callback)
     : PermissionInfobarDelegate(
           requesting_frame,
+          content::PermissionType::PROTECTED_MEDIA_IDENTIFIER,
           CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
           callback),
       requesting_frame_(requesting_frame),
diff --git a/chrome/browser/media/protected_media_identifier_permission_context.cc b/chrome/browser/media/protected_media_identifier_permission_context.cc
index 0ac7e815..e045b64 100644
--- a/chrome/browser/media/protected_media_identifier_permission_context.cc
+++ b/chrome/browser/media/protected_media_identifier_permission_context.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/permission_type.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
@@ -36,6 +37,7 @@
 ProtectedMediaIdentifierPermissionContext::
     ProtectedMediaIdentifierPermissionContext(Profile* profile)
     : PermissionContextBase(profile,
+                            content::PermissionType::PROTECTED_MEDIA_IDENTIFIER,
                             CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER)
 #if defined(OS_CHROMEOS)
       ,
@@ -68,9 +70,11 @@
     // Log to the developer console.
     web_contents->GetMainFrame()->AddMessageToConsole(
         content::CONSOLE_MESSAGE_LEVEL_LOG,
-        base::StringPrintf("%s permission has been blocked.",
+        base::StringPrintf(
+            "%s permission has been blocked.",
             PermissionUtil::GetPermissionString(
-                CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER).c_str()));
+                content::PermissionType::PROTECTED_MEDIA_IDENTIFIER)
+                .c_str()));
     // The kill switch is enabled for this permission; Block all requests and
     // run the callback immediately.
     callback.Run(CONTENT_SETTING_BLOCK);
diff --git a/chrome/browser/media/webrtc_log_uploader.cc b/chrome/browser/media/webrtc_log_uploader.cc
index 25b0b4c..631bbff 100644
--- a/chrome/browser/media/webrtc_log_uploader.cc
+++ b/chrome/browser/media/webrtc_log_uploader.cc
@@ -442,10 +442,27 @@
 
   scoped_ptr<net::URLFetcher> url_fetcher(net::URLFetcher::Create(
       GURL(chrome::kUploadURL), net::URLFetcher::POST, this));
-  url_fetcher->SetRequestContext(g_browser_process->system_request_context());
   url_fetcher->SetUploadData(content_type, *post_data);
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+      base::Bind(&WebRtcLogUploader::SetRequestContextOnUIThread,
+          base::Unretained(this), base::Unretained(url_fetcher.release()),
+          upload_done_data));
+}
+
+void WebRtcLogUploader::SetRequestContextOnUIThread(
+    net::URLFetcher* url_fetcher, const WebRtcLogUploadDoneData& data) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  url_fetcher->SetRequestContext(g_browser_process->system_request_context());
+  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+      base::Bind(&WebRtcLogUploader::StartAndTrackRequestContext,
+                 base::Unretained(this), base::Unretained(url_fetcher), data));
+}
+
+void WebRtcLogUploader::StartAndTrackRequestContext(
+    net::URLFetcher* url_fetcher, const WebRtcLogUploadDoneData& data) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   url_fetcher->Start();
-  upload_done_data_[url_fetcher.release()] = upload_done_data;
+  upload_done_data_[url_fetcher] = data;
 }
 
 void WebRtcLogUploader::DecreaseLogCount() {
diff --git a/chrome/browser/media/webrtc_log_uploader.h b/chrome/browser/media/webrtc_log_uploader.h
index b584827..dfe1cb8 100644
--- a/chrome/browser/media/webrtc_log_uploader.h
+++ b/chrome/browser/media/webrtc_log_uploader.h
@@ -125,6 +125,13 @@
       const WebRtcLogUploadDoneData& upload_done_data,
       scoped_ptr<std::string> post_data);
 
+  // A couple of helper functions due to having to hop to the UI thread
+  // to fetch the system_request_context and back again to the IO thread.
+  void SetRequestContextOnUIThread(
+      net::URLFetcher* url_fetcher, const WebRtcLogUploadDoneData& data);
+  void StartAndTrackRequestContext(
+      net::URLFetcher* url_fetcher, const WebRtcLogUploadDoneData& data);
+
   void DecreaseLogCount();
 
   void ShutdownOnIOThread();
diff --git a/chrome/browser/media_galleries/win/mtp_device_operations_util.cc b/chrome/browser/media_galleries/win/mtp_device_operations_util.cc
index 33559c2..ca274d8 100644
--- a/chrome/browser/media_galleries/win/mtp_device_operations_util.cc
+++ b/chrome/browser/media_galleries/win/mtp_device_operations_util.cc
@@ -5,10 +5,11 @@
 #include "chrome/browser/media_galleries/win/mtp_device_operations_util.h"
 
 #include <portabledevice.h>
+#include <stdint.h>
 
 #include <algorithm>
+#include <limits>
 
-#include "base/basictypes.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
@@ -150,13 +151,15 @@
 
 // Gets the size of the file object in bytes from the property key values
 // specified by the |properties_values|. On failure, return -1.
-int64 GetObjectSize(IPortableDeviceValues* properties_values) {
+int64_t GetObjectSize(IPortableDeviceValues* properties_values) {
   DCHECK(properties_values);
   ULONGLONG actual_size;
   HRESULT hr = properties_values->GetUnsignedLargeIntegerValue(WPD_OBJECT_SIZE,
                                                                &actual_size);
-  bool success = SUCCEEDED(hr) && (actual_size <= kint64max);
-  return success ? static_cast<int64>(actual_size) : -1;
+  bool success = SUCCEEDED(hr) &&
+                 (actual_size <=
+                  static_cast<ULONGLONG>(std::numeric_limits<int64_t>::max()));
+  return success ? static_cast<int64_t>(actual_size) : -1;
 }
 
 // Gets the details of the object specified by the |object_id| given the media
@@ -167,7 +170,7 @@
                       const base::string16 object_id,
                       base::string16* name,
                       bool* is_directory,
-                      int64* size,
+                      int64_t* size,
                       base::Time* last_modified_time) {
   base::ThreadRestrictions::AssertIOAllowed();
   DCHECK(device);
@@ -225,7 +228,7 @@
   // Try to get the last modified time, but don't fail if we can't.
   GetLastModifiedTime(properties_values.get(), last_modified_time);
 
-  int64 object_size = GetObjectSize(properties_values.get());
+  int64_t object_size = GetObjectSize(properties_values.get());
   if (object_size < 0)
     return false;
   *size = object_size;
@@ -241,7 +244,7 @@
   DCHECK(!object_id.empty());
   base::string16 name;
   bool is_directory;
-  int64 size;
+  int64_t size;
   base::Time last_modified_time;
   MTPDeviceObjectEntry entry;
   if (GetObjectDetails(device, object_id, &name, &is_directory, &size,
diff --git a/chrome/browser/media_galleries/win/snapshot_file_details.cc b/chrome/browser/media_galleries/win/snapshot_file_details.cc
index 1a86268..57a6714 100644
--- a/chrome/browser/media_galleries/win/snapshot_file_details.cc
+++ b/chrome/browser/media_galleries/win/snapshot_file_details.cc
@@ -4,7 +4,9 @@
 
 #include "chrome/browser/media_galleries/win/snapshot_file_details.h"
 
-#include "base/basictypes.h"
+#include <stdint.h>
+
+#include <limits>
 
 ///////////////////////////////////////////////////////////////////////////////
 //                       SnapshotRequestInfo                                 //
@@ -60,7 +62,7 @@
 
 bool SnapshotFileDetails::AddBytesWritten(DWORD bytes_written) {
   if ((bytes_written == 0) ||
-      (bytes_written_ > kuint64max - bytes_written) ||
+      (bytes_written_ > std::numeric_limits<uint64_t>::max() - bytes_written) ||
       (bytes_written_ + bytes_written > file_info_.size))
     return false;
 
diff --git a/chrome/browser/net/net_pref_observer.cc b/chrome/browser/net/net_pref_observer.cc
index cc7b470..09c36d36 100644
--- a/chrome/browser/net/net_pref_observer.cc
+++ b/chrome/browser/net/net_pref_observer.cc
@@ -39,5 +39,9 @@
 // static
 void NetPrefObserver::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
+  registry->RegisterBooleanPref(
+      prefs::kNetworkPredictionEnabled,
+      true,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterBooleanPref(prefs::kDisableSpdy, false);
 }
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc
index 34add647..6dc4a55 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc
@@ -7,12 +7,12 @@
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h"
 #include "chrome/common/chrome_content_client.h"
+#include "chrome/common/pref_names.h"
 #include "components/data_reduction_proxy/content/browser/content_lofi_decider.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_retrieval_params.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/build_info.h"
@@ -54,8 +54,7 @@
 #endif
 
   bool enabled =
-      prefs->GetBoolean(
-          data_reduction_proxy::prefs::kDataReductionProxyEnabled) ||
+      prefs->GetBoolean(prefs::kDataSaverEnabled) ||
       data_reduction_proxy::params::ShouldForceEnableDataReductionProxy();
   scoped_ptr<data_reduction_proxy::DataReductionProxyIOData>
       data_reduction_proxy_io_data(
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
index db5f7b3..fac32f3 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/pref_names.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
@@ -165,7 +166,8 @@
 }
 
 DataReductionProxyChromeSettings::DataReductionProxyChromeSettings()
-    : data_reduction_proxy::DataReductionProxySettings() {
+    : data_reduction_proxy::DataReductionProxySettings(),
+      data_reduction_proxy_enabled_pref_name_(prefs::kDataSaverEnabled) {
 }
 
 DataReductionProxyChromeSettings::~DataReductionProxyChromeSettings() {
@@ -202,7 +204,9 @@
           ui_task_runner, io_data->io_task_runner(), db_task_runner,
           commit_delay));
   data_reduction_proxy::DataReductionProxySettings::
-      InitDataReductionProxySettings(profile_prefs, io_data, service.Pass());
+      InitDataReductionProxySettings(
+          data_reduction_proxy_enabled_pref_name_, profile_prefs, io_data,
+          service.Pass());
   io_data->SetDataReductionProxyService(
       data_reduction_proxy_service()->GetWeakPtr());
 
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h
index 10b5a1fa..83df4562 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_NET_SPDYPROXY_DATA_REDUCTION_PROXY_CHROME_SETTINGS_H_
 #define CHROME_BROWSER_NET_SPDYPROXY_DATA_REDUCTION_PROXY_CHROME_SETTINGS_H_
 
+#include <string>
+
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -73,6 +75,13 @@
   // Public for testing.
   void MigrateDataReductionProxyOffProxyPrefs(PrefService* prefs);
 
+  // Override the default pref name for enabling the Data Reduction Proxy.
+  // Used in tests.
+  void set_data_reduction_proxy_enabled_pref_name_for_test(
+      const std::string& pref_name) {
+    data_reduction_proxy_enabled_pref_name_ = pref_name;
+  }
+
  private:
   // Helper method for migrating the Data Reduction Proxy away from using the
   // proxy pref. Returns the ProxyPrefMigrationResult value indicating the
@@ -80,6 +89,8 @@
   ProxyPrefMigrationResult MigrateDataReductionProxyOffProxyPrefsHelper(
       PrefService* prefs);
 
+  std::string data_reduction_proxy_enabled_pref_name_;
+
   DISALLOW_COPY_AND_ASSIGN(DataReductionProxyChromeSettings);
 };
 
diff --git a/chrome/browser/notifications/message_center_settings_controller_unittest.cc b/chrome/browser/notifications/message_center_settings_controller_unittest.cc
index cb5dc53..225c7d9 100644
--- a/chrome/browser/notifications/message_center_settings_controller_unittest.cc
+++ b/chrome/browser/notifications/message_center_settings_controller_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <string>
+#include <utility>
 
 #include "base/command_line.h"
 #include "base/strings/utf_string_conversions.h"
@@ -205,13 +206,14 @@
           .Set("name", "Foo")
           .Set("version", "1.0.0")
           .Set("manifest_version", 2)
-          .Set("app", extensions::DictionaryBuilder().Set(
-                          "background",
-                          extensions::DictionaryBuilder().Set(
-                              "scripts", extensions::ListBuilder().Append(
-                                             "background.js"))))
+          .Set("app",
+               extensions::DictionaryBuilder().Set(
+                   "background",
+                   extensions::DictionaryBuilder().Set(
+                       "scripts", std::move(extensions::ListBuilder().Append(
+                                      "background.js")))))
           .Set("permissions",
-               extensions::ListBuilder().Append("notifications")));
+               std::move(extensions::ListBuilder().Append("notifications"))));
   foo_app.SetID(kFooId);
   extension_service->AddExtension(foo_app.Build().get());
 
@@ -221,13 +223,14 @@
           .Set("name", "Bar")
           .Set("version", "1.0.0")
           .Set("manifest_version", 2)
-          .Set("app", extensions::DictionaryBuilder().Set(
-                          "background",
-                          extensions::DictionaryBuilder().Set(
-                              "scripts", extensions::ListBuilder().Append(
-                                             "background.js"))))
+          .Set("app",
+               extensions::DictionaryBuilder().Set(
+                   "background",
+                   extensions::DictionaryBuilder().Set(
+                       "scripts", std::move(extensions::ListBuilder().Append(
+                                      "background.js")))))
           .Set("permissions",
-               extensions::ListBuilder().Append("notifications")));
+               std::move(extensions::ListBuilder().Append("notifications"))));
   bar_app.SetID(kBarId);
   extension_service->AddExtension(bar_app.Build().get());
 
@@ -237,11 +240,12 @@
           .Set("name", "baz")
           .Set("version", "1.0.0")
           .Set("manifest_version", 2)
-          .Set("app", extensions::DictionaryBuilder().Set(
-                          "background",
-                          extensions::DictionaryBuilder().Set(
-                              "scripts", extensions::ListBuilder().Append(
-                                             "background.js")))));
+          .Set("app",
+               extensions::DictionaryBuilder().Set(
+                   "background",
+                   extensions::DictionaryBuilder().Set(
+                       "scripts", std::move(extensions::ListBuilder().Append(
+                                      "background.js"))))));
   baz_app.SetID(kBazId);
   extension_service->AddExtension(baz_app.Build().get());
 
@@ -254,13 +258,13 @@
           .Set("app",
                extensions::DictionaryBuilder().Set(
                    "urls",
-                   extensions::ListBuilder().Append(
-                       "http://localhost/extensions/hosted_app/main.html")))
+                   std::move(extensions::ListBuilder().Append(
+                       "http://localhost/extensions/hosted_app/main.html"))))
           .Set("launch",
                extensions::DictionaryBuilder().Set(
                    "urls",
-                   extensions::ListBuilder().Append(
-                       "http://localhost/extensions/hosted_app/main.html"))));
+                   std::move(extensions::ListBuilder().Append(
+                       "http://localhost/extensions/hosted_app/main.html")))));
 
   baf_app.SetID(kBafId);
   extension_service->AddExtension(baf_app.Build().get());
diff --git a/chrome/browser/notifications/notification_permission_context.cc b/chrome/browser/notifications/notification_permission_context.cc
index 06037ae..096b6ed 100644
--- a/chrome/browser/notifications/notification_permission_context.cc
+++ b/chrome/browser/notifications/notification_permission_context.cc
@@ -6,10 +6,13 @@
 
 #include "chrome/browser/notifications/desktop_notification_profile_util.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
+#include "content/public/browser/permission_type.h"
 #include "url/gurl.h"
 
 NotificationPermissionContext::NotificationPermissionContext(Profile* profile)
-    : PermissionContextBase(profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {}
+    : PermissionContextBase(profile,
+                            content::PermissionType::NOTIFICATIONS,
+                            CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {}
 
 NotificationPermissionContext::~NotificationPermissionContext() {}
 
diff --git a/chrome/browser/notifications/notification_permission_infobar_delegate.cc b/chrome/browser/notifications/notification_permission_infobar_delegate.cc
index 105e48d..d932c001 100644
--- a/chrome/browser/notifications/notification_permission_infobar_delegate.cc
+++ b/chrome/browser/notifications/notification_permission_infobar_delegate.cc
@@ -30,6 +30,7 @@
     const std::string& display_languages,
     const base::Callback<void(bool, bool)>& callback)
     : PermissionInfobarDelegate(requesting_frame,
+                                content::PermissionType::NOTIFICATIONS,
                                 CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                 callback),
       requesting_frame_(requesting_frame),
diff --git a/chrome/browser/notifications/notifier_state_tracker.cc b/chrome/browser/notifications/notifier_state_tracker.cc
index 86405a8..9f55f227 100644
--- a/chrome/browser/notifications/notifier_state_tracker.cc
+++ b/chrome/browser/notifications/notifier_state_tracker.cc
@@ -162,10 +162,6 @@
   if (IsNotifierEnabled(notifier_id))
     return;
 
-  // The settings for ephemeral apps will be persisted across cache evictions.
-  if (extensions::util::IsEphemeralApp(extension->id(), profile_))
-    return;
-
   SetNotifierEnabled(notifier_id, true);
 }
 
diff --git a/chrome/browser/notifications/platform_notification_service_unittest.cc b/chrome/browser/notifications/platform_notification_service_unittest.cc
index 1429d6d..06c9066 100644
--- a/chrome/browser/notifications/platform_notification_service_unittest.cc
+++ b/chrome/browser/notifications/platform_notification_service_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
@@ -331,8 +333,9 @@
                            .Set("version", "1.0")
                            .Set("manifest_version", 2)
                            .Set("description", "Test Extension")
-                           .Set("permissions", extensions::ListBuilder().Append(
-                                                   "notifications")))
+                           .Set("permissions",
+                                std::move(extensions::ListBuilder().Append(
+                                    "notifications"))))
           .Build();
 
   // Install the extension on the faked extension service, and verify that it
diff --git a/chrome/browser/password_manager/account_chooser_dialog_android.cc b/chrome/browser/password_manager/account_chooser_dialog_android.cc
index 9df5381..a7b6730 100644
--- a/chrome/browser/password_manager/account_chooser_dialog_android.cc
+++ b/chrome/browser/password_manager/account_chooser_dialog_android.cc
@@ -16,10 +16,10 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/browser_sync/browser/profile_sync_service.h"
 #include "components/password_manager/core/browser/password_bubble_experiment.h"
+#include "components/password_manager/core/browser/password_manager_constants.h"
 #include "components/password_manager/core/common/credential_manager_types.h"
 #include "jni/AccountChooserDialog_jni.h"
 #include "ui/android/window_android.h"
-#include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/range/range.h"
 
@@ -173,7 +173,7 @@
 
 void AccountChooserDialogAndroid::OnLinkClicked(JNIEnv* env, jobject obj) {
   web_contents_->OpenURL(content::OpenURLParams(
-      GURL(l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SMART_LOCK_PAGE)),
+      GURL(password_manager::kPasswordManagerAccountDashboardURL),
       content::Referrer(), NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_LINK,
       false /* is_renderer_initiated */));
 }
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index 2e030a5..807796af 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -301,12 +301,10 @@
 void ChromePasswordManagerClient::PasswordWasAutofilled(
     const autofill::PasswordFormMap& best_matches,
     const GURL& origin) const {
-#if !defined(OS_ANDROID)
   PasswordsClientUIDelegate* manage_passwords_ui_controller =
       PasswordsClientUIDelegateFromWebContents(web_contents());
   if (manage_passwords_ui_controller && IsTheHotNewBubbleUIEnabled())
     manage_passwords_ui_controller->OnPasswordAutofilled(best_matches, origin);
-#endif
 }
 
 void ChromePasswordManagerClient::HidePasswordGenerationPopup() {
diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
index 14e89b1..c4c53e5 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
@@ -14,7 +14,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/browser/sync/profile_sync_test_util.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
@@ -183,7 +183,7 @@
   ProfileSyncServiceMock* mock_sync_service =
       static_cast<ProfileSyncServiceMock*>(
           ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-              profile(), ProfileSyncServiceMock::BuildMockProfileSyncService));
+              profile(), BuildMockProfileSyncService));
 
   syncer::ModelTypeSet active_types;
   active_types.Put(syncer::PASSWORDS);
diff --git a/chrome/browser/permissions/permission_bubble_request_impl.cc b/chrome/browser/permissions/permission_bubble_request_impl.cc
index f438678..41a103e 100644
--- a/chrome/browser/permissions/permission_bubble_request_impl.cc
+++ b/chrome/browser/permissions/permission_bubble_request_impl.cc
@@ -16,41 +16,40 @@
 PermissionBubbleRequestImpl::PermissionBubbleRequestImpl(
     const GURL& request_origin,
     bool user_gesture,
-    ContentSettingsType type,
+    content::PermissionType permission_type,
     const std::string& display_languages,
     const PermissionDecidedCallback& permission_decided_callback,
     const base::Closure delete_callback)
     : request_origin_(request_origin),
       user_gesture_(user_gesture),
-      type_(type),
+      permission_type_(permission_type),
       display_languages_(display_languages),
       permission_decided_callback_(permission_decided_callback),
       delete_callback_(delete_callback),
       is_finished_(false),
-      action_taken_(false) {
-}
+      action_taken_(false) {}
 
 PermissionBubbleRequestImpl::~PermissionBubbleRequestImpl() {
   DCHECK(is_finished_);
   if (!action_taken_)
-    PermissionUmaUtil::PermissionIgnored(type_, request_origin_);
+    PermissionUmaUtil::PermissionIgnored(permission_type_, request_origin_);
 }
 
 gfx::VectorIconId PermissionBubbleRequestImpl::GetVectorIconId() const {
 #if !defined(OS_MACOSX)
-  switch (type_) {
-    case CONTENT_SETTINGS_TYPE_GEOLOCATION:
+  switch (permission_type_) {
+    case content::PermissionType::GEOLOCATION:
       return gfx::VectorIconId::LOCATION_ON;
 #if defined(ENABLE_NOTIFICATIONS)
-    case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
+    case content::PermissionType::NOTIFICATIONS:
       return gfx::VectorIconId::NOTIFICATIONS;
 #endif
 #if defined(OS_CHROMEOS)
     // TODO(xhwang): fix this icon, see crrev.com/863263007
-    case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER:
+    case content::PermissionType::PROTECTED_MEDIA_IDENTIFIER:
       return gfx::VectorIconId::CHROME_PRODUCT;
 #endif
-    case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
+    case content::PermissionType::MIDI_SYSEX:
       return gfx::VectorIconId::MIDI;
     default:
       NOTREACHED();
@@ -64,16 +63,16 @@
 int PermissionBubbleRequestImpl::GetIconId() const {
   int icon_id = IDR_INFOBAR_WARNING;
 #if defined(OS_MACOSX)
-  switch (type_) {
-    case CONTENT_SETTINGS_TYPE_GEOLOCATION:
+  switch (permission_type_) {
+    case content::PermissionType::GEOLOCATION:
       icon_id = IDR_INFOBAR_GEOLOCATION;
       break;
 #if defined(ENABLE_NOTIFICATIONS)
-    case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
+    case content::PermissionType::NOTIFICATIONS:
       icon_id = IDR_INFOBAR_DESKTOP_NOTIFICATIONS;
       break;
 #endif
-    case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
+    case content::PermissionType::MIDI_SYSEX:
       icon_id = IDR_ALLOWED_MIDI_SYSEX;
       break;
     default:
@@ -85,23 +84,23 @@
 
 base::string16 PermissionBubbleRequestImpl::GetMessageText() const {
   int message_id;
-  switch (type_) {
-    case CONTENT_SETTINGS_TYPE_GEOLOCATION:
+  switch (permission_type_) {
+    case content::PermissionType::GEOLOCATION:
       message_id = IDS_GEOLOCATION_INFOBAR_QUESTION;
       break;
 #if defined(ENABLE_NOTIFICATIONS)
-    case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
+    case content::PermissionType::NOTIFICATIONS:
       message_id = IDS_NOTIFICATION_PERMISSIONS;
       break;
 #endif
-    case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
+    case content::PermissionType::MIDI_SYSEX:
       message_id = IDS_MIDI_SYSEX_INFOBAR_QUESTION;
       break;
-    case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING:
+    case content::PermissionType::PUSH_MESSAGING:
       message_id = IDS_PUSH_MESSAGES_PERMISSION_QUESTION;
       break;
 #if defined(OS_CHROMEOS)
-    case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER:
+    case content::PermissionType::PROTECTED_MEDIA_IDENTIFIER:
       message_id = IDS_PROTECTED_MEDIA_IDENTIFIER_INFOBAR_QUESTION;
       break;
 #endif
@@ -116,27 +115,27 @@
 
 base::string16 PermissionBubbleRequestImpl::GetMessageTextFragment() const {
   int message_id;
-  switch (type_) {
-    case CONTENT_SETTINGS_TYPE_GEOLOCATION:
+  switch (permission_type_) {
+    case content::PermissionType::GEOLOCATION:
       message_id = IDS_GEOLOCATION_INFOBAR_PERMISSION_FRAGMENT;
       break;
 #if defined(ENABLE_NOTIFICATIONS)
-    case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
+    case content::PermissionType::NOTIFICATIONS:
       message_id = IDS_NOTIFICATION_PERMISSIONS_FRAGMENT;
       break;
 #endif
-    case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
+    case content::PermissionType::MIDI_SYSEX:
       message_id = IDS_MIDI_SYSEX_PERMISSION_FRAGMENT;
       break;
-    case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING:
+    case content::PermissionType::PUSH_MESSAGING:
       message_id = IDS_PUSH_MESSAGES_BUBBLE_FRAGMENT;
       break;
 #if defined(OS_CHROMEOS)
-    case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER:
+    case content::PermissionType::PROTECTED_MEDIA_IDENTIFIER:
       message_id = IDS_PROTECTED_MEDIA_IDENTIFIER_PERMISSION_FRAGMENT;
       break;
 #endif
-    case CONTENT_SETTINGS_TYPE_DURABLE_STORAGE:
+    case content::PermissionType::DURABLE_STORAGE:
       message_id = IDS_DURABLE_STORAGE_BUBBLE_FRAGMENT;
       break;
     default:
diff --git a/chrome/browser/permissions/permission_bubble_request_impl.h b/chrome/browser/permissions/permission_bubble_request_impl.h
index 4cb37a3..95e82524 100644
--- a/chrome/browser/permissions/permission_bubble_request_impl.h
+++ b/chrome/browser/permissions/permission_bubble_request_impl.h
@@ -9,7 +9,7 @@
 #include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/browser/ui/website_settings/permission_bubble_request.h"
 #include "components/content_settings/core/common/content_settings.h"
-#include "components/content_settings/core/common/content_settings_types.h"
+#include "content/public/browser/permission_type.h"
 
 class GURL;
 class PermissionContextBase;
@@ -24,7 +24,7 @@
   PermissionBubbleRequestImpl(
       const GURL& request_origin,
       bool user_gesture,
-      ContentSettingsType type,
+      content::PermissionType permission_type,
       const std::string& display_languages,
       const PermissionDecidedCallback& permission_decided_callback,
       const base::Closure delete_callback);
@@ -54,7 +54,7 @@
  private:
   GURL request_origin_;
   bool user_gesture_;
-  ContentSettingsType type_;
+  content::PermissionType permission_type_;
   std::string display_languages_;
 
   // Called once a decision is made about the permission.
diff --git a/chrome/browser/permissions/permission_context_base.cc b/chrome/browser/permissions/permission_context_base.cc
index acbf908..dc5b8bd3 100644
--- a/chrome/browser/permissions/permission_context_base.cc
+++ b/chrome/browser/permissions/permission_context_base.cc
@@ -37,13 +37,15 @@
 
 PermissionContextBase::PermissionContextBase(
     Profile* profile,
-    const ContentSettingsType permission_type)
+    const content::PermissionType permission_type,
+    const ContentSettingsType content_settings_type)
     : profile_(profile),
       permission_type_(permission_type),
+      content_settings_type_(content_settings_type),
       weak_factory_(this) {
 #if defined(OS_ANDROID)
-  permission_queue_controller_.reset(
-      new PermissionQueueController(profile_, permission_type_));
+  permission_queue_controller_.reset(new PermissionQueueController(
+      profile_, permission_type_, content_settings_type_));
 #endif
 }
 
@@ -64,7 +66,8 @@
     // Log to the developer console.
     web_contents->GetMainFrame()->AddMessageToConsole(
         content::CONSOLE_MESSAGE_LEVEL_LOG,
-        base::StringPrintf("%s permission has been blocked.",
+        base::StringPrintf(
+            "%s permission has been blocked.",
             PermissionUtil::GetPermissionString(permission_type_).c_str()));
     // The kill switch is enabled for this permission; Block all requests.
     callback.Run(CONTENT_SETTING_BLOCK);
@@ -77,7 +80,7 @@
   if (!requesting_origin.is_valid() || !embedding_origin.is_valid()) {
     std::string type_name =
         content_settings::WebsiteSettingsRegistry::GetInstance()
-            ->Get(permission_type_)
+            ->Get(content_settings_type_)
             ->name();
 
     DVLOG(1) << "Attempt to use " << type_name
@@ -99,7 +102,7 @@
   ContentSetting content_setting =
       HostContentSettingsMapFactory::GetForProfile(profile_)
           ->GetContentSettingAndMaybeUpdateLastUsage(
-              requesting_origin, embedding_origin, permission_type_,
+              requesting_origin, embedding_origin, content_settings_type_,
               std::string());
 
   if (content_setting == CONTENT_SETTING_ALLOW ||
@@ -130,10 +133,8 @@
   }
 
   return HostContentSettingsMapFactory::GetForProfile(profile_)
-      ->GetContentSetting(requesting_origin,
-                          embedding_origin,
-                          permission_type_,
-                          std::string());
+      ->GetContentSetting(requesting_origin, embedding_origin,
+                          content_settings_type_, std::string());
 }
 
 void PermissionContextBase::ResetPermission(
@@ -142,7 +143,7 @@
   HostContentSettingsMapFactory::GetForProfile(profile_)->SetContentSetting(
       ContentSettingsPattern::FromURLNoWildcard(requesting_origin),
       ContentSettingsPattern::FromURLNoWildcard(embedding_origin),
-      permission_type_, std::string(), CONTENT_SETTING_DEFAULT);
+      content_settings_type_, std::string(), CONTENT_SETTING_DEFAULT);
 }
 
 void PermissionContextBase::CancelPermissionRequest(
@@ -260,7 +261,7 @@
   if (content_setting == CONTENT_SETTING_DEFAULT) {
     content_setting =
         HostContentSettingsMapFactory::GetForProfile(profile_)
-            ->GetDefaultContentSetting(permission_type_, nullptr);
+            ->GetDefaultContentSetting(content_settings_type_, nullptr);
   }
 
   DCHECK_NE(content_setting, CONTENT_SETTING_DEFAULT);
@@ -284,13 +285,13 @@
   HostContentSettingsMapFactory::GetForProfile(profile_)->SetContentSetting(
       ContentSettingsPattern::FromURLNoWildcard(requesting_origin),
       ContentSettingsPattern::FromURLNoWildcard(embedding_origin),
-      permission_type_, std::string(), content_setting);
+      content_settings_type_, std::string(), content_setting);
 }
 
 bool PermissionContextBase::IsPermissionKillSwitchOn() const {
-  const std::string param =
-      variations::GetVariationParamValue(kPermissionsKillSwitchFieldStudy,
-          PermissionUtil::GetPermissionString(permission_type_));
+  const std::string param = variations::GetVariationParamValue(
+      kPermissionsKillSwitchFieldStudy,
+      PermissionUtil::GetPermissionString(permission_type_));
 
   return param == kPermissionsKillSwitchBlockedValue;
 }
diff --git a/chrome/browser/permissions/permission_context_base.h b/chrome/browser/permissions/permission_context_base.h
index 2db397c..b135e25 100644
--- a/chrome/browser/permissions/permission_context_base.h
+++ b/chrome/browser/permissions/permission_context_base.h
@@ -13,6 +13,7 @@
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "content/public/browser/permission_type.h"
 #include "url/gurl.h"
 
 #if defined(OS_ANDROID)
@@ -55,7 +56,8 @@
 class PermissionContextBase : public KeyedService {
  public:
   PermissionContextBase(Profile* profile,
-                        const ContentSettingsType permission_type);
+                        const content::PermissionType permission_type,
+                        const ContentSettingsType content_settings_type);
   ~PermissionContextBase() override;
 
   // A field trial used to enable the global permissions kill switch.
@@ -144,12 +146,19 @@
   // Whether the permission should be restricted to secure origins.
   virtual bool IsRestrictedToSecureOrigins() const = 0;
 
+ protected:
+  content::PermissionType permission_type() const { return permission_type_; }
+  ContentSettingsType content_settings_type() const {
+    return content_settings_type_;
+  }
+
  private:
   // Called when a bubble is no longer used so it can be cleaned up.
   void CleanUpBubble(const PermissionRequestID& id);
 
   Profile* profile_;
-  const ContentSettingsType permission_type_;
+  const content::PermissionType permission_type_;
+  const ContentSettingsType content_settings_type_;
 #if defined(OS_ANDROID)
   scoped_ptr<PermissionQueueController> permission_queue_controller_;
 #endif
diff --git a/chrome/browser/permissions/permission_context_base_unittest.cc b/chrome/browser/permissions/permission_context_base_unittest.cc
index 5be49577..02d984b 100644
--- a/chrome/browser/permissions/permission_context_base_unittest.cc
+++ b/chrome/browser/permissions/permission_context_base_unittest.cc
@@ -21,6 +21,7 @@
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/variations/variations_associated_data.h"
+#include "content/public/browser/permission_type.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/mock_render_process_host.h"
@@ -42,13 +43,14 @@
 class TestPermissionContext : public PermissionContextBase {
  public:
   TestPermissionContext(Profile* profile,
-                  const ContentSettingsType permission_type)
-   : PermissionContextBase(profile, permission_type),
-     permission_set_(false),
-     permission_granted_(false),
-     tab_context_updated_(false),
-     field_trial_list_(new base::FieldTrialList(new base::MockEntropyProvider))
-     {}
+                        const content::PermissionType permission_type,
+                        const ContentSettingsType content_settings_type)
+      : PermissionContextBase(profile, permission_type, content_settings_type),
+        permission_set_(false),
+        permission_granted_(false),
+        tab_context_updated_(false),
+        field_trial_list_(
+            new base::FieldTrialList(new base::MockEntropyProvider)) {}
 
   ~TestPermissionContext() override {}
 
@@ -126,7 +128,8 @@
 
   void TestAskAndGrant_TestContent() {
     TestPermissionContext permission_context(
-        profile(), CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
+        profile(), content::PermissionType::NOTIFICATIONS,
+        CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
     GURL url("http://www.google.com");
     content::WebContentsTester::For(web_contents())->NavigateAndCommit(url);
 
@@ -156,7 +159,8 @@
 
   void TestAskAndDismiss_TestContent() {
     TestPermissionContext permission_context(
-        profile(), CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
+        profile(), content::PermissionType::MIDI_SYSEX,
+        CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
     GURL url("http://www.google.es");
     content::WebContentsTester::For(web_contents())->NavigateAndCommit(url);
 
@@ -184,8 +188,11 @@
     EXPECT_EQ(CONTENT_SETTING_ASK, setting);
   }
 
-  void TestRequestPermissionInvalidUrl(ContentSettingsType type) {
-    TestPermissionContext permission_context(profile(), type);
+  void TestRequestPermissionInvalidUrl(
+      content::PermissionType permission_type,
+      ContentSettingsType content_settings_type) {
+    TestPermissionContext permission_context(profile(), permission_type,
+                                             content_settings_type);
     GURL url;
     ASSERT_FALSE(url.is_valid());
     content::WebContentsTester::For(web_contents())->NavigateAndCommit(url);
@@ -206,16 +213,16 @@
 
     ContentSetting setting =
         HostContentSettingsMapFactory::GetForProfile(profile())
-            ->GetContentSetting(url.GetOrigin(),
-                                url.GetOrigin(),
-                                type,
-                                std::string());
+            ->GetContentSetting(url.GetOrigin(), url.GetOrigin(),
+                                content_settings_type, std::string());
     EXPECT_EQ(CONTENT_SETTING_ASK, setting);
   }
 
-  void TestGrantAndRevoke_TestContent(ContentSettingsType type,
+  void TestGrantAndRevoke_TestContent(content::PermissionType permission_type,
+                                      ContentSettingsType content_settings_type,
                                       ContentSetting expected_default) {
-    TestPermissionContext permission_context(profile(), type);
+    TestPermissionContext permission_context(profile(), permission_type,
+                                             content_settings_type);
     GURL url("https://www.google.com");
     content::WebContentsTester::For(web_contents())->NavigateAndCommit(url);
 
@@ -236,33 +243,32 @@
 
     ContentSetting setting =
         HostContentSettingsMapFactory::GetForProfile(profile())
-            ->GetContentSetting(url.GetOrigin(),
-                                url.GetOrigin(),
-                                type,
-                                std::string());
+            ->GetContentSetting(url.GetOrigin(), url.GetOrigin(),
+                                content_settings_type, std::string());
     EXPECT_EQ(CONTENT_SETTING_ALLOW, setting);
 
     // Try to reset permission.
     permission_context.ResetPermission(url.GetOrigin(), url.GetOrigin());
     ContentSetting setting_after_reset =
         HostContentSettingsMapFactory::GetForProfile(profile())
-            ->GetContentSetting(url.GetOrigin(),
-                                url.GetOrigin(),
-                                type,
-                                std::string());
+            ->GetContentSetting(url.GetOrigin(), url.GetOrigin(),
+                                content_settings_type, std::string());
     ContentSetting default_setting =
         HostContentSettingsMapFactory::GetForProfile(profile())
-            ->GetDefaultContentSetting(type, nullptr);
+            ->GetDefaultContentSetting(content_settings_type, nullptr);
     EXPECT_EQ(default_setting, setting_after_reset);
   }
 
-  void TestGlobalPermissionsKillSwitch(ContentSettingsType type) {
-    TestPermissionContext permission_context(profile(), type);
+  void TestGlobalPermissionsKillSwitch(
+      content::PermissionType permission_type,
+      ContentSettingsType content_settings_type) {
+    TestPermissionContext permission_context(profile(), permission_type,
+                                             content_settings_type);
     permission_context.ResetFieldTrialList();
 
     EXPECT_FALSE(permission_context.IsPermissionKillSwitchOn());
     std::map<std::string, std::string> params;
-    params[PermissionUtil::GetPermissionString(type)] =
+    params[PermissionUtil::GetPermissionString(permission_type)] =
         kPermissionsKillSwitchBlockedValue;
     variations::AssociateVariationParams(
         kPermissionsKillSwitchFieldStudy, kPermissionsKillSwitchTestGroup,
@@ -301,12 +307,17 @@
 // Simulates non-valid requesting URL.
 // The permission should be denied but not saved for future use.
 TEST_F(PermissionContextBaseTests, TestNonValidRequestingUrl) {
-  TestRequestPermissionInvalidUrl(CONTENT_SETTINGS_TYPE_GEOLOCATION);
-  TestRequestPermissionInvalidUrl(CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
-  TestRequestPermissionInvalidUrl(CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
-  TestRequestPermissionInvalidUrl(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING);
+  TestRequestPermissionInvalidUrl(content::PermissionType::GEOLOCATION,
+                                  CONTENT_SETTINGS_TYPE_GEOLOCATION);
+  TestRequestPermissionInvalidUrl(content::PermissionType::NOTIFICATIONS,
+                                  CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
+  TestRequestPermissionInvalidUrl(content::PermissionType::MIDI_SYSEX,
+                                  CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
+  TestRequestPermissionInvalidUrl(content::PermissionType::PUSH_MESSAGING,
+                                  CONTENT_SETTINGS_TYPE_PUSH_MESSAGING);
 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
   TestRequestPermissionInvalidUrl(
+      content::PermissionType::PROTECTED_MEDIA_IDENTIFIER,
       CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER);
 #endif
 }
@@ -314,11 +325,14 @@
 #if defined(OS_ANDROID)
 // This test is specific to Android because other platforms use bubbles.
 TEST_F(PermissionContextBaseTests, TestGrantAndRevokeWithInfobars) {
-  TestGrantAndRevoke_TestContent(CONTENT_SETTINGS_TYPE_GEOLOCATION,
+  TestGrantAndRevoke_TestContent(content::PermissionType::GEOLOCATION,
+                                 CONTENT_SETTINGS_TYPE_GEOLOCATION,
                                  CONTENT_SETTING_ASK);
-  TestGrantAndRevoke_TestContent(CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
+  TestGrantAndRevoke_TestContent(content::PermissionType::MIDI_SYSEX,
+                                 CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
                                  CONTENT_SETTING_ASK);
   TestGrantAndRevoke_TestContent(
+      content::PermissionType::PROTECTED_MEDIA_IDENTIFIER,
       CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER, CONTENT_SETTING_ASK);
   // TODO(timvolodine): currently no test for
   // CONTENT_SETTINGS_TYPE_NOTIFICATIONS because notification permissions work
@@ -333,30 +347,42 @@
 // Simulates granting and revoking of permissions using permission bubbles.
 // This test shouldn't run on mobile because mobile platforms use infobars.
 TEST_F(PermissionContextBaseTests, TestGrantAndRevokeWithBubbles) {
-  TestGrantAndRevoke_TestContent(CONTENT_SETTINGS_TYPE_GEOLOCATION,
+  TestGrantAndRevoke_TestContent(content::PermissionType::GEOLOCATION,
+                                 CONTENT_SETTINGS_TYPE_GEOLOCATION,
                                  CONTENT_SETTING_ASK);
 #if defined(ENABLE_NOTIFICATIONS)
-  TestGrantAndRevoke_TestContent(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+  TestGrantAndRevoke_TestContent(content::PermissionType::NOTIFICATIONS,
+                                 CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                  CONTENT_SETTING_ASK);
 #endif
-  TestGrantAndRevoke_TestContent(CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
+  TestGrantAndRevoke_TestContent(content::PermissionType::MIDI_SYSEX,
+                                 CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
                                  CONTENT_SETTING_ASK);
-  TestGrantAndRevoke_TestContent(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING,
+  TestGrantAndRevoke_TestContent(content::PermissionType::PUSH_MESSAGING,
+                                 CONTENT_SETTINGS_TYPE_PUSH_MESSAGING,
                                  CONTENT_SETTING_ASK);
 }
 #endif
 
 // Tests the global kill switch by enabling/disabling the Field Trials.
 TEST_F(PermissionContextBaseTests, TestGlobalKillSwitch) {
-  TestGlobalPermissionsKillSwitch(CONTENT_SETTINGS_TYPE_GEOLOCATION);
-  TestGlobalPermissionsKillSwitch(CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
-  TestGlobalPermissionsKillSwitch(CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
-  TestGlobalPermissionsKillSwitch(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING);
-  TestGlobalPermissionsKillSwitch(CONTENT_SETTINGS_TYPE_DURABLE_STORAGE);
+  TestGlobalPermissionsKillSwitch(content::PermissionType::GEOLOCATION,
+                                  CONTENT_SETTINGS_TYPE_GEOLOCATION);
+  TestGlobalPermissionsKillSwitch(content::PermissionType::NOTIFICATIONS,
+                                  CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
+  TestGlobalPermissionsKillSwitch(content::PermissionType::MIDI_SYSEX,
+                                  CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
+  TestGlobalPermissionsKillSwitch(content::PermissionType::PUSH_MESSAGING,
+                                  CONTENT_SETTINGS_TYPE_PUSH_MESSAGING);
+  TestGlobalPermissionsKillSwitch(content::PermissionType::DURABLE_STORAGE,
+                                  CONTENT_SETTINGS_TYPE_DURABLE_STORAGE);
 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
   TestGlobalPermissionsKillSwitch(
+      content::PermissionType::PROTECTED_MEDIA_IDENTIFIER,
       CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER);
 #endif
-  TestGlobalPermissionsKillSwitch(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
-  TestGlobalPermissionsKillSwitch(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
+  TestGlobalPermissionsKillSwitch(content::PermissionType::AUDIO_CAPTURE,
+                                  CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
+  TestGlobalPermissionsKillSwitch(content::PermissionType::VIDEO_CAPTURE,
+                                  CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
 }
diff --git a/chrome/browser/permissions/permission_infobar_delegate.cc b/chrome/browser/permissions/permission_infobar_delegate.cc
index 00b45e48..07e36bd 100644
--- a/chrome/browser/permissions/permission_infobar_delegate.cc
+++ b/chrome/browser/permissions/permission_infobar_delegate.cc
@@ -11,18 +11,19 @@
 
 PermissionInfobarDelegate::~PermissionInfobarDelegate() {
   if (!action_taken_)
-    PermissionUmaUtil::PermissionIgnored(type_, requesting_origin_);
+    PermissionUmaUtil::PermissionIgnored(permission_type_, requesting_origin_);
 }
 
 PermissionInfobarDelegate::PermissionInfobarDelegate(
     const GURL& requesting_origin,
-    ContentSettingsType type,
+    content::PermissionType permission_type,
+    ContentSettingsType content_settings_type,
     const base::Callback<void(bool, bool)>& callback)
     : requesting_origin_(requesting_origin),
       action_taken_(false),
-      type_(type),
-      callback_(callback) {
-}
+      permission_type_(permission_type),
+      content_settings_type_(content_settings_type),
+      callback_(callback) {}
 
 infobars::InfoBarDelegate::Type
 PermissionInfobarDelegate::GetInfoBarType() const {
diff --git a/chrome/browser/permissions/permission_infobar_delegate.h b/chrome/browser/permissions/permission_infobar_delegate.h
index 35fc49f..6413f6c 100644
--- a/chrome/browser/permissions/permission_infobar_delegate.h
+++ b/chrome/browser/permissions/permission_infobar_delegate.h
@@ -8,6 +8,7 @@
 #include "chrome/browser/infobars/infobar_service.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/infobars/core/confirm_infobar_delegate.h"
+#include "content/public/browser/permission_type.h"
 #include "content/public/browser/web_contents.h"
 
 class NavigationDetails;
@@ -20,11 +21,12 @@
 
  public:
   using PermissionSetCallback = base::Callback<void(bool, bool)>;
-  ContentSettingsType content_setting() const { return type_; }
+  ContentSettingsType content_setting() const { return content_settings_type_; }
 
  protected:
   PermissionInfobarDelegate(const GURL& requesting_origin,
-                            ContentSettingsType type,
+                            content::PermissionType permission_type,
+                            ContentSettingsType content_settings_type,
                             const PermissionSetCallback& callback);
   ~PermissionInfobarDelegate() override;
 
@@ -41,7 +43,8 @@
 
   GURL requesting_origin_;
   bool action_taken_;
-  ContentSettingsType type_;
+  content::PermissionType permission_type_;
+  ContentSettingsType content_settings_type_;
   const PermissionSetCallback callback_;
 
   DISALLOW_COPY_AND_ASSIGN(PermissionInfobarDelegate);
diff --git a/chrome/browser/permissions/permission_queue_controller.cc b/chrome/browser/permissions/permission_queue_controller.cc
index ac7e3f6..253da94 100644
--- a/chrome/browser/permissions/permission_queue_controller.cc
+++ b/chrome/browser/permissions/permission_queue_controller.cc
@@ -51,7 +51,7 @@
 
 class PermissionQueueController::PendingInfobarRequest {
  public:
-  PendingInfobarRequest(ContentSettingsType type,
+  PendingInfobarRequest(content::PermissionType type,
                         const PermissionRequestID& id,
                         const GURL& requesting_frame,
                         const GURL& embedder,
@@ -71,7 +71,7 @@
                      const std::string& display_languages);
 
  private:
-  ContentSettingsType type_;
+  content::PermissionType type_;
   PermissionRequestID id_;
   GURL requesting_frame_;
   GURL embedder_;
@@ -82,7 +82,7 @@
 };
 
 PermissionQueueController::PendingInfobarRequest::PendingInfobarRequest(
-    ContentSettingsType type,
+    content::PermissionType type,
     const PermissionRequestID& id,
     const GURL& requesting_frame,
     const GURL& embedder,
@@ -92,8 +92,7 @@
       requesting_frame_(requesting_frame),
       embedder_(embedder),
       callback_(callback),
-      infobar_(NULL) {
-}
+      infobar_(NULL) {}
 
 PermissionQueueController::PendingInfobarRequest::~PendingInfobarRequest() {
 }
@@ -123,31 +122,31 @@
                  requesting_frame_,
                  embedder_);
   switch (type_) {
-    case CONTENT_SETTINGS_TYPE_GEOLOCATION:
+    case content::PermissionType::GEOLOCATION:
       infobar_ = GeolocationInfoBarDelegateAndroid::Create(
           GetInfoBarService(id_), requesting_frame_, display_languages,
           callback);
       break;
 #if defined(ENABLE_NOTIFICATIONS)
-    case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
+    case content::PermissionType::NOTIFICATIONS:
       infobar_ = NotificationPermissionInfobarDelegate::Create(
           GetInfoBarService(id_), requesting_frame_,
           display_languages, callback);
       break;
 #endif  // ENABLE_NOTIFICATIONS
-    case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
+    case content::PermissionType::MIDI_SYSEX:
       infobar_ = MidiPermissionInfoBarDelegateAndroid::Create(
-          GetInfoBarService(id_), requesting_frame_, display_languages, type_,
+          GetInfoBarService(id_), requesting_frame_, display_languages,
           callback);
       break;
-    case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER:
+    case content::PermissionType::PROTECTED_MEDIA_IDENTIFIER:
       infobar_ = ProtectedMediaIdentifierInfoBarDelegateAndroid::Create(
           GetInfoBarService(id_), requesting_frame_, display_languages,
           callback);
       break;
-    case CONTENT_SETTINGS_TYPE_DURABLE_STORAGE:
+    case content::PermissionType::DURABLE_STORAGE:
       infobar_ = DurableStoragePermissionInfoBarDelegateAndroid::Create(
-          GetInfoBarService(id_), requesting_frame_, display_languages, type_,
+          GetInfoBarService(id_), requesting_frame_, display_languages,
           callback);
       break;
     default:
@@ -156,13 +155,14 @@
   }
 }
 
-
-PermissionQueueController::PermissionQueueController(Profile* profile,
-                                                     ContentSettingsType type)
+PermissionQueueController::PermissionQueueController(
+    Profile* profile,
+    content::PermissionType permission_type,
+    ContentSettingsType content_settings_type)
     : profile_(profile),
-      type_(type),
-      in_shutdown_(false) {
-}
+      permission_type_(permission_type),
+      content_settings_type_(content_settings_type),
+      in_shutdown_(false) {}
 
 PermissionQueueController::~PermissionQueueController() {
   // Cancel all outstanding requests.
@@ -183,7 +183,7 @@
     return;
 
   pending_infobar_requests_.push_back(PendingInfobarRequest(
-      type_, id, requesting_frame, embedder, callback));
+      permission_type_, id, requesting_frame, embedder, callback));
   if (!AlreadyShowingInfoBarForTab(id))
     ShowQueuedInfoBarForTab(id);
 }
@@ -219,11 +219,11 @@
   if (update_content_setting) {
     UpdateContentSetting(requesting_frame, embedder, allowed);
     if (allowed)
-      PermissionUmaUtil::PermissionGranted(type_, requesting_frame);
+      PermissionUmaUtil::PermissionGranted(permission_type_, requesting_frame);
     else
-      PermissionUmaUtil::PermissionDenied(type_, requesting_frame);
+      PermissionUmaUtil::PermissionDenied(permission_type_, requesting_frame);
   } else {
-    PermissionUmaUtil::PermissionDismissed(type_, requesting_frame);
+    PermissionUmaUtil::PermissionDismissed(permission_type_, requesting_frame);
   }
 
   // Cancel this request first, then notify listeners.  TODO(pkasting): Why
@@ -400,14 +400,11 @@
       allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
 
   ContentSettingsPattern embedder_pattern =
-      (type_ == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) ?
-      ContentSettingsPattern::Wildcard() :
-      ContentSettingsPattern::FromURLNoWildcard(embedder.GetOrigin());
+      (content_settings_type_ == CONTENT_SETTINGS_TYPE_NOTIFICATIONS)
+          ? ContentSettingsPattern::Wildcard()
+          : ContentSettingsPattern::FromURLNoWildcard(embedder.GetOrigin());
 
   HostContentSettingsMapFactory::GetForProfile(profile_)->SetContentSetting(
       ContentSettingsPattern::FromURLNoWildcard(requesting_frame.GetOrigin()),
-      embedder_pattern,
-      type_,
-      std::string(),
-      content_setting);
+      embedder_pattern, content_settings_type_, std::string(), content_setting);
 }
diff --git a/chrome/browser/permissions/permission_queue_controller.h b/chrome/browser/permissions/permission_queue_controller.h
index 1ec3b1e..3e8b7fe 100644
--- a/chrome/browser/permissions/permission_queue_controller.h
+++ b/chrome/browser/permissions/permission_queue_controller.h
@@ -10,6 +10,7 @@
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/permission_type.h"
 
 class GURL;
 class PermissionRequestID;
@@ -28,7 +29,9 @@
  public:
   using PermissionDecidedCallback = base::Callback<void(ContentSetting)>;
 
-  PermissionQueueController(Profile* profile, ContentSettingsType type);
+  PermissionQueueController(Profile* profile,
+                            content::PermissionType permission_type,
+                            ContentSettingsType content_settings_type);
   ~PermissionQueueController() override;
 
   // The InfoBar will be displayed immediately if the tab is not already
@@ -86,7 +89,8 @@
   content::NotificationRegistrar registrar_;
 
   Profile* const profile_;
-  ContentSettingsType type_;
+  content::PermissionType permission_type_;
+  ContentSettingsType content_settings_type_;
   PendingInfobarRequests pending_infobar_requests_;
   bool in_shutdown_;
 
diff --git a/chrome/browser/permissions/permission_queue_controller_unittest.cc b/chrome/browser/permissions/permission_queue_controller_unittest.cc
index d9dd27c..c6b94fe1 100644
--- a/chrome/browser/permissions/permission_queue_controller_unittest.cc
+++ b/chrome/browser/permissions/permission_queue_controller_unittest.cc
@@ -11,6 +11,7 @@
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/content_settings/core/common/content_settings_types.h"
+#include "content/public/browser/permission_type.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/mock_render_process_host.h"
@@ -64,9 +65,10 @@
 
 ObservationCountingQueueController::ObservationCountingQueueController(
     Profile* profile)
-    : PermissionQueueController(profile, CONTENT_SETTINGS_TYPE_GEOLOCATION),
-      call_count_(0) {
-}
+    : PermissionQueueController(profile,
+                                content::PermissionType::GEOLOCATION,
+                                CONTENT_SETTINGS_TYPE_GEOLOCATION),
+      call_count_(0) {}
 
 ObservationCountingQueueController::~ObservationCountingQueueController() {
 }
diff --git a/chrome/browser/permissions/permission_uma_util.cc b/chrome/browser/permissions/permission_uma_util.cc
index 328e685..9ef340f 100644
--- a/chrome/browser/permissions/permission_uma_util.cc
+++ b/chrome/browser/permissions/permission_uma_util.cc
@@ -51,7 +51,7 @@
 
 // Deprecated. This method is used for the single-dimensional RAPPOR metrics
 // that are being replaced by the multi-dimensional ones.
-const std::string GetRapporMetric(ContentSettingsType permission,
+const std::string GetRapporMetric(PermissionType permission,
                                   PermissionAction action) {
   std::string action_str;
   switch (action) {
@@ -73,8 +73,8 @@
   }
 
   // Do not record the deprecated RAPPOR metrics for media permissions.
-  if (permission == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA ||
-      permission == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) {
+  if (permission == PermissionType::AUDIO_CAPTURE ||
+      permission == PermissionType::VIDEO_CAPTURE) {
     return "";
   }
 
@@ -86,13 +86,13 @@
                             permission_str.c_str(), action_str.c_str());
 }
 
-void RecordPermissionAction(ContentSettingsType permission,
+void RecordPermissionAction(PermissionType permission,
                             PermissionAction action,
                             const GURL& requesting_origin) {
   bool secure_origin = content::IsOriginSecure(requesting_origin);
 
   switch (permission) {
-      case CONTENT_SETTINGS_TYPE_GEOLOCATION:
+    case PermissionType::GEOLOCATION:
         PERMISSION_ACTION_UMA(
             secure_origin,
             "Permissions.Action.Geolocation",
@@ -100,7 +100,7 @@
             "Permissions.Action.InsecureOrigin.Geolocation",
             action);
         break;
-      case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
+    case PermissionType::NOTIFICATIONS:
         PERMISSION_ACTION_UMA(
             secure_origin,
             "Permissions.Action.Notifications",
@@ -108,7 +108,7 @@
             "Permissions.Action.InsecureOrigin.Notifications",
             action);
         break;
-      case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
+    case PermissionType::MIDI_SYSEX:
         PERMISSION_ACTION_UMA(
             secure_origin,
             "Permissions.Action.MidiSysEx",
@@ -116,7 +116,7 @@
             "Permissions.Action.InsecureOrigin.MidiSysEx",
             action);
         break;
-      case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING:
+    case PermissionType::PUSH_MESSAGING:
         PERMISSION_ACTION_UMA(
             secure_origin,
             "Permissions.Action.PushMessaging",
@@ -124,8 +124,7 @@
             "Permissions.Action.InsecureOrigin.PushMessaging",
             action);
         break;
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
-      case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER:
+    case PermissionType::PROTECTED_MEDIA_IDENTIFIER:
         PERMISSION_ACTION_UMA(
             secure_origin,
             "Permissions.Action.ProtectedMedia",
@@ -133,8 +132,7 @@
             "Permissions.Action.InsecureOrigin.ProtectedMedia",
             action);
         break;
-#endif
-      case CONTENT_SETTINGS_TYPE_DURABLE_STORAGE:
+    case PermissionType::DURABLE_STORAGE:
         PERMISSION_ACTION_UMA(
             secure_origin,
             "Permissions.Action.DurableStorage",
@@ -142,18 +140,21 @@
             "Permissions.Action.InsecureOrigin.DurableStorage",
             action);
         break;
-      case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
+    case PermissionType::AUDIO_CAPTURE:
         // Media permissions are disabled on insecure origins, so there's no
         // need to record metrics for secure/insecue.
         UMA_HISTOGRAM_ENUMERATION("Permissions.Action.AudioCapture", action,
                                   PERMISSION_ACTION_NUM);
         break;
-      case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
+    case PermissionType::VIDEO_CAPTURE:
         UMA_HISTOGRAM_ENUMERATION("Permissions.Action.VideoCapture", action,
                                   PERMISSION_ACTION_NUM);
         break;
-      default:
-        NOTREACHED() << "PERMISSION " << permission << " not accounted for";
+    case PermissionType::MIDI:
+    case PermissionType::NUM:
+      NOTREACHED() << "PERMISSION "
+                   << PermissionUtil::GetPermissionString(permission)
+                   << " not accounted for";
   }
 
   // There are two sets of semi-redundant RAPPOR metrics being reported:
@@ -212,58 +213,35 @@
   return std::string();
 }
 
-void RecordPermissionRequest(ContentSettingsType permission,
+void RecordPermissionRequest(PermissionType permission,
                              const GURL& requesting_origin,
                              const GURL& embedding_origin,
                              Profile* profile) {
   bool secure_origin = content::IsOriginSecure(requesting_origin);
-  PermissionType type;
-  switch (permission) {
-    case CONTENT_SETTINGS_TYPE_GEOLOCATION:
-      type = PermissionType::GEOLOCATION;
+  if (permission == PermissionType::GEOLOCATION) {
       rappor::SampleDomainAndRegistryFromGURL(
           g_browser_process->rappor_service(),
           "ContentSettings.PermissionRequested.Geolocation.Url",
           requesting_origin);
-      break;
-    case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
-      type = PermissionType::NOTIFICATIONS;
+  } else if (permission == PermissionType::NOTIFICATIONS) {
       rappor::SampleDomainAndRegistryFromGURL(
           g_browser_process->rappor_service(),
           "ContentSettings.PermissionRequested.Notifications.Url",
           requesting_origin);
-      break;
-    case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
-      type = PermissionType::MIDI_SYSEX;
-      break;
-    case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING:
-      type = PermissionType::PUSH_MESSAGING;
-      break;
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
-    case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER:
-      type = PermissionType::PROTECTED_MEDIA_IDENTIFIER;
-      break;
-#endif
-    case CONTENT_SETTINGS_TYPE_DURABLE_STORAGE:
-      type = content::PermissionType::DURABLE_STORAGE;
-      break;
-    default:
-      NOTREACHED() << "PERMISSION " << permission << " not accounted for";
-      return;
   }
   UMA_HISTOGRAM_ENUMERATION(
       "ContentSettings.PermissionRequested",
-      static_cast<base::HistogramBase::Sample>(type),
+      static_cast<base::HistogramBase::Sample>(permission),
       static_cast<base::HistogramBase::Sample>(PermissionType::NUM));
   if (secure_origin) {
     UMA_HISTOGRAM_ENUMERATION(
         "ContentSettings.PermissionRequested_SecureOrigin",
-        static_cast<base::HistogramBase::Sample>(type),
+        static_cast<base::HistogramBase::Sample>(permission),
         static_cast<base::HistogramBase::Sample>(PermissionType::NUM));
   } else {
     UMA_HISTOGRAM_ENUMERATION(
         "ContentSettings.PermissionRequested_InsecureOrigin",
-        static_cast<base::HistogramBase::Sample>(type),
+        static_cast<base::HistogramBase::Sample>(permission),
         static_cast<base::HistogramBase::Sample>(PermissionType::NUM));
   }
 
@@ -277,17 +255,19 @@
     if (!manager)
       return;
     content::PermissionStatus embedding_permission_status =
-        manager->GetPermissionStatus(type, embedding_origin, embedding_origin);
+        manager->GetPermissionStatus(permission, embedding_origin,
+                                     embedding_origin);
 
     base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
-        "Permissions.Requested.CrossOrigin_" + PermissionTypeToString(type), 1,
-        content::PERMISSION_STATUS_LAST, content::PERMISSION_STATUS_LAST + 1,
+        "Permissions.Requested.CrossOrigin_" +
+            PermissionTypeToString(permission),
+        1, content::PERMISSION_STATUS_LAST, content::PERMISSION_STATUS_LAST + 1,
         base::HistogramBase::kUmaTargetedHistogramFlag);
     histogram->Add(embedding_permission_status);
   } else {
     UMA_HISTOGRAM_ENUMERATION(
         "Permissions.Requested.SameOrigin",
-        static_cast<base::HistogramBase::Sample>(type),
+        static_cast<base::HistogramBase::Sample>(permission),
         static_cast<base::HistogramBase::Sample>(PermissionType::NUM));
   }
 }
@@ -296,31 +276,30 @@
 
 // Make sure you update histograms.xml permission histogram_suffix if you
 // add new permission
-void PermissionUmaUtil::PermissionRequested(
-    ContentSettingsType permission,
-    const GURL& requesting_origin,
-    const GURL& embedding_origin,
-    Profile* profile) {
+void PermissionUmaUtil::PermissionRequested(PermissionType permission,
+                                            const GURL& requesting_origin,
+                                            const GURL& embedding_origin,
+                                            Profile* profile) {
   RecordPermissionRequest(permission, requesting_origin, embedding_origin,
                           profile);
 }
 
-void PermissionUmaUtil::PermissionGranted(
-    ContentSettingsType permission, const GURL& requesting_origin) {
+void PermissionUmaUtil::PermissionGranted(PermissionType permission,
+                                          const GURL& requesting_origin) {
   RecordPermissionAction(permission, GRANTED, requesting_origin);
 }
 
-void PermissionUmaUtil::PermissionDenied(
-    ContentSettingsType permission, const GURL& requesting_origin) {
+void PermissionUmaUtil::PermissionDenied(PermissionType permission,
+                                         const GURL& requesting_origin) {
   RecordPermissionAction(permission, DENIED, requesting_origin);
 }
 
-void PermissionUmaUtil::PermissionDismissed(
-    ContentSettingsType permission, const GURL& requesting_origin) {
+void PermissionUmaUtil::PermissionDismissed(PermissionType permission,
+                                            const GURL& requesting_origin) {
   RecordPermissionAction(permission, DISMISSED, requesting_origin);
 }
 
-void PermissionUmaUtil::PermissionIgnored(
-    ContentSettingsType permission, const GURL& requesting_origin) {
+void PermissionUmaUtil::PermissionIgnored(PermissionType permission,
+                                          const GURL& requesting_origin) {
   RecordPermissionAction(permission, IGNORED, requesting_origin);
 }
diff --git a/chrome/browser/permissions/permission_uma_util.h b/chrome/browser/permissions/permission_uma_util.h
index ce5cb11..f7f886f 100644
--- a/chrome/browser/permissions/permission_uma_util.h
+++ b/chrome/browser/permissions/permission_uma_util.h
@@ -6,25 +6,28 @@
 #define CHROME_BROWSER_PERMISSIONS_PERMISSION_UMA_UTIL_H_
 
 #include "base/logging.h"
-#include "components/content_settings/core/common/content_settings_types.h"
 
 class GURL;
 class Profile;
 
+namespace content {
+enum class PermissionType;
+}  // namespace content
+
 // Provides a convenient way of logging UMA for permission related operations.
 class PermissionUmaUtil {
  public:
-  static void PermissionRequested(ContentSettingsType permission,
+  static void PermissionRequested(content::PermissionType permission,
                                   const GURL& requesting_origin,
                                   const GURL& embedding_origin,
                                   Profile* profile);
-  static void PermissionGranted(ContentSettingsType permission,
+  static void PermissionGranted(content::PermissionType permission,
                                 const GURL& requesting_origin);
-  static void PermissionDenied(ContentSettingsType permission,
+  static void PermissionDenied(content::PermissionType permission,
                                const GURL& requesting_origin);
-  static void PermissionDismissed(ContentSettingsType permission,
+  static void PermissionDismissed(content::PermissionType permission,
                                   const GURL& requesting_origin);
-  static void PermissionIgnored(ContentSettingsType permission,
+  static void PermissionIgnored(content::PermissionType permission,
                                 const GURL& requesting_origin);
 
  private:
diff --git a/chrome/browser/permissions/permission_util.cc b/chrome/browser/permissions/permission_util.cc
index d7d77eb5..4daa4ba5 100644
--- a/chrome/browser/permissions/permission_util.cc
+++ b/chrome/browser/permissions/permission_util.cc
@@ -5,33 +5,37 @@
 #include "chrome/browser/permissions/permission_util.h"
 
 #include "base/logging.h"
+#include "content/public/browser/permission_type.h"
+
+using content::PermissionType;
 
 // The returned strings must match the RAPPOR metrics in rappor.xml,
 // and any Field Trial configs for the Permissions kill switch e.g.
 // Permissions.Action.Geolocation etc..
 std::string PermissionUtil::GetPermissionString(
-    ContentSettingsType permission) {
+    content::PermissionType permission) {
   switch (permission) {
-    case CONTENT_SETTINGS_TYPE_GEOLOCATION:
+    case content::PermissionType::GEOLOCATION:
       return "Geolocation";
-    case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
+    case content::PermissionType::NOTIFICATIONS:
       return "Notifications";
-    case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
+    case content::PermissionType::MIDI_SYSEX:
       return "MidiSysEx";
-    case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING:
+    case content::PermissionType::PUSH_MESSAGING:
       return "PushMessaging";
-    case CONTENT_SETTINGS_TYPE_DURABLE_STORAGE:
+    case content::PermissionType::DURABLE_STORAGE:
       return "DurableStorage";
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
-    case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER:
+    case content::PermissionType::PROTECTED_MEDIA_IDENTIFIER:
       return "ProtectedMediaIdentifier";
-#endif
-    case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
+    case content::PermissionType::AUDIO_CAPTURE:
       return "AudioCapture";
-    case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
+    case content::PermissionType::VIDEO_CAPTURE:
       return "VideoCapture";
-    default:
-      NOTREACHED();
-      return std::string();
+    case content::PermissionType::MIDI:
+      return "Midi";
+    case content::PermissionType::NUM:
+      break;
   }
+  NOTREACHED();
+  return std::string();
 }
diff --git a/chrome/browser/permissions/permission_util.h b/chrome/browser/permissions/permission_util.h
index 4fdd2e5..be19b5a5 100644
--- a/chrome/browser/permissions/permission_util.h
+++ b/chrome/browser/permissions/permission_util.h
@@ -8,13 +8,16 @@
 #include <string>
 
 #include "base/macros.h"
-#include "components/content_settings/core/common/content_settings_types.h"
+
+namespace content {
+enum class PermissionType;
+}  // namespace content
 
 // A utility class for permissions.
 class PermissionUtil {
  public:
-  // Returns the permission string for the given ContentSettingsType.
-  static std::string GetPermissionString(ContentSettingsType permission);
+  // Returns the permission string for the given PermissionType.
+  static std::string GetPermissionString(content::PermissionType permission);
 
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(PermissionUtil);
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index ba44e2cb..17c807e8 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -16,7 +16,6 @@
 #include "chrome/common/pref_names.h"
 #include "components/bookmarks/common/bookmark_pref_names.h"
 #include "components/content_settings/core/common/pref_names.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
 #include "components/metrics/metrics_pref_names.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/policy/core/browser/autofill_policy_handler.h"
@@ -510,7 +509,7 @@
 
 #if BUILDFLAG(ANDROID_JAVA_UI)
   { key::kDataCompressionProxyEnabled,
-    data_reduction_proxy::prefs::kDataReductionProxyEnabled,
+    prefs::kDataSaverEnabled,
     base::Value::TYPE_BOOLEAN },
   { key::kAuthAndroidNegotiateAccountType,
     prefs::kAuthAndroidNegotiateAccountType,
diff --git a/chrome/browser/policy/managed_bookmarks_policy_handler_unittest.cc b/chrome/browser/policy/managed_bookmarks_policy_handler_unittest.cc
index 50097313..1105262 100644
--- a/chrome/browser/policy/managed_bookmarks_policy_handler_unittest.cc
+++ b/chrome/browser/policy/managed_bookmarks_policy_handler_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/json/json_reader.h"
 #include "chrome/browser/policy/managed_bookmarks_policy_handler.h"
 #include "components/bookmarks/common/bookmark_pref_names.h"
@@ -79,31 +81,39 @@
   scoped_ptr<base::Value> expected(
       extensions::ListBuilder()
           .Append(extensions::DictionaryBuilder()
-              .Set("name", "Google")
-              .Set("url", "http://google.com/"))
+                      .Set("name", "Google")
+                      .Set("url", "http://google.com/"))
           .Append(extensions::DictionaryBuilder()
-              .Set("name", "Empty Folder")
-              .Set("children", extensions::ListBuilder().Pass()))
-          .Append(extensions::DictionaryBuilder()
-              .Set("name", "Big Folder")
-              .Set("children", extensions::ListBuilder()
-                  .Append(extensions::DictionaryBuilder()
-                      .Set("name", "Youtube")
-                      .Set("url", "http://youtube.com/"))
-                  .Append(extensions::DictionaryBuilder()
-                      .Set("name", "Chromium")
-                      .Set("url", "http://chromium.org/"))
-                  .Append(extensions::DictionaryBuilder()
-                      .Set("name", "More Stuff")
-                      .Set("children", extensions::ListBuilder()
-                          .Append(extensions::DictionaryBuilder()
-                              .Set("name", "Bugs")
-                              .Set("url", "http://crbug.com/")
-                              .Pass())
-                          .Pass())
-                      .Pass())
+                      .Set("name", "Empty Folder")
+                      .Set("children", extensions::ListBuilder()))
+          .Append(
+              extensions::DictionaryBuilder()
+                  .Set("name", "Big Folder")
+                  .Set(
+                      "children",
+                      std::move(
+                          extensions::ListBuilder()
+                              .Append(extensions::DictionaryBuilder()
+                                          .Set("name", "Youtube")
+                                          .Set("url", "http://youtube.com/"))
+                              .Append(extensions::DictionaryBuilder()
+                                          .Set("name", "Chromium")
+                                          .Set("url", "http://chromium.org/"))
+                              .Append(
+                                  extensions::DictionaryBuilder()
+                                      .Set("name", "More Stuff")
+                                      .Set("children",
+                                           std::move(
+                                               extensions::ListBuilder().Append(
+                                                   extensions::
+                                                       DictionaryBuilder()
+                                                           .Set("name", "Bugs")
+                                                           .Set("url",
+                                                                "http://"
+                                                                "crbug.com/")
+                                                           .Pass())))
+                                      .Pass())))
                   .Pass())
-              .Pass())
           .Build());
   EXPECT_TRUE(pref_value->Equals(expected.get()));
 }
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index dc61c60..03ad285 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -3269,56 +3269,6 @@
             RedirectHostsToTestData, kRestoredURLs, arraysize(kRestoredURLs)));
   }
 
-  void HomepageIsNotNTP() {
-    // Verifies that policy can set the startup pages to the homepage, when
-    // the homepage is not the NTP.
-    PolicyMap policies;
-    policies.Set(
-        key::kRestoreOnStartup,
-        POLICY_LEVEL_MANDATORY,
-        POLICY_SCOPE_USER,
-        POLICY_SOURCE_CLOUD,
-        new base::FundamentalValue(SessionStartupPref::kPrefValueHomePage),
-        NULL);
-    policies.Set(key::kHomepageIsNewTabPage,
-                 POLICY_LEVEL_MANDATORY,
-                 POLICY_SCOPE_USER,
-                 POLICY_SOURCE_CLOUD,
-                 new base::FundamentalValue(false),
-                 NULL);
-    policies.Set(key::kHomepageLocation,
-                 POLICY_LEVEL_MANDATORY,
-                 POLICY_SCOPE_USER,
-                 POLICY_SOURCE_CLOUD,
-                 new base::StringValue(kRestoredURLs[1]),
-                 NULL);
-    provider_.UpdateChromePolicy(policies);
-
-    expected_urls_.push_back(GURL(kRestoredURLs[1]));
-  }
-
-  void HomepageIsNTP() {
-    // Verifies that policy can set the startup pages to the homepage, when
-    // the homepage is the NTP.
-    PolicyMap policies;
-    policies.Set(
-        key::kRestoreOnStartup,
-        POLICY_LEVEL_MANDATORY,
-        POLICY_SCOPE_USER,
-        POLICY_SOURCE_CLOUD,
-        new base::FundamentalValue(SessionStartupPref::kPrefValueHomePage),
-        NULL);
-    policies.Set(key::kHomepageIsNewTabPage,
-                 POLICY_LEVEL_MANDATORY,
-                 POLICY_SCOPE_USER,
-                 POLICY_SOURCE_CLOUD,
-                 new base::FundamentalValue(true),
-                 NULL);
-    provider_.UpdateChromePolicy(policies);
-
-    expected_urls_.push_back(GURL(chrome::kChromeUINewTabURL));
-  }
-
   void ListOfURLs() {
     // Verifies that policy can set the startup pages to a list of URLs.
     base::ListValue urls;
@@ -3405,9 +3355,7 @@
 INSTANTIATE_TEST_CASE_P(
     RestoreOnStartupPolicyTestInstance,
     RestoreOnStartupPolicyTest,
-    testing::Values(&RestoreOnStartupPolicyTest::HomepageIsNotNTP,
-                    &RestoreOnStartupPolicyTest::HomepageIsNTP,
-                    &RestoreOnStartupPolicyTest::ListOfURLs,
+    testing::Values(&RestoreOnStartupPolicyTest::ListOfURLs,
                     &RestoreOnStartupPolicyTest::NTP,
                     &RestoreOnStartupPolicyTest::Last));
 
diff --git a/chrome/browser/policy/policy_path_parser_win.cc b/chrome/browser/policy/policy_path_parser_win.cc
index 3fa8a99..2e0c197 100644
--- a/chrome/browser/policy/policy_path_parser_win.cc
+++ b/chrome/browser/policy/policy_path_parser_win.cc
@@ -77,7 +77,7 @@
     result = result.substr(1, result.length() - 2);
   }
   // First translate all path variables we recognize.
-  for (int i = 0; i < arraysize(win_folder_mapping); ++i) {
+  for (size_t i = 0; i < arraysize(win_folder_mapping); ++i) {
     size_t position = result.find(win_folder_mapping[i].name);
     if (position != std::wstring::npos) {
       WCHAR path[MAX_PATH];
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 57862ff..6358cf6 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -242,6 +242,9 @@
 const char kRestoreStartupURLsMigrationTime[] =
   "session.startup_urls_migration_time";
 
+// Deprecated 12/2015.
+const char kRestoreOnStartupMigrated[] = "session.restore_on_startup_migrated";
+
 }  // namespace
 
 namespace chrome {
@@ -542,6 +545,7 @@
 
   registry->RegisterListPref(kURLsToRestoreOnStartupOld);
   registry->RegisterInt64Pref(kRestoreStartupURLsMigrationTime, 0);
+  registry->RegisterBooleanPref(kRestoreOnStartupMigrated, false);
 }
 
 void RegisterUserProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
@@ -593,6 +597,9 @@
   // Added 12/1015.
   profile_prefs->ClearPref(kURLsToRestoreOnStartupOld);
   profile_prefs->ClearPref(kRestoreStartupURLsMigrationTime);
+
+  // Added 12/2015.
+  profile_prefs->ClearPref(kRestoreOnStartupMigrated);
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/prefs/session_startup_pref.cc b/chrome/browser/prefs/session_startup_pref.cc
index 6e30712..51fb6c5 100644
--- a/chrome/browser/prefs/session_startup_pref.cc
+++ b/chrome/browser/prefs/session_startup_pref.cc
@@ -25,16 +25,6 @@
   }
 }
 
-void SetNewURLList(PrefService* prefs) {
-  if (prefs->IsUserModifiablePreference(prefs::kURLsToRestoreOnStartup)) {
-    base::ListValue new_url_pref_list;
-    base::StringValue* home_page =
-        new base::StringValue(prefs->GetString(prefs::kHomePage));
-    new_url_pref_list.Append(home_page);
-    prefs->Set(prefs::kURLsToRestoreOnStartup, new_url_pref_list);
-  }
-}
-
 void URLListToPref(const base::ListValue* url_list, SessionStartupPref* pref) {
   pref->urls.clear();
   for (size_t i = 0; i < url_list->GetSize(); ++i) {
@@ -57,7 +47,6 @@
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterListPref(prefs::kURLsToRestoreOnStartup,
                              user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
-  registry->RegisterBooleanPref(prefs::kRestoreOnStartupMigrated, false);
 }
 
 // static
@@ -110,8 +99,6 @@
 SessionStartupPref SessionStartupPref::GetStartupPref(PrefService* prefs) {
   DCHECK(prefs);
 
-  MigrateIfNecessary(prefs);
-
   SessionStartupPref pref(
       PrefValueToType(prefs->GetInteger(prefs::kRestoreOnStartup)));
 
@@ -125,54 +112,6 @@
 }
 
 // static
-void SessionStartupPref::MigrateIfNecessary(PrefService* prefs) {
-  DCHECK(prefs);
-
-  if (!prefs->GetBoolean(prefs::kRestoreOnStartupMigrated)) {
-    // Read existing values.
-    const base::Value* homepage_is_new_tab_page_value =
-        prefs->GetUserPrefValue(prefs::kHomePageIsNewTabPage);
-    bool homepage_is_new_tab_page = true;
-    if (homepage_is_new_tab_page_value) {
-      if (!homepage_is_new_tab_page_value->GetAsBoolean(
-              &homepage_is_new_tab_page))
-        NOTREACHED();
-    }
-
-    const base::Value* restore_on_startup_value =
-        prefs->GetUserPrefValue(prefs::kRestoreOnStartup);
-    int restore_on_startup = -1;
-    if (restore_on_startup_value) {
-      if (!restore_on_startup_value->GetAsInteger(&restore_on_startup))
-        NOTREACHED();
-    }
-
-    // If restore_on_startup has the deprecated value kPrefValueHomePage,
-    // migrate it to open the homepage on startup. If 'homepage is NTP' is set,
-    // that means just opening the NTP. If not, it means opening a one-item URL
-    // list containing the homepage.
-    if (restore_on_startup == kPrefValueHomePage) {
-      if (homepage_is_new_tab_page) {
-        prefs->SetInteger(prefs::kRestoreOnStartup, kPrefValueNewTab);
-      } else {
-        prefs->SetInteger(prefs::kRestoreOnStartup, kPrefValueURLs);
-        SetNewURLList(prefs);
-      }
-    } else if (!restore_on_startup_value && !homepage_is_new_tab_page &&
-               GetDefaultStartupType() == DEFAULT) {
-      // kRestoreOnStartup was never set by the user, but the homepage was set.
-      // Migrate to the list of URLs. (If restore_on_startup was never set,
-      // and homepage_is_new_tab_page is true, no action is needed. The new
-      // default value is "open the new tab page" which is what we want.)
-      prefs->SetInteger(prefs::kRestoreOnStartup, kPrefValueURLs);
-      SetNewURLList(prefs);
-    }
-
-    prefs->SetBoolean(prefs::kRestoreOnStartupMigrated, true);
-  }
-}
-
-// static
 bool SessionStartupPref::TypeIsManaged(PrefService* prefs) {
   DCHECK(prefs);
   const PrefService::Preference* pref_restore =
@@ -204,7 +143,6 @@
   switch (pref_value) {
     case kPrefValueLast:     return SessionStartupPref::LAST;
     case kPrefValueURLs:     return SessionStartupPref::URLS;
-    case kPrefValueHomePage: return SessionStartupPref::HOMEPAGE;
     default:                 return SessionStartupPref::DEFAULT;
   }
 }
diff --git a/chrome/browser/prefs/session_startup_pref.h b/chrome/browser/prefs/session_startup_pref.h
index 0a7aeec0..67ebeaa 100644
--- a/chrome/browser/prefs/session_startup_pref.h
+++ b/chrome/browser/prefs/session_startup_pref.h
@@ -23,25 +23,18 @@
     // Indicates the user wants to open the New Tab page.
     DEFAULT,
 
-    // Deprecated. See comment in session_startup_pref.cc
-    HOMEPAGE,
-
     // Indicates the user wants to restore the last session.
     LAST,
 
     // Indicates the user wants to restore a specific set of URLs. The URLs
     // are contained in urls.
     URLS,
-
-    // Number of values in this enum.
-    TYPE_COUNT
   };
 
   // For historical reasons the enum and value registered in the prefs don't
   // line up. These are the values registered in prefs.
   // The values are also recorded in Settings.StartupPageLoadSettings histogram,
   // so make sure to update histograms.xml if you change these.
-  static const int kPrefValueHomePage = 0;  // Deprecated
   static const int kPrefValueLast = 1;
   static const int kPrefValueURLs = 4;
   static const int kPrefValueNewTab = 5;
@@ -59,11 +52,6 @@
   static SessionStartupPref GetStartupPref(Profile* profile);
   static SessionStartupPref GetStartupPref(PrefService* prefs);
 
-  // If the user had the "restore on startup" property set to the deprecated
-  // "Open the home page" value, this migrates them to a value that will have
-  // the same effect.
-  static void MigrateIfNecessary(PrefService* prefs);
-
   // Whether the startup type and URLs are managed via policy.
   static bool TypeIsManaged(PrefService* prefs);
   static bool URLsAreManaged(PrefService* prefs);
diff --git a/chrome/browser/prefs/session_startup_pref_unittest.cc b/chrome/browser/prefs/session_startup_pref_unittest.cc
index 1e8d221..31385b4 100644
--- a/chrome/browser/prefs/session_startup_pref_unittest.cc
+++ b/chrome/browser/prefs/session_startup_pref_unittest.cc
@@ -18,15 +18,6 @@
     registry()->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, true);
   }
 
-  bool IsUseLastOpenDefault() {
-    // On ChromeOS, the default SessionStartupPref is LAST.
-#if defined(OS_CHROMEOS)
-    return true;
-#else
-    return false;
-#endif
-  }
-
   user_prefs::PrefRegistrySyncable* registry() {
     return pref_service_->registry();
   }
@@ -71,88 +62,3 @@
   result = SessionStartupPref::GetStartupPref(pref_service_.get());
   EXPECT_EQ(3u, result.urls.size());
 }
-
-// Checks to make sure that if the user had previously not selected anything
-// (so that, in effect, the default value "Open the homepage" was selected),
-// their preferences are migrated on upgrade to m19.
-TEST_F(SessionStartupPrefTest, DefaultMigration) {
-  registry()->RegisterStringPref(prefs::kHomePage, "http://google.com/");
-  pref_service_->SetString(prefs::kHomePage, "http://chromium.org/");
-  pref_service_->SetBoolean(prefs::kHomePageIsNewTabPage, false);
-
-  EXPECT_FALSE(pref_service_->HasPrefPath(prefs::kRestoreOnStartup));
-
-  SessionStartupPref pref = SessionStartupPref::GetStartupPref(
-      pref_service_.get());
-
-  if (IsUseLastOpenDefault()) {
-    EXPECT_EQ(SessionStartupPref::LAST, pref.type);
-    EXPECT_EQ(0U, pref.urls.size());
-  } else {
-    EXPECT_EQ(SessionStartupPref::URLS, pref.type);
-    EXPECT_EQ(1U, pref.urls.size());
-    EXPECT_EQ(GURL("http://chromium.org/"), pref.urls[0]);
-  }
-}
-
-// Checks to make sure that if the user had previously not selected anything
-// (so that, in effect, the default value "Open the homepage" was selected),
-// and the NTP is being used for the homepage, their preferences are migrated
-// to "Open the New Tab Page" on upgrade to M19.
-TEST_F(SessionStartupPrefTest, DefaultMigrationHomepageIsNTP) {
-  registry()->RegisterStringPref(prefs::kHomePage, "http://google.com/");
-  pref_service_->SetString(prefs::kHomePage, "http://chromium.org/");
-  pref_service_->SetBoolean(prefs::kHomePageIsNewTabPage, true);
-
-  EXPECT_FALSE(pref_service_->HasPrefPath(prefs::kRestoreOnStartup));
-
-  SessionStartupPref pref = SessionStartupPref::GetStartupPref(
-      pref_service_.get());
-
-  if (IsUseLastOpenDefault())
-    EXPECT_EQ(SessionStartupPref::LAST, pref.type);
-  else
-    EXPECT_EQ(SessionStartupPref::DEFAULT, pref.type);
-
-  // The "URLs to restore on startup" shouldn't get migrated.
-  EXPECT_EQ(0U, pref.urls.size());
-}
-
-// Checks to make sure that if the user had previously selected "Open the
-// "homepage", their preferences are migrated on upgrade to M19.
-TEST_F(SessionStartupPrefTest, HomePageMigration) {
-  registry()->RegisterStringPref(prefs::kHomePage, "http://google.com/");
-
-  // By design, it's impossible to set the 'restore on startup' pref to 0
-  // ("open the homepage") using SessionStartupPref::SetStartupPref(), so set it
-  // using the pref service directly.
-  pref_service_->SetInteger(prefs::kRestoreOnStartup, /*kPrefValueHomePage*/ 0);
-  pref_service_->SetString(prefs::kHomePage, "http://chromium.org/");
-  pref_service_->SetBoolean(prefs::kHomePageIsNewTabPage, false);
-
-  SessionStartupPref pref = SessionStartupPref::GetStartupPref(
-      pref_service_.get());
-
-  EXPECT_EQ(SessionStartupPref::URLS, pref.type);
-  EXPECT_EQ(1U, pref.urls.size());
-  EXPECT_EQ(GURL("http://chromium.org/"), pref.urls[0]);
-}
-
-// Checks to make sure that if the user had previously selected "Open the
-// "homepage", and the NTP is being used for the homepage, their preferences
-// are migrated on upgrade to M19.
-TEST_F(SessionStartupPrefTest, HomePageMigrationHomepageIsNTP) {
-  registry()->RegisterStringPref(prefs::kHomePage, "http://google.com/");
-
-  // By design, it's impossible to set the 'restore on startup' pref to 0
-  // ("open the homepage") using SessionStartupPref::SetStartupPref(), so set it
-  // using the pref service directly.
-  pref_service_->SetInteger(prefs::kRestoreOnStartup, /*kPrefValueHomePage*/ 0);
-  pref_service_->SetString(prefs::kHomePage, "http://chromium.org/");
-  pref_service_->SetBoolean(prefs::kHomePageIsNewTabPage, true);
-
-  SessionStartupPref pref = SessionStartupPref::GetStartupPref(
-      pref_service_.get());
-
-  EXPECT_EQ(SessionStartupPref::DEFAULT, pref.type);
-}
diff --git a/chrome/browser/profile_resetter/profile_resetter.cc b/chrome/browser/profile_resetter/profile_resetter.cc
index bbbf0c4..346f47c 100644
--- a/chrome/browser/profile_resetter/profile_resetter.cc
+++ b/chrome/browser/profile_resetter/profile_resetter.cc
@@ -282,7 +282,6 @@
   else
     prefs->ClearPref(prefs::kRestoreOnStartup);
 
-  prefs->SetBoolean(prefs::kRestoreOnStartupMigrated, true);
   MarkAsDone(STARTUP_PAGES);
 }
 
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 2e73738..8b4ece12 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -63,7 +63,6 @@
 
 #if defined(ENABLE_EXTENSIONS)
 #include "apps/browser_context_keyed_service_factories.h"
-#include "chrome/browser/apps/ephemeral_app_service_factory.h"
 #include "chrome/browser/apps/shortcut_manager_factory.h"
 #include "chrome/browser/extensions/api/networking_private/networking_private_ui_delegate_factory_impl.h"
 #include "chrome/browser/extensions/api/networking_private/networking_private_verify_delegate_factory_impl.h"
@@ -175,7 +174,6 @@
   extensions::ExtensionManagementFactory::GetInstance();
   chrome_extensions::EnsureBrowserContextKeyedServiceFactoriesBuilt();
   AppShortcutManagerFactory::GetInstance();
-  EphemeralAppServiceFactory::GetInstance();
 #endif
 
 #if defined(ENABLE_APP_LIST)
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index f967a254..18bc6df4 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -139,6 +139,7 @@
   registry->RegisterBooleanPref(prefs::kDevToolsRemoteEnabled, false);
 #endif
 
+  registry->RegisterBooleanPref(prefs::kDataSaverEnabled, false);
   data_reduction_proxy::RegisterSyncableProfilePrefs(registry);
 
 #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) && !defined(OS_IOS)
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 28e4090..ebd8ed7 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -324,7 +324,6 @@
     user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterBooleanPref(prefs::kSavingBrowserHistoryDisabled, false);
   registry->RegisterBooleanPref(prefs::kAllowDeletingBrowserHistory, true);
-  registry->RegisterBooleanPref(prefs::kSigninAllowed, true);
   registry->RegisterBooleanPref(prefs::kForceGoogleSafeSearch, false);
   registry->RegisterBooleanPref(prefs::kForceYouTubeSafetyMode, false);
   registry->RegisterBooleanPref(prefs::kRecordHistory, false);
diff --git a/chrome/browser/push_messaging/push_messaging_permission_context.cc b/chrome/browser/push_messaging/push_messaging_permission_context.cc
index 7bf8cfe..7e689f4 100644
--- a/chrome/browser/push_messaging/push_messaging_permission_context.cc
+++ b/chrome/browser/push_messaging/push_messaging_permission_context.cc
@@ -12,15 +12,15 @@
 #include "chrome/browser/profiles/profile.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/permission_type.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/origin_util.h"
 
-const ContentSettingsType kPushSettingType =
-    CONTENT_SETTINGS_TYPE_PUSH_MESSAGING;
-
 PushMessagingPermissionContext::PushMessagingPermissionContext(Profile* profile)
-    : PermissionContextBase(profile, CONTENT_SETTINGS_TYPE_PUSH_MESSAGING),
+    : PermissionContextBase(profile,
+                            content::PermissionType::PUSH_MESSAGING,
+                            CONTENT_SETTINGS_TYPE_PUSH_MESSAGING),
       profile_(profile),
       weak_factory_ui_thread_(this) {}
 
@@ -111,12 +111,12 @@
   ContentSetting push_content_setting =
       HostContentSettingsMapFactory::GetForProfile(profile_)
           ->GetContentSettingAndMaybeUpdateLastUsage(
-              requesting_origin, embedding_origin, kPushSettingType,
+              requesting_origin, embedding_origin, content_settings_type(),
               std::string());
 
   if (push_content_setting == CONTENT_SETTING_BLOCK) {
     DVLOG(1) << "Push permission was explicitly blocked.";
-    PermissionUmaUtil::PermissionDenied(kPushSettingType, requesting_origin);
+    PermissionUmaUtil::PermissionDenied(permission_type(), requesting_origin);
     NotifyPermissionSet(id, requesting_origin, embedding_origin, callback,
                         true /* persist */, CONTENT_SETTING_BLOCK);
     return;
@@ -129,7 +129,7 @@
     return;
   }
 
-  PermissionUmaUtil::PermissionGranted(kPushSettingType, requesting_origin);
+  PermissionUmaUtil::PermissionGranted(permission_type(), requesting_origin);
   NotifyPermissionSet(id, requesting_origin, embedding_origin, callback,
                       true /* persist */, CONTENT_SETTING_ALLOW);
 }
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc
index afcfcc4..ae80f2b 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc
@@ -19,13 +19,13 @@
 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_factory.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
 #include "components/data_reduction_proxy/core/browser/data_store.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
 #include "components/proxy_config/proxy_config_pref_names.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_renderer_host.h"
@@ -385,12 +385,10 @@
     PrefRegistrySimple* registry =
         drp_test_context_->pref_service()->registry();
     registry->RegisterDictionaryPref(proxy_config::prefs::kProxy);
-
-    drp_test_context_->pref_service()->SetBoolean(
-        data_reduction_proxy::prefs::kDataReductionProxyEnabled,
+    drp_test_context_->SetDataReductionProxyEnabled(
         enable_data_reduction_proxy);
-    drp_test_context_->InitSettings();
-
+    settings->set_data_reduction_proxy_enabled_pref_name_for_test(
+        drp_test_context_->GetDataReductionProxyEnabledPrefName());
     settings->InitDataReductionProxySettings(
         drp_test_context_->io_data(), drp_test_context_->pref_service(),
         drp_test_context_->request_context_getter(),
diff --git a/chrome/browser/repost_form_warning_controller.cc b/chrome/browser/repost_form_warning_controller.cc
index 0dadfc9..815f0a1 100644
--- a/chrome/browser/repost_form_warning_controller.cc
+++ b/chrome/browser/repost_form_warning_controller.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/repost_form_warning_controller.h"
 
-#include "chrome/grit/generated_resources.h"
+#include "components/strings/grit/components_strings.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
index 34e73eba..fd0a7547 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
@@ -169,8 +169,7 @@
       } else {
         // When in compat mode, if the focus is within the desktop tree proper,
         // then do not disable content scripts.
-        if (this.currentRange_ &&
-            this.currentRange_.start.node.root.role == RoleType.desktop)
+        if (this.currentRange_ && !this.currentRange_.isWebRange())
           return;
 
         this.disableClassicChromeVox_();
@@ -196,7 +195,8 @@
     if (mode != ChromeVoxMode.FORCE_NEXT) {
       if (this.isWhitelistedForNext_(url))
         mode = ChromeVoxMode.NEXT;
-      else if (this.isBlacklistedForClassic_(url))
+      else if (this.isBlacklistedForClassic_(url) || (this.currentRange_ &&
+          !this.currentRange_.isWebRange()))
         mode = ChromeVoxMode.COMPAT;
       else
         mode = ChromeVoxMode.CLASSIC;
@@ -440,9 +440,8 @@
       case 'toggleChromeVoxVersion':
         var newMode;
         if (this.mode_ == ChromeVoxMode.FORCE_NEXT) {
-          var inViews =
-              this.currentRange_.start.node.root.role == RoleType.desktop;
-          newMode = inViews ? ChromeVoxMode.COMPAT : ChromeVoxMode.CLASSIC;
+          var inWeb = current.isWebRange();
+          newMode = inWeb ? ChromeVoxMode.CLASSIC : ChromeVoxMode.COMPAT;
         } else {
           newMode = ChromeVoxMode.FORCE_NEXT;
         }
@@ -573,7 +572,7 @@
    * @private
    */
   isBlacklistedForClassic_: function(url) {
-    return url === '' || this.classicBlacklistRegExp_.test(url);
+    return this.classicBlacklistRegExp_.test(url);
   },
 
   /**
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
index 36191c46..2c573bb 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
@@ -467,3 +467,31 @@
     }
   );
 });
+
+TEST_F('BackgroundTest', 'ModeSwitching', function() {
+  this.runWithLoadedTree('<button></button>', function(root) {
+    // Tests default to force next mode.
+    assertEquals('force_next', global.backgroundObj.mode);
+
+    // Force next mode stays set regardless of where the range lands.
+    global.backgroundObj.refreshMode('http://google.com');
+    assertEquals('force_next', global.backgroundObj.mode);
+    // Empty urls occur before document load or when root is desktop.
+    global.backgroundObj.refreshMode('');
+    assertEquals('force_next', global.backgroundObj.mode);
+
+    // Verify compat -> classic switching.
+    global.backgroundObj.setMode('compat');
+    global.backgroundObj.refreshMode('http://google.com');
+    assertEquals('classic', global.backgroundObj.mode);
+
+    global.backgroundObj.setCurrentRange(cursors.Range.fromNode(root.parent));
+    global.backgroundObj.refreshMode('');
+    assertEquals('compat', global.backgroundObj.mode);
+
+    // And back to classic.
+    global.backgroundObj.setCurrentRange(cursors.Range.fromNode(root));
+    global.backgroundObj.refreshMode('');
+    assertEquals('classic', global.backgroundObj.mode);
+  }.bind(this));
+});
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
index 5067cf8..5b5a869 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
@@ -433,6 +433,15 @@
         break;
     }
     return new cursors.Range(newStart, newEnd);
+  },
+
+  /**
+   * Returns true if this range has either cursor end on web content.
+   * @return {boolean}
+  */
+  isWebRange: function() {
+    return this.start.node.root.role != Role.desktop ||
+        this.end.node.root.role != Role.desktop;
   }
 };
 
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
index fab8d6ab..bb50767 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
@@ -303,3 +303,13 @@
     assertEquals(root.firstChild.firstChild, cursor.node);
   });
 });
+
+TEST_F('CursorsTest', 'IsInWebRange', function() {
+  this.runWithLoadedTree(this.simpleDoc, function(root) {
+    var para = root.firstChild;
+    var webRange = new cursors.Range.fromNode(para);
+    var auraRange = cursors.Range.fromNode(root.parent);
+    assertFalse(auraRange.isWebRange());
+    assertTrue(webRange.isWebRange());
+  });
+});
diff --git a/chrome/browser/resources/chromeos/chromevox/host/chrome/tts_background.js b/chrome/browser/resources/chromeos/chromevox/host/chrome/tts_background.js
index a70c7588..29306a4 100644
--- a/chrome/browser/resources/chromeos/chromevox/host/chrome/tts_background.js
+++ b/chrome/browser/resources/chromeos/chromevox/host/chrome/tts_background.js
@@ -253,9 +253,10 @@
   // pattern causes ChromeVox to read numbers as digits rather than words.
   textString = this.getNumberAsDigits_(textString);
 
-  // TODO(dtseng): Google TTS flushes the queue when encountering strings of
-  // this pattern which stops ChromeVox speech.
-  if (!textString || !textString.match(/\w+/g)) {
+  // TODO(plundblad): Google TTS doesn't handle strings that don't produce
+  // any speech very well. Handle empty and whitespace only strings (including
+  // non-breaking space) here to mitigate the issue somewhat.
+  if (/^[\s\u00a0]*$/.test(textString)) {
     // We still want to callback for listeners in our content script.
     if (properties['startCallback']) {
       try {
diff --git a/chrome/browser/resources/chromeos/chromevox/host/chrome/tts_background_test.extjs b/chrome/browser/resources/chromeos/chromevox/host/chrome/tts_background_test.extjs
index b3d1d716..dda509d7 100644
--- a/chrome/browser/resources/chromeos/chromevox/host/chrome/tts_background_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/host/chrome/tts_background_test.extjs
@@ -71,3 +71,23 @@
   tts.updateVoice_('French');
   assertEquals('French', tts.currentVoice);
 });
+
+SYNC_TEST_F('CvoxTtsBackgroundTest', 'EmptyStringCallsCallbacks', function() {
+  var tts = new cvox.TtsBackground(false);
+  chrome.tts.speak = assertNotReached.bind(
+      null, 'chrome.tts.speak shouldn\t be called.');
+
+  assertCallsCallbacks = function(text) {
+    var startCalls = 0;
+    var endCalls = 0;
+    tts.speak(text, cvox.QueueMode.QUEUE,
+              {startCallback: function() { ++startCalls; },
+               endCallback: function() { ++endCalls; }});
+    assertEquals(1, startCalls, text);
+    assertEquals(1, endCalls, text);
+  }.bind(this);
+
+  assertCallsCallbacks('');
+  assertCallsCallbacks('  ');
+  assertCallsCallbacks(' \u00a0 ');
+});
diff --git a/chrome/browser/resources/chromeos/chromevox/testing/mock_feedback_test.unitjs b/chrome/browser/resources/chromeos/chromevox/testing/mock_feedback_test.unitjs
index 5466b773..c1bdf6167 100644
--- a/chrome/browser/resources/chromeos/chromevox/testing/mock_feedback_test.unitjs
+++ b/chrome/browser/resources/chromeos/chromevox/testing/mock_feedback_test.unitjs
@@ -154,7 +154,7 @@
   mock.replay();
   assertException('', function() {
     mock.expectSpeech('hello');
-  }, 'Error');
+  }, 'AssertionError');
 });
 
 TEST_F('MockFeedbackUnitTest', 'NoMatchDoesNotFinish', function() {
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.js b/chrome/browser/resources/local_ntp/most_visited_single.js
index 6c51584b..98ebea5 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.js
+++ b/chrome/browser/resources/local_ntp/most_visited_single.js
@@ -300,10 +300,8 @@
           window.devicePixelRatio + 'x/' + data.renderViewId + '/' + data.tid;
     }
     tiles.appendChild(renderTile(data));
-    logEvent(LOG_TYPE.NTP_CLIENT_SIDE_SUGGESTION);
   } else if (args.id) {
     tiles.appendChild(renderTile(args));
-    logEvent(LOG_TYPE.NTP_SERVER_SIDE_SUGGESTION);
   } else {
     tiles.appendChild(renderTile(null));
   }
diff --git a/chrome/browser/resources/md_extensions/manager.html b/chrome/browser/resources/md_extensions/manager.html
index 2dd99ba..30c5e07 100644
--- a/chrome/browser/resources/md_extensions/manager.html
+++ b/chrome/browser/resources/md_extensions/manager.html
@@ -12,19 +12,26 @@
     <paper-header-panel id="panel">
       <extensions-toolbar class="paper-header" id="toolbar">
       </extensions-toolbar>
-      <extensions-sidebar in-dev-mode="[[inDevMode]]"></extensions-sidebar>
+      <extensions-sidebar in-dev-mode="[[inDevMode]]"
+          hide-extensions-button="[[computeListHidden_(extensions, extensions.splices)]]"
+          hide-apps-button="[[computeListHidden_(apps, apps.splices)]]"
+          hide-websites-button="[[computeListHidden_(websites, websites.splices)]]">
+      </extensions-sidebar>
       <div id="items">
         <extensions-item-list id="extensions-list" items="[[extensions]]"
             delegate="[[service]]" header="[[i18n('sidebarExtensions')]]"
-            in-dev-mode="[[inDevMode]]">
+            in-dev-mode="[[inDevMode]]"
+            hidden$="[[computeListHidden_(extensions, extensions.splices)]]">
         </extensions-item-list>
         <extensions-item-list id="apps-list" items="[[apps]]"
             delegate="[[service]]" header="[[i18n('sidebarApps')]]"
-            in-dev-mode="[[inDevMode]]">
+            in-dev-mode="[[inDevMode]]"
+            hidden$="[[computeListHidden_(apps, apps.splices)]]">
         </extensions-item-list>
         <extensions-item-list id="websites-list" items="[[websites]]"
             delegate="[[service]]" header="[[i18n('sidebarWebsites')]]"
-            in-dev-mode="[[inDevMode]]">
+            in-dev-mode="[[inDevMode]]"
+            hidden$="[[computeListHidden_(websites, websites.splices)]]">
         </extensions-item-list>
       </div>
     </paper-header-panel>
diff --git a/chrome/browser/resources/md_extensions/manager.js b/chrome/browser/resources/md_extensions/manager.js
index 417b5aa3..3b5a9fb 100644
--- a/chrome/browser/resources/md_extensions/manager.js
+++ b/chrome/browser/resources/md_extensions/manager.js
@@ -69,7 +69,8 @@
 
     ready: function() {
       /** @type {extensions.Sidebar} */
-      this.sidebar = this.$$('extensions-sidebar');
+      this.sidebar =
+          /** @type {extensions.Sidebar} */(this.$$('extensions-sidebar'));
       this.service = extensions.Service.getInstance();
       this.service.managerReady(this);
       this.sidebar.setScrollDelegate(new ScrollHelper(this));
@@ -117,6 +118,14 @@
     },
 
     /**
+     * @param {!Array<!chrome.developerPrivate.ExtensionInfo>} list
+     * @return {boolean} Whether the list should be visible.
+     */
+    computeListHidden_: function(list) {
+      return list.length == 0;
+    },
+
+    /**
      * 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
diff --git a/chrome/browser/resources/md_extensions/sidebar.html b/chrome/browser/resources/md_extensions/sidebar.html
index 4a8c173..a56a9e46 100644
--- a/chrome/browser/resources/md_extensions/sidebar.html
+++ b/chrome/browser/resources/md_extensions/sidebar.html
@@ -10,17 +10,17 @@
   <template>
     <paper-menu id="section-menu">
       <paper-item class="section-menu-item" id="sections-extensions"
-          on-tap="onExtensionsTap_">
+          on-tap="onExtensionsTap_" hidden$="[[hideExtensionsButton]]">
         <iron-icon icon="extension"></iron-icon>
         <span i18n-content="sidebarExtensions"></span>
       </paper-item>
       <paper-item class="section-menu-item" id="sections-apps"
-          on-tap="onAppsTap_">
+          on-tap="onAppsTap_" hidden$="[[hideAppsButton]]">
         <iron-icon icon="apps"></iron-icon>
         <span i18n-content="sidebarApps"></span>
       </paper-item>
       <paper-item class="section-menu-item" id="sections-websites"
-          on-tap="onWebsitesTap_">
+          on-tap="onWebsitesTap_" hidden$="[[hideWebsitesButton]]">
         <iron-icon icon="cloud"></iron-icon>
         <span i18n-content="sidebarWebsites"></span>
       </paper-item>
diff --git a/chrome/browser/resources/md_extensions/sidebar.js b/chrome/browser/resources/md_extensions/sidebar.js
index 47c68a7..622c5ec3 100644
--- a/chrome/browser/resources/md_extensions/sidebar.js
+++ b/chrome/browser/resources/md_extensions/sidebar.js
@@ -45,6 +45,21 @@
         type: Boolean,
         value: false,
       },
+
+      hideExtensionsButton: {
+        type: Boolean,
+        value: false,
+      },
+
+      hideAppsButton: {
+        type: Boolean,
+        value: false,
+      },
+
+      hideWebsitesButton: {
+        type: Boolean,
+        value: false,
+      },
     },
 
     behaviors: [
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 3fc7746b..f10423ad 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
@@ -29,7 +29,7 @@
       </issue-banner>
     </template>
     <paper-menu id="cast-mode-list"
-        hidden$="[[computeCastModeHidden_(currentView_)]]">
+        hidden$="[[computeCastModeListHidden_(currentView_)]]">
       <template is="dom-repeat" id="defaultCastModeList"
           items="[[computeDefaultCastModeList_(castModeList)]]">
         <paper-item on-click="onCastModeClick_">
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 f88b92f..f9e561f4 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
@@ -162,14 +162,6 @@
     },
 
     /**
-     * The value of the selected cast mode in |castModeList|.
-     * @private {number}
-     */
-    selectedCastModeValue_: {
-      type: Number,
-    },
-
-    /**
      * The subheading text for the non-cast-enabled app cast mode list.
      * @private {string}
      */
@@ -180,6 +172,25 @@
     },
 
     /**
+     * The cast mode shown to the user. Initially set to auto mode. (See
+     * media_router.CastMode documentation for details on auto mode.)
+     * This value may be changed in one of the following ways:
+     * 1) The user explicitly selected a cast mode.
+     * 2) The user selected cast mode is no longer available for the associated
+     *    WebContents. In this case, the container will reset to auto mode. Note
+     *    that |userHasSelectedCastMode_| will switch back to false.
+     * 3) The sink list changed, and the user had not explicitly selected a cast
+     *    mode. If the sinks support exactly 1 cast mode, the container will
+     *    switch to that cast mode. Otherwise, the container will reset to auto
+     *    mode.
+     * @private {number}
+     */
+    shownCastModeValue_: {
+      type: Number,
+      value: media_router.AUTO_CAST_MODE.type,
+    },
+
+    /**
      * Maps media_router.Sink.id to corresponding media_router.Sink.
      * @private {!Object<!string, !media_router.Sink>}
      */
@@ -215,6 +226,15 @@
       type: Array,
       value: [],
     },
+
+    /**
+     * Whether the user has explicitly selected a cast mode.
+     * @private {boolean}
+     */
+    userHasSelectedCastMode_: {
+      type: Boolean,
+      value: false,
+    },
   },
 
   listeners: {
@@ -243,18 +263,49 @@
    * cast mode to the first available cast mode on the list.
    */
   checkCurrentCastMode_: function() {
-    if (this.castModeList.length > 0 &&
-        !this.findCastModeByType_(this.selectedCastModeValue_)) {
-      this.setSelectedCastMode_(this.castModeList[0]);
+    if (!this.castModeList.length)
+      return;
+
+    // If we are currently showing auto mode, then nothing needs to be done.
+    // Otherwise, if the cast mode currently shown no longer exists (regardless
+    // of whether it was selected by user), then switch back to auto cast mode.
+    if (this.shownCastModeValue_ != media_router.CastModeType.AUTO &&
+        !this.findCastModeByType_(this.shownCastModeValue_)) {
+      this.setShownCastMode_(media_router.AUTO_CAST_MODE);
+      this.rebuildSinksToShow_();
     }
   },
 
   /**
+   * If |allSinks| supports only a single cast mode, returns that cast mode.
+   * Otherwise, returns AUTO_MODE. Only called if |userHasSelectedCastMode_| is
+   * |false|.
+   * @return {!media_router.CastMode} The single cast mode supported by
+   *                                  |allSinks|, or AUTO_MODE.
+   */
+  computeCastMode_: function() {
+    var allCastModes = this.allSinks.reduce(function(castModesSoFar, sink) {
+      return castModesSoFar | sink.castModes;
+    }, 0);
+
+    // This checks whether |castModes| does not consist of exactly 1 cast mode.
+    if (!allCastModes || allCastModes & (allCastModes - 1))
+      return media_router.AUTO_CAST_MODE;
+
+    var castMode = this.findCastModeByType_(allCastModes);
+    if (castMode)
+      return castMode;
+
+    console.error('Cast mode ' + allCastModes + ' not in castModeList');
+    return media_router.AUTO_CAST_MODE;
+  },
+
+  /**
    * @param {media_router.MediaRouterView} view The current view.
    * @return {boolean} Whether or not to hide the cast mode list.
    * @private
    */
-  computeCastModeHidden_: function(view) {
+  computeCastModeListHidden_: function(view) {
     return view != media_router.MediaRouterView.CAST_MODE_LIST;
   },
 
@@ -521,23 +572,6 @@
   },
 
   /**
-   * Sets the list of available cast modes and the initial cast mode.
-   *
-   * @param {!Array<!media_router.CastMode>} availableCastModes The list
-   *     of available cast modes.
-   * @param {number} initialCastModeType The initial cast mode when dialog is
-   *     opened.
-   */
-  initializeCastModes: function(availableCastModes, initialCastModeType) {
-    this.castModeList = availableCastModes;
-    var castMode = this.findCastModeByType_(initialCastModeType);
-    if (!castMode)
-      return;
-
-    this.setSelectedCastMode_(castMode);
-  },
-
-  /**
    * 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.
@@ -572,7 +606,7 @@
 
   /**
    * Handles a cast mode selection. Updates |headerText|, |headerTextTooltip|,
-   * and |selectedCastModeValue_|.
+   * and |shownCastModeValue_|.
    *
    * @param {!Event} event The event object.
    * @private
@@ -587,7 +621,15 @@
     if (!clickedMode)
       return;
 
-    this.setSelectedCastMode_(clickedMode);
+    this.userHasSelectedCastMode_ = true;
+
+    // The list of sinks to show will be the same if the shown cast mode did
+    // not change, regardless of whether the user selected it explicitly.
+    if (clickedMode.type != this.shownCastModeValue_) {
+      this.setShownCastMode_(clickedMode);
+      this.rebuildSinksToShow_();
+    }
+
     this.showSinkList_();
   },
 
@@ -718,22 +760,22 @@
    */
   rebuildSinksToShow_: function() {
     var sinksToShow = [];
-    this.allSinks.forEach(function(element) {
-      if (element.castModes.indexOf(this.selectedCastModeValue_) != -1 ||
-          this.sinkToRouteMap_[element.id]) {
-        sinksToShow.push(element);
-      }
-    }, this);
-
-    // Sort the |sinksToShow| by name.  If any two devices have the same name,
-    // use their IDs to stabilize the ordering.
-    sinksToShow.sort(function(a, b) {
-      var ordering = a.name.localeCompare(b.name);
-      if (ordering != 0) {
-        return ordering;
-      }
-      return (a.id < b.id) ? -1 : ((a.id == b.id) ? 0 : 1);
-    });
+    if (this.userHasSelectedCastMode_) {
+      // If user explicitly selected a cast mode, then we show only sinks that
+      // are compatible with current cast mode or sinks that are active.
+      sinksToShow = this.allSinks.filter(function(element) {
+        return (element.castModes & this.shownCastModeValue_) ||
+               this.sinkToRouteMap_[element.id];
+      }, this);
+    } else {
+      // If user did not select a cast mode, then:
+      // - If all sinks support only a single cast mode, then the cast mode is
+      //   switched to that mode.
+      // - Otherwise, the cast mode becomes auto mode.
+      // Either way, all sinks will be shown.
+      this.setShownCastMode_(this.computeCastMode_());
+      sinksToShow = this.allSinks;
+    }
 
     this.sinksToShow_ = sinksToShow;
   },
@@ -754,18 +796,21 @@
   },
 
   /**
-   * Updates the selected cast mode, and updates the header text fields
-   * according to the cast mode.
+   * Updates the shown cast mode, and updates the header text fields
+   * according to the cast mode. If |castMode| type is AUTO, then set
+   * |userHasSelectedCastMode_| to false.
    *
    * @param {!media_router.CastMode} castMode
    */
-  setSelectedCastMode_: function(castMode) {
-    if (castMode.type != this.selectedCastModeValue_) {
-      this.headerText = castMode.description;
-      this.headerTextTooltip = castMode.host;
-      this.selectedCastModeValue_ = castMode.type;
-      this.rebuildSinksToShow_();
-    }
+  setShownCastMode_: function(castMode) {
+    if (this.shownCastMode_ == castMode.type)
+      return;
+
+    this.shownCastModeValue_ = castMode.type;
+    this.headerText = castMode.description;
+    this.headerTextTooltip = castMode.host;
+    if (castMode.type == media_router.CastModeType.AUTO)
+      this.userHasSelectedCastMode_ = false;
   },
 
   /**
@@ -792,7 +837,13 @@
       // Allow one launch at a time.
       this.fire('create-route', {
         sinkId: sink.id,
-        selectedCastModeValue: this.selectedCastModeValue_
+        // If user selected a cast mode, then we will create a route using that
+        // cast mode. Otherwise, the UI is in "auto" cast mode and will use the
+        // preferred cast mode compatible with the sink. The preferred cast mode
+        // value is the least significant bit on the bitset.
+        selectedCastModeValue:
+            this.shownCastModeValue_ == media_router.CastModeType.AUTO ?
+                sink.castModes & -sink.castModes : this.shownCastModeValue_
       });
       this.currentLaunchingSinkId_ = sink.id;
     }
diff --git a/chrome/browser/resources/media_router/media_router.html b/chrome/browser/resources/media_router/media_router.html
index b2208038..f0f3ffa6 100644
--- a/chrome/browser/resources/media_router/media_router.html
+++ b/chrome/browser/resources/media_router/media_router.html
@@ -8,8 +8,8 @@
   <script src="chrome://resources/js/cr.js"></script>
   <script src="chrome://resources/js/load_time_data.js"></script>
   <script src="chrome://resources/js/util.js"></script>
-  <script src="chrome://media-router/media_router.js"></script>
   <script src="chrome://media-router/strings.js"></script>
+  <script src="chrome://media-router/media_router.js"></script>
 
   <link rel="stylesheet" href="chrome://resources/css/roboto.css">
   <link rel="stylesheet" href="media_router.css">
diff --git a/chrome/browser/resources/media_router/media_router_data.js b/chrome/browser/resources/media_router/media_router_data.js
index 4568566..794b171ef 100644
--- a/chrome/browser/resources/media_router/media_router_data.js
+++ b/chrome/browser/resources/media_router/media_router_data.js
@@ -8,13 +8,19 @@
   'use strict';
 
   /**
-   * This corresponds to the C++ MediaCastMode.
+   * This corresponds to the C++ MediaCastMode, with the exception of AUTO.
+   * See below for details. Note to support fast bitset operations, the values
+   * here are (1 << [corresponding value in MR]).
    * @enum {number}
    */
   var CastModeType = {
-    DEFAULT: 0,
-    TAB_MIRROR: 1,
-    DESKTOP_MIRROR: 2,
+    // Note: AUTO mode is only used to configure the sink list container to show
+    // all sinks. Individual sinks are configured with a specific cast mode
+    // (DEFAULT, TAB_MIRROR, DESKTOP_MIRROR).
+    AUTO: -1,
+    DEFAULT: 0x1,
+    TAB_MIRROR: 0x2,
+    DESKTOP_MIRROR: 0x4,
   };
 
   /**
@@ -55,7 +61,7 @@
   /**
    * @param {media_router.CastModeType} type The type of cast mode.
    * @param {string} description The description of the cast mode.
-   * @param {string} host The hostname of the site to cast.
+   * @param {?string} host The hostname of the site to cast.
    * @constructor
    * @struct
    */
@@ -66,10 +72,17 @@
     /** @type {string} */
     this.description = description;
 
-    /** @type {string} */
+    /** @type {?string} */
     this.host = host || null;
   };
 
+  /**
+   * Placeholder object for AUTO cast mode. See comment in CastModeType.
+   * @const {!media_router.CastMode}
+   */
+  var AUTO_CAST_MODE = new CastMode(CastModeType.AUTO,
+      loadTimeData.getString('autoCastMode'), null);
+
 
   /**
    * @param {string} id The ID of this issue.
@@ -153,7 +166,7 @@
    * @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.
+   * @param {number} castModes Bitset of cast modes compatible with the sink.
    * @constructor
    * @struct
    */
@@ -173,7 +186,7 @@
     /** @type {media_router.SinkStatus} */
     this.status = status;
 
-    /** @type {!Array<number>} */
+    /** @type {number} */
     this.castModes = castModes;
   };
 
@@ -193,6 +206,7 @@
   };
 
   return {
+    AUTO_CAST_MODE: AUTO_CAST_MODE,
     CastModeType: CastModeType,
     MediaRouterView: MediaRouterView,
     SinkIconType: SinkIconType,
diff --git a/chrome/browser/resources/media_router/media_router_ui_interface.js b/chrome/browser/resources/media_router/media_router_ui_interface.js
index 45bee33..cf21324 100644
--- a/chrome/browser/resources/media_router/media_router_ui_interface.js
+++ b/chrome/browser/resources/media_router/media_router_ui_interface.js
@@ -53,22 +53,18 @@
    * @param {deviceMissingUrl: string,
    *         sinks: !Array<!media_router.Sink>,
    *         routes: !Array<!media_router.Route>,
-   *         castModes: !Array<!media_router.CastMode>,
-   *         initialCastModeType: number} data
+   *         castModes: !Array<!media_router.CastMode>} data
    * Parameters in data:
    *   deviceMissingUrl - url to be opened on "Device missing?" clicked.
    *   sinks - list of sinks to be displayed.
    *   routes - list of routes that are associated with the sinks.
    *   castModes - list of available cast modes.
-   *   initialCastModeType - cast mode to show initially. Expected to be
-   *       included in |castModes|.
    */
   function setInitialData(data) {
     container.deviceMissingUrl = data['deviceMissingUrl'];
+    container.castModeList = data['castModes'];
     container.allSinks = data['sinks'];
     container.routeList = data['routes'];
-    container.initializeCastModes(data['castModes'],
-        data['initialCastModeType']);
   }
 
   /**
diff --git a/chrome/browser/resources/net_internals/import_view.html b/chrome/browser/resources/net_internals/import_view.html
index cae43304..452ec1d 100644
--- a/chrome/browser/resources/net_internals/import_view.html
+++ b/chrome/browser/resources/net_internals/import_view.html
@@ -56,7 +56,7 @@
       </td>
     </tr>
     <tr>
-      <th>OS type</th>
+      <th>OS info</th>
       <td jscontent="constants.clientInfo.os_type"></td>
     </tr>
     <tr>
diff --git a/chrome/browser/resources/settings/advanced_page/advanced_page.css b/chrome/browser/resources/settings/advanced_page/advanced_page.css
index 8c46a6f..1a33ff32 100644
--- a/chrome/browser/resources/settings/advanced_page/advanced_page.css
+++ b/chrome/browser/resources/settings/advanced_page/advanced_page.css
@@ -5,4 +5,5 @@
 :host {
   display: block;
   height: 100%;
+  width: 605px;
 }
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.css b/chrome/browser/resources/settings/basic_page/basic_page.css
index 8c46a6f..1a33ff32 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.css
+++ b/chrome/browser/resources/settings/basic_page/basic_page.css
@@ -5,4 +5,5 @@
 :host {
   display: block;
   height: 100%;
+  width: 605px;
 }
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html
index ca8e3d90..992dfc5b85 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.html
+++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -39,7 +39,7 @@
     </settings-section>
 
     <settings-section i18n-values="page-title:onStartup"
-        current-route="[[currentRoute]]" section="on-startup">
+        current-route="[[currentRoute]]" section="onStartup">
       <settings-on-startup-page prefs="{{prefs}}"
           current-route="{{currentRoute}}">
       </settings-on-startup-page>
diff --git a/chrome/browser/resources/settings/settings_page/settings_router.js b/chrome/browser/resources/settings/settings_page/settings_router.js
index 6caa660d..02e4771 100644
--- a/chrome/browser/resources/settings/settings_page/settings_router.js
+++ b/chrome/browser/resources/settings/settings_page/settings_router.js
@@ -98,13 +98,6 @@
       subpageTitles: ['customizeFonts'],
     },
     {
-      url: '/startup',
-      page: 'basic',
-      section: 'on-startup',
-      subpage: ['startup-urls'],
-      subpageTitles: ['onStartupSetPages'],
-    },
-    {
       url: '/searchEngines',
       page: 'basic',
       section: 'search',
diff --git a/chrome/browser/resources/settings/settings_page/settings_section.css b/chrome/browser/resources/settings/settings_page/settings_section.css
index 9c1ee5b9..91a81fc 100644
--- a/chrome/browser/resources/settings/settings_page/settings_section.css
+++ b/chrome/browser/resources/settings/settings_page/settings_section.css
@@ -31,7 +31,6 @@
 paper-material,
 #placeholder {
   margin-bottom: 16px;
-  width: 605px;
 }
 
 :host(.neon-animating) paper-material {
diff --git a/chrome/browser/resources/settings/signin_page/signin_page.html b/chrome/browser/resources/settings/signin_page/signin_page.html
index e74f5c4..5ae74c2 100644
--- a/chrome/browser/resources/settings/signin_page/signin_page.html
+++ b/chrome/browser/resources/settings/signin_page/signin_page.html
@@ -19,8 +19,10 @@
         <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. -->
+              <!-- TODO(tommycli): Investigate ChromeOS user pictures.
+                                   To be done by January 2015. -->
+              <img src="[[syncStatus.iconURL]]">
+              [[syncStatus.name]]
             </span>
             <span>
               <template is="dom-if" if="[[!syncStatus.signedIn]]">
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 35a330f..05547fb3 100644
--- a/chrome/browser/resources/settings/sync_page/sync_private_api.js
+++ b/chrome/browser/resources/settings/sync_page/sync_private_api.js
@@ -59,7 +59,9 @@
  *            childUser: (boolean|undefined),
  *            hasError: (boolean|undefined),
  *            hasUnrecoverableError: (boolean|undefined),
+ *            iconURL: (string|undefined),
  *            managed: (boolean|undefined),
+ *            name: (string|undefined),
  *            setupCompleted: (boolean|undefined),
  *            setupInProgress: (boolean|undefined),
  *            signedIn: (boolean|undefined),
diff --git a/chrome/browser/safe_browsing/two_phase_uploader.cc b/chrome/browser/safe_browsing/two_phase_uploader.cc
index aafecec..fca2c2a 100644
--- a/chrome/browser/safe_browsing/two_phase_uploader.cc
+++ b/chrome/browser/safe_browsing/two_phase_uploader.cc
@@ -4,7 +4,10 @@
 
 #include "chrome/browser/safe_browsing/two_phase_uploader.h"
 
-#include "base/basictypes.h"
+#include <stdint.h>
+
+#include <limits>
+
 #include "base/bind.h"
 #include "base/task_runner.h"
 #include "net/base/net_errors.h"
@@ -41,8 +44,8 @@
   // net::URLFetcherDelegate implementation:
   void OnURLFetchComplete(const net::URLFetcher* source) override;
   void OnURLFetchUploadProgress(const net::URLFetcher* source,
-                                int64 current,
-                                int64 total) override;
+                                int64_t current,
+                                int64_t total) override;
 
  private:
   void UploadMetadata();
@@ -143,13 +146,13 @@
       return;
     default:
       NOTREACHED();
-  };
+  }
 }
 
 void TwoPhaseUploaderImpl::OnURLFetchUploadProgress(
     const net::URLFetcher* source,
-    int64 current,
-    int64 total) {
+    int64_t current,
+    int64_t total) {
   DCHECK(CalledOnValidThread());
   DVLOG(3) << __FUNCTION__ << " " << source->GetURL().spec()
            << " " << current << "/" << total;
@@ -175,8 +178,9 @@
   url_fetcher_ =
       net::URLFetcher::Create(upload_url_, net::URLFetcher::PUT, this);
   url_fetcher_->SetRequestContext(url_request_context_getter_.get());
-  url_fetcher_->SetUploadFilePath(
-      kUploadContentType, file_path_, 0, kuint64max, file_task_runner_);
+  url_fetcher_->SetUploadFilePath(kUploadContentType, file_path_, 0,
+                                  std::numeric_limits<uint64_t>::max(),
+                                  file_task_runner_);
   url_fetcher_->Start();
 }
 
diff --git a/chrome/browser/safe_browsing/two_phase_uploader.h b/chrome/browser/safe_browsing/two_phase_uploader.h
index 1055529d..18d6b41b7 100644
--- a/chrome/browser/safe_browsing/two_phase_uploader.h
+++ b/chrome/browser/safe_browsing/two_phase_uploader.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/files/file_path.h"
 #include "base/memory/scoped_ptr.h"
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc
index f8ea9c1..a75cc22 100644
--- a/chrome/browser/search/instant_service.cc
+++ b/chrome/browser/search/instant_service.cc
@@ -331,6 +331,7 @@
     if (suggestion.has_click_url()) {
       item.click_url = GURL(suggestion.click_url());
     }
+    item.is_server_side_suggestion = true;
     new_suggestions_items.push_back(item);
   }
   suggestions_items_ = new_suggestions_items;
@@ -346,6 +347,7 @@
     InstantMostVisitedItem item;
     item.url = url.url;
     item.title = url.title;
+    item.is_server_side_suggestion = false;
     new_most_visited_items.push_back(item);
   }
 
diff --git a/chrome/browser/search/instant_service.h b/chrome/browser/search/instant_service.h
index 8892528..5d0b8094 100644
--- a/chrome/browser/search/instant_service.h
+++ b/chrome/browser/search/instant_service.h
@@ -107,6 +107,8 @@
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, ProcessIsolation);
   FRIEND_TEST_ALL_PREFIXES(InstantServiceEnabledTest,
                            SendsSearchURLsToRenderer);
+  FRIEND_TEST_ALL_PREFIXES(InstantServiceTest, GetSuggestionFromServiceSide);
+  FRIEND_TEST_ALL_PREFIXES(InstantServiceTest, GetSuggestionFromClientSide);
 
   // KeyedService:
   void Shutdown() override;
diff --git a/chrome/browser/search/instant_service_unittest.cc b/chrome/browser/search/instant_service_unittest.cc
index 4b5d0f7d..4b5f0f7 100644
--- a/chrome/browser/search/instant_service_unittest.cc
+++ b/chrome/browser/search/instant_service_unittest.cc
@@ -165,3 +165,25 @@
               OmniboxStartMarginChanged(new_start_margin)).Times(1);
   UpdateOmniboxStartMargin(new_start_margin);
 }
+
+TEST_F(InstantServiceTest, GetSuggestionFromServiceSide) {
+  auto profile = suggestions::SuggestionsProfile();
+  profile.add_suggestions();
+
+  instant_service_->OnSuggestionsAvailable(profile);
+
+  auto items = instant_service_->suggestions_items_;
+  ASSERT_EQ(1, (int)items.size());
+  ASSERT_TRUE(items[0].is_server_side_suggestion);
+}
+
+TEST_F(InstantServiceTest, GetSuggestionFromClientSide) {
+  history::MostVisitedURLList url_list;
+  url_list.push_back(history::MostVisitedURL());
+
+  instant_service_->OnMostVisitedItemsReceived(url_list);
+
+  auto items = instant_service_->most_visited_items_;
+  ASSERT_EQ(1, (int)items.size());
+  ASSERT_FALSE(items[0].is_server_side_suggestion);
+}
diff --git a/chrome/browser/search_engines/template_url_service_android.cc b/chrome/browser/search_engines/template_url_service_android.cc
index b157f89e..c86346e 100644
--- a/chrome/browser/search_engines/template_url_service_android.cc
+++ b/chrome/browser/search_engines/template_url_service_android.cc
@@ -122,9 +122,7 @@
       env,
       index,
       base::android::ConvertUTF16ToJavaString(
-          env, template_url->short_name()).obj(),
-      base::android::ConvertUTF16ToJavaString(
-          env, template_url->keyword()).obj());
+          env, template_url->short_name()).obj());
 }
 
 bool TemplateUrlServiceAndroid::IsPrepopulatedTemplate(TemplateURL* url) {
diff --git a/chrome/browser/sessions/restore_on_startup_policy_handler.cc b/chrome/browser/sessions/restore_on_startup_policy_handler.cc
index 4e9a2d4..57c435ae 100644
--- a/chrome/browser/sessions/restore_on_startup_policy_handler.cc
+++ b/chrome/browser/sessions/restore_on_startup_policy_handler.cc
@@ -32,45 +32,7 @@
     int restore_on_startup;
     if (!restore_on_startup_value->GetAsInteger(&restore_on_startup))
       return;
-
-    if (restore_on_startup == SessionStartupPref::kPrefValueHomePage)
-      ApplyPolicySettingsFromHomePage(policies, prefs);
-    else
-      prefs->SetInteger(prefs::kRestoreOnStartup, restore_on_startup);
-  }
-}
-
-void RestoreOnStartupPolicyHandler::ApplyPolicySettingsFromHomePage(
-    const PolicyMap& policies,
-    PrefValueMap* prefs) {
-  const base::Value* homepage_is_new_tab_page_value =
-      policies.GetValue(key::kHomepageIsNewTabPage);
-  if (!homepage_is_new_tab_page_value) {
-    // The policy is enforcing 'open the homepage on startup' but not
-    // enforcing what the homepage should be. Don't set any prefs.
-    return;
-  }
-
-  bool homepage_is_new_tab_page;
-  if (!homepage_is_new_tab_page_value->GetAsBoolean(&homepage_is_new_tab_page))
-    return;
-
-  if (homepage_is_new_tab_page) {
-    prefs->SetInteger(prefs::kRestoreOnStartup,
-                      SessionStartupPref::kPrefValueNewTab);
-  } else {
-    const base::Value* homepage_value =
-        policies.GetValue(key::kHomepageLocation);
-    if (!homepage_value || !homepage_value->IsType(base::Value::TYPE_STRING)) {
-      // The policy is enforcing 'open the homepage on startup' but not
-      // enforcing what the homepage should be. Don't set any prefs.
-      return;
-    }
-    scoped_ptr<base::ListValue> url_list(new base::ListValue());
-    url_list->Append(homepage_value->CreateDeepCopy());
-    prefs->SetInteger(prefs::kRestoreOnStartup,
-                      SessionStartupPref::kPrefValueURLs);
-    prefs->SetValue(prefs::kURLsToRestoreOnStartup, url_list.Pass());
+    prefs->SetInteger(prefs::kRestoreOnStartup, restore_on_startup);
   }
 }
 
@@ -86,7 +48,7 @@
     int restore_value;
     CHECK(restore_policy->GetAsInteger(&restore_value));  // Passed type check.
     switch (restore_value) {
-      case SessionStartupPref::kPrefValueHomePage:
+      case 0:  // Deprecated kPrefValueHomePage.
         errors->AddError(policy_name(), IDS_POLICY_VALUE_DEPRECATED);
         break;
       case SessionStartupPref::kPrefValueLast: {
diff --git a/chrome/browser/sessions/restore_on_startup_policy_handler.h b/chrome/browser/sessions/restore_on_startup_policy_handler.h
index 3fea8069..adde95b 100644
--- a/chrome/browser/sessions/restore_on_startup_policy_handler.h
+++ b/chrome/browser/sessions/restore_on_startup_policy_handler.h
@@ -27,9 +27,6 @@
                            PrefValueMap* prefs) override;
 
  private:
-  void ApplyPolicySettingsFromHomePage(const PolicyMap& policies,
-                                       PrefValueMap* prefs);
-
   DISALLOW_COPY_AND_ASSIGN(RestoreOnStartupPolicyHandler);
 };
 
diff --git a/chrome/browser/sessions/restore_on_startup_policy_handler_unittest.cc b/chrome/browser/sessions/restore_on_startup_policy_handler_unittest.cc
index 0c35d58..63e94c2 100644
--- a/chrome/browser/sessions/restore_on_startup_policy_handler_unittest.cc
+++ b/chrome/browser/sessions/restore_on_startup_policy_handler_unittest.cc
@@ -70,8 +70,7 @@
 
 TEST_F(RestoreOnStartupPolicyHandlerTest, CheckPolicySettings_UnknownValue) {
   // Specify an unknown value for the policy.
-  int impossible_value = SessionStartupPref::kPrefValueHomePage +
-                         SessionStartupPref::kPrefValueLast +
+  int impossible_value = SessionStartupPref::kPrefValueLast +
                          SessionStartupPref::kPrefValueURLs +
                          SessionStartupPref::kPrefValueNewTab;
   SetPolicyValue(key::kRestoreOnStartup,
@@ -89,7 +88,7 @@
   // Specify the HomePage value.
   SetPolicyValue(
       key::kRestoreOnStartup,
-      new base::FundamentalValue(SessionStartupPref::kPrefValueHomePage));
+      new base::FundamentalValue(0));  // kPrefValueHomePage, deprecated.
   // Checking should succeed but add an error to the error map.
   EXPECT_TRUE(CheckPolicySettings());
   EXPECT_EQ(1U, errors().size());
@@ -116,6 +115,18 @@
             errors().begin()->second);
 }
 
+TEST_F(RestoreOnStartupPolicyHandlerTest, ApplyPolicySettings_NotHomePage) {
+  // Specify anything except the HomePage value.
+  int not_home_page = 1;  // kPrefValueHomePage + 1, deprecated.
+  SetPolicyValue(key::kRestoreOnStartup,
+                 new base::FundamentalValue(not_home_page));
+  ApplyPolicySettings();
+  // The resulting prefs should have the value we specified.
+  int result;
+  EXPECT_TRUE(prefs().GetInteger(prefs::kRestoreOnStartup, &result));
+  EXPECT_EQ(not_home_page, result);
+}
+
 TEST_F(RestoreOnStartupPolicyHandlerTest,
        CheckPolicySettings_RestoreLastSession_ClearDataOnExit) {
   // Specify the Last value and the Clear-Data-On-Exit value.
@@ -178,116 +189,4 @@
   EXPECT_TRUE(prefs().begin() == prefs().end());
 }
 
-TEST_F(RestoreOnStartupPolicyHandlerTest, ApplyPolicySettings_NotHomePage) {
-  // Specify anything except the HomePage value.
-  int not_home_page = SessionStartupPref::kPrefValueHomePage + 1;
-  SetPolicyValue(key::kRestoreOnStartup,
-                 new base::FundamentalValue(not_home_page));
-  ApplyPolicySettings();
-  // The resulting prefs should have the value we specified.
-  int result;
-  EXPECT_TRUE(prefs().GetInteger(prefs::kRestoreOnStartup, &result));
-  EXPECT_EQ(not_home_page, result);
-}
-
-TEST_F(RestoreOnStartupPolicyHandlerTest,
-       ApplyPolicySettings_HomePage_NoHomePageValue) {
-  // Specify the HomePage value but no HomePageIsNewTabPage value.
-  SetPolicyValue(
-      key::kRestoreOnStartup,
-      new base::FundamentalValue(SessionStartupPref::kPrefValueHomePage));
-  ApplyPolicySettings();
-  // The resulting prefs should be empty.
-  EXPECT_TRUE(prefs().begin() == prefs().end());
-}
-
-TEST_F(RestoreOnStartupPolicyHandlerTest,
-       ApplyPolicySettings_HomePage_HomePageValueIsWrongType) {
-  // Specify the HomePage value and an integer for the home page value.
-  SetPolicyValue(
-      key::kRestoreOnStartup,
-      new base::FundamentalValue(SessionStartupPref::kPrefValueHomePage));
-  SetPolicyValue(
-      key::kHomepageIsNewTabPage,
-      new base::FundamentalValue(314159));
-  ApplyPolicySettings();
-  // The resulting prefs should be empty.
-  EXPECT_TRUE(prefs().begin() == prefs().end());
-}
-
-TEST_F(RestoreOnStartupPolicyHandlerTest,
-       ApplyPolicySettings_HomePage_HomePageIsNewTabPage) {
-  // Specify the HomePage value and the home page as the new tab page.
-  SetPolicyValue(
-      key::kRestoreOnStartup,
-      new base::FundamentalValue(SessionStartupPref::kPrefValueHomePage));
-  SetPolicyValue(
-      key::kHomepageIsNewTabPage,
-      new base::FundamentalValue(true));
-  ApplyPolicySettings();
-  // The resulting prefs should have the restore value as NTP.
-  int result;
-  EXPECT_TRUE(prefs().GetInteger(prefs::kRestoreOnStartup, &result));
-  int expected = SessionStartupPref::kPrefValueNewTab;
-  EXPECT_EQ(expected, result);
-}
-
-TEST_F(RestoreOnStartupPolicyHandlerTest,
-       ApplyPolicySettings_HomePage_HomePageIsNotNewTabPage_NotDefined) {
-  // Specify the HomePage value but don't specify the home page to use.
-  SetPolicyValue(
-      key::kRestoreOnStartup,
-      new base::FundamentalValue(SessionStartupPref::kPrefValueHomePage));
-  SetPolicyValue(
-      key::kHomepageIsNewTabPage,
-      new base::FundamentalValue(false));
-  ApplyPolicySettings();
-  // The resulting prefs should be empty.
-  EXPECT_TRUE(prefs().begin() == prefs().end());
-}
-
-TEST_F(RestoreOnStartupPolicyHandlerTest,
-       ApplyPolicySettings_HomePage_HomePageIsNotNewTabPage_WrongType) {
-  // Specify the HomePage value but specify a boolean as the home page.
-  SetPolicyValue(
-      key::kRestoreOnStartup,
-      new base::FundamentalValue(SessionStartupPref::kPrefValueHomePage));
-  SetPolicyValue(
-      key::kHomepageIsNewTabPage,
-      new base::FundamentalValue(false));
-  SetPolicyValue(
-      key::kHomepageLocation,
-      new base::FundamentalValue(false));
-  ApplyPolicySettings();
-  // The resulting prefs should be empty.
-  EXPECT_TRUE(prefs().begin() == prefs().end());
-}
-
-TEST_F(RestoreOnStartupPolicyHandlerTest,
-       ApplyPolicySettings_HomePage_HomePageIsNotNewTabPage) {
-  SetPolicyValue(
-      key::kRestoreOnStartup,
-      new base::FundamentalValue(SessionStartupPref::kPrefValueHomePage));
-  SetPolicyValue(key::kHomepageIsNewTabPage, new base::FundamentalValue(false));
-  SetPolicyValue(key::kHomepageLocation,
-                 new base::StringValue("http://foo.com"));
-  ApplyPolicySettings();
-
-  // The resulting prefs should have have URLs specified for startup.
-  int result;
-  EXPECT_TRUE(prefs().GetInteger(prefs::kRestoreOnStartup, &result));
-  int expected = SessionStartupPref::kPrefValueURLs;
-  EXPECT_EQ(expected, result);
-
-  // The resulting prefs should have the URL we specified as the home page.
-  base::Value* url_result;
-  EXPECT_TRUE(prefs().GetValue(prefs::kURLsToRestoreOnStartup, &url_result));
-  base::ListValue* url_list_result;
-  EXPECT_TRUE(url_result->GetAsList(&url_list_result));
-  EXPECT_EQ(1U, url_list_result->GetSize());
-  std::string expected_url;
-  EXPECT_TRUE(url_list_result->GetString(0, &expected_url));
-  EXPECT_EQ(std::string("http://foo.com"), expected_url);
-}
-
 }  // namespace policy
diff --git a/chrome/browser/signin/chrome_proximity_auth_client.cc b/chrome/browser/signin/chrome_proximity_auth_client.cc
index a3037fd..7ae7736 100644
--- a/chrome/browser/signin/chrome_proximity_auth_client.cc
+++ b/chrome/browser/signin/chrome_proximity_auth_client.cc
@@ -78,8 +78,9 @@
   }
 
   static_cast<EasyUnlockServiceSignin*>(easy_unlock_service)
-      ->WrapChallengeForUserAndDevice(user_id, remote_public_key,
-                                      channel_binding_data, callback);
+      ->WrapChallengeForUserAndDevice(AccountId::FromUserEmail(user_id),
+                                      remote_public_key, channel_binding_data,
+                                      callback);
 #else
   callback.Run(std::string());
 #endif
diff --git a/chrome/browser/signin/easy_unlock_auth_attempt.cc b/chrome/browser/signin/easy_unlock_auth_attempt.cc
index a47c3e2..fced561 100644
--- a/chrome/browser/signin/easy_unlock_auth_attempt.cc
+++ b/chrome/browser/signin/easy_unlock_auth_attempt.cc
@@ -49,7 +49,7 @@
 void DefaultAuthAttemptFinalizedHandler(
     EasyUnlockAuthAttempt::Type auth_attempt_type,
     bool success,
-    const std::string& user_id,
+    const AccountId& account_id,
     const std::string& key_secret,
     const std::string& key_label) {
   if (!proximity_auth::ScreenlockBridge::Get()->IsLocked())
@@ -59,7 +59,7 @@
     case EasyUnlockAuthAttempt::TYPE_UNLOCK:
       if (success) {
         proximity_auth::ScreenlockBridge::Get()->lock_handler()->Unlock(
-            user_id);
+            account_id);
       } else {
         proximity_auth::ScreenlockBridge::Get()->lock_handler()->EnableInput();
       }
@@ -68,13 +68,13 @@
       if (success) {
         proximity_auth::ScreenlockBridge::Get()
             ->lock_handler()
-            ->AttemptEasySignin(user_id, key_secret, key_label);
+            ->AttemptEasySignin(account_id, key_secret, key_label);
       } else {
         // Attempting signin with an empty secret is equivalent to canceling the
         // attempt.
         proximity_auth::ScreenlockBridge::Get()
             ->lock_handler()
-            ->AttemptEasySignin(user_id, std::string(), std::string());
+            ->AttemptEasySignin(account_id, std::string(), std::string());
       }
       return;
   }
@@ -84,12 +84,12 @@
 
 EasyUnlockAuthAttempt::EasyUnlockAuthAttempt(
     EasyUnlockAppManager* app_manager,
-    const std::string& user_id,
+    const AccountId& account_id,
     Type type,
     const FinalizedCallback& finalized_callback)
     : app_manager_(app_manager),
       state_(STATE_IDLE),
-      user_id_(user_id),
+      account_id_(account_id),
       type_(type),
       finalized_callback_(finalized_callback) {
   if (finalized_callback_.is_null())
@@ -98,7 +98,7 @@
 
 EasyUnlockAuthAttempt::~EasyUnlockAuthAttempt() {
   if (state_ == STATE_RUNNING)
-    Cancel(user_id_);
+    Cancel(account_id_);
 }
 
 bool EasyUnlockAuthAttempt::Start() {
@@ -109,10 +109,10 @@
 
   proximity_auth::ScreenlockBridge::LockHandler::AuthType auth_type =
       proximity_auth::ScreenlockBridge::Get()->lock_handler()->GetAuthType(
-          user_id_);
+          account_id_);
 
   if (auth_type != proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK) {
-    Cancel(user_id_);
+    Cancel(account_id_);
     return false;
   }
 
@@ -128,47 +128,47 @@
   if (!app_manager_->SendAuthAttemptEvent() &&
       !base::CommandLine::ForCurrentProcess()->HasSwitch(
           proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery)) {
-    Cancel(user_id_);
+    Cancel(account_id_);
     return false;
   }
 
   return true;
 }
 
-void EasyUnlockAuthAttempt::FinalizeUnlock(const std::string& user_id,
+void EasyUnlockAuthAttempt::FinalizeUnlock(const AccountId& account_id,
                                            bool success) {
-  if (state_ != STATE_RUNNING || user_id != user_id_)
+  if (state_ != STATE_RUNNING || account_id != account_id_)
     return;
 
   if (!proximity_auth::ScreenlockBridge::Get()->IsLocked())
     return;
 
   if (type_ != TYPE_UNLOCK) {
-    Cancel(user_id_);
+    Cancel(account_id_);
     return;
   }
 
-  finalized_callback_.Run(type_, success, user_id, std::string(),
+  finalized_callback_.Run(type_, success, account_id, std::string(),
                           std::string());
   state_ = STATE_DONE;
 }
 
-void EasyUnlockAuthAttempt::FinalizeSignin(const std::string& user_id,
+void EasyUnlockAuthAttempt::FinalizeSignin(const AccountId& account_id,
                                            const std::string& wrapped_secret,
                                            const std::string& raw_session_key) {
-  if (state_ != STATE_RUNNING || user_id != user_id_)
+  if (state_ != STATE_RUNNING || account_id != account_id_)
     return;
 
   if (!proximity_auth::ScreenlockBridge::Get()->IsLocked())
     return;
 
   if (type_ != TYPE_SIGNIN) {
-    Cancel(user_id_);
+    Cancel(account_id_);
     return;
   }
 
   if (wrapped_secret.empty()) {
-    Cancel(user_id_);
+    Cancel(account_id_);
     return;
   }
 
@@ -180,15 +180,15 @@
 #endif  // defined(OS_CHROMEOS)
 
   const bool kSuccess = true;
-  finalized_callback_.Run(type_, kSuccess, user_id, unwrapped_secret,
+  finalized_callback_.Run(type_, kSuccess, account_id, unwrapped_secret,
                           key_label);
   state_ = STATE_DONE;
 }
 
-void EasyUnlockAuthAttempt::Cancel(const std::string& user_id) {
+void EasyUnlockAuthAttempt::Cancel(const AccountId& account_id) {
   state_ = STATE_DONE;
 
   const bool kFailure = false;
-  finalized_callback_.Run(type_, kFailure, user_id, std::string(),
+  finalized_callback_.Run(type_, kFailure, account_id, std::string(),
                           std::string());
 }
diff --git a/chrome/browser/signin/easy_unlock_auth_attempt.h b/chrome/browser/signin/easy_unlock_auth_attempt.h
index 18bc9af..3cd683fc 100644
--- a/chrome/browser/signin/easy_unlock_auth_attempt.h
+++ b/chrome/browser/signin/easy_unlock_auth_attempt.h
@@ -9,6 +9,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "components/signin/core/account_id/account_id.h"
 
 class EasyUnlockAppManager;
 
@@ -28,18 +29,17 @@
   };
 
   // A callback to be invoked after the auth attempt is finalized. |success|
-  // indicates whether the attempt is successful or not. |user_id| is the
+  // indicates whether the attempt is successful or not. |account_id| is the
   // associated user. |key_secret| is the user secret for a sign-in attempt
   // and |key_label| is the label of the corresponding cryptohome key.
   typedef base::Callback<void(Type auth_attempt_type,
                               bool success,
-                              const std::string& user_id,
+                              const AccountId& account_id,
                               const std::string& key_secret,
-                              const std::string& key_label)>
-      FinalizedCallback;
+                              const std::string& key_label)> FinalizedCallback;
 
   EasyUnlockAuthAttempt(EasyUnlockAppManager* app_manager,
-                        const std::string& user_id,
+                        const AccountId& account_id,
                         Type type,
                         const FinalizedCallback& finalized_callback);
   ~EasyUnlockAuthAttempt();
@@ -51,14 +51,14 @@
   // Finalizes an unlock attempt. It unlocks the screen if |success| is true.
   // If |this| has TYPE_SIGNIN type, calling this method will cause signin
   // failure equivalent to cancelling the attempt.
-  void FinalizeUnlock(const std::string& user_id, bool success);
+  void FinalizeUnlock(const AccountId& account_id, bool success);
 
   // Finalizes signin attempt. It tries to log in using the secret derived from
   // |wrapped_secret| decrypted by |session_key|. If the decryption fails, it
   // fails the signin attempt.
   // If called on an object with TYPE_UNLOCK type, it will cause unlock failure
   // equivalent to cancelling the request.
-  void FinalizeSignin(const std::string& user_id,
+  void FinalizeSignin(const AccountId& account_id,
                       const std::string& wrapped_secret,
                       const std::string& session_key);
 
@@ -71,11 +71,11 @@
   };
 
   // Cancels the attempt.
-  void Cancel(const std::string& user_id);
+  void Cancel(const AccountId& account_id);
 
   EasyUnlockAppManager* app_manager_;
   State state_;
-  std::string user_id_;
+  const AccountId account_id_;
   Type type_;
 
   FinalizedCallback finalized_callback_;
diff --git a/chrome/browser/signin/easy_unlock_auth_attempt_unittest.cc b/chrome/browser/signin/easy_unlock_auth_attempt_unittest.cc
index a8b49fd2..0f4b6ff 100644
--- a/chrome/browser/signin/easy_unlock_auth_attempt_unittest.cc
+++ b/chrome/browser/signin/easy_unlock_auth_attempt_unittest.cc
@@ -113,18 +113,14 @@
     STATE_SIGNIN_DONE
   };
 
-  explicit TestLockHandler(const std::string& user_id)
-      : state_(STATE_NONE), auth_type_(USER_CLICK), user_id_(user_id) {}
+  explicit TestLockHandler(const AccountId& account_id)
+      : state_(STATE_NONE), auth_type_(USER_CLICK), account_id_(account_id) {}
 
   ~TestLockHandler() override {}
 
   void set_state(AuthState value) { state_ = value; }
   AuthState state() const { return state_; }
 
-  // Changes the user associated with the lock handler.
-  // Caller should make sure that |state_| is also appropriately updated.
-  void set_user_id(const std::string& value) { user_id_ = value; }
-
   // Sets the secret that is expected to be sent to |AttemptEasySignin|
   void set_expected_secret(const std::string& value) {
     expected_secret_ = value;
@@ -139,13 +135,13 @@
   }
 
   void ShowUserPodCustomIcon(
-      const std::string& user_email,
+      const AccountId& account_id,
       const proximity_auth::ScreenlockBridge::UserPodCustomIconOptions& icon)
       override {
     ADD_FAILURE() << "Should not be reached.";
   }
 
-  void HideUserPodCustomIcon(const std::string& user_email) override {
+  void HideUserPodCustomIcon(const AccountId& account_id) override {
     ADD_FAILURE() << "Should not be reached.";
   }
 
@@ -154,13 +150,13 @@
     state_ = STATE_UNLOCK_CANCELED;
   }
 
-  void SetAuthType(const std::string& user_email,
+  void SetAuthType(const AccountId& account_id,
                    AuthType auth_type,
                    const base::string16& auth_value) override {
     ADD_FAILURE() << "Should not be reached.";
   }
 
-  AuthType GetAuthType(const std::string& user_email) const override {
+  AuthType GetAuthType(const AccountId& account_id) const override {
     return auth_type_;
   }
 
@@ -169,17 +165,21 @@
     return LOCK_SCREEN;
   }
 
-  void Unlock(const std::string& user_email) override {
-    ASSERT_EQ(user_id_, user_email);
+  void Unlock(const AccountId& account_id) override {
+    ASSERT_TRUE(account_id_ == account_id)
+        << "account_id_=" << account_id_.Serialize()
+        << " != " << account_id.Serialize();
     ASSERT_EQ(STATE_ATTEMPTING_UNLOCK, state_);
     state_ = STATE_UNLOCK_DONE;
   }
 
-  void AttemptEasySignin(const std::string& user_email,
+  void AttemptEasySignin(const AccountId& account_id,
                          const std::string& secret,
                          const std::string& key_label) override {
 #if defined(OS_CHROMEOS)
-    ASSERT_EQ(user_id_, user_email);
+    ASSERT_TRUE(account_id_ == account_id)
+        << "account_id_=" << account_id_.Serialize()
+        << " != " << account_id.Serialize();
 
     ASSERT_EQ(STATE_ATTEMPTING_SIGNIN, state_);
     if (secret.empty()) {
@@ -197,7 +197,7 @@
  private:
   AuthState state_;
   AuthType auth_type_;
-  std::string user_id_;
+  const AccountId account_id_;
   std::string expected_secret_;
 
   DISALLOW_COPY_AND_ASSIGN(TestLockHandler);
@@ -210,9 +210,10 @@
 
   void SetUp() override {
     app_manager_.reset(new FakeAppManager());
-    auth_attempt_.reset(new EasyUnlockAuthAttempt(
-        app_manager_.get(), kTestUser1, EasyUnlockAuthAttempt::TYPE_UNLOCK,
-        EasyUnlockAuthAttempt::FinalizedCallback()));
+    auth_attempt_.reset(
+        new EasyUnlockAuthAttempt(app_manager_.get(), test_account_id1_,
+                                  EasyUnlockAuthAttempt::TYPE_UNLOCK,
+                                  EasyUnlockAuthAttempt::FinalizedCallback()));
   }
 
   void TearDown() override {
@@ -222,7 +223,7 @@
 
  protected:
   void InitScreenLock() {
-    lock_handler_.reset(new TestLockHandler(kTestUser1));
+    lock_handler_.reset(new TestLockHandler(test_account_id1_));
     lock_handler_->set_state(TestLockHandler::STATE_ATTEMPTING_UNLOCK);
     proximity_auth::ScreenlockBridge::Get()->SetLockHandler(
         lock_handler_.get());
@@ -232,6 +233,9 @@
   scoped_ptr<FakeAppManager> app_manager_;
   scoped_ptr<TestLockHandler> lock_handler_;
 
+  const AccountId test_account_id1_ = AccountId::FromUserEmail(kTestUser1);
+  const AccountId test_account_id2_ = AccountId::FromUserEmail(kTestUser2);
+
  private:
   DISALLOW_COPY_AND_ASSIGN(EasyUnlockAuthAttemptUnlockTest);
 };
@@ -296,7 +300,7 @@
   ASSERT_EQ(1u, app_manager_->auth_attempt_count());
   EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
 
-  auth_attempt_->FinalizeUnlock(kTestUser1, false);
+  auth_attempt_->FinalizeUnlock(test_account_id1_, false);
 
   EXPECT_EQ(TestLockHandler::STATE_UNLOCK_CANCELED, lock_handler_->state());
 }
@@ -312,7 +316,7 @@
   EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
 
   // Wrapped secret and key should be irrelevant in this case.
-  auth_attempt_->FinalizeSignin(kTestUser1, GetWrappedSecret(),
+  auth_attempt_->FinalizeSignin(test_account_id1_, GetWrappedSecret(),
                                 GetSessionKey());
 
   EXPECT_EQ(TestLockHandler::STATE_UNLOCK_CANCELED, lock_handler_->state());
@@ -328,7 +332,7 @@
   ASSERT_EQ(1u, app_manager_->auth_attempt_count());
   EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
 
-  auth_attempt_->FinalizeUnlock(kTestUser1, true);
+  auth_attempt_->FinalizeUnlock(test_account_id1_, true);
 
   ASSERT_EQ(TestLockHandler::STATE_UNLOCK_DONE, lock_handler_->state());
 }
@@ -343,7 +347,7 @@
   ASSERT_EQ(1u, app_manager_->auth_attempt_count());
   EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
 
-  auth_attempt_->FinalizeUnlock(kTestUser2, true);
+  auth_attempt_->FinalizeUnlock(test_account_id2_, true);
 
   // If FinalizeUnlock is called for an incorrect user, it should be ignored
   // rather than cancelling the authentication.
@@ -351,7 +355,7 @@
 
   // When FinalizeUnlock is called for the correct user, it should work as
   // expected.
-  auth_attempt_->FinalizeUnlock(kTestUser1, true);
+  auth_attempt_->FinalizeUnlock(test_account_id1_, true);
 
   ASSERT_EQ(TestLockHandler::STATE_UNLOCK_DONE, lock_handler_->state());
 }
@@ -364,9 +368,10 @@
 
   void SetUp() override {
     app_manager_.reset(new FakeAppManager());
-    auth_attempt_.reset(new EasyUnlockAuthAttempt(
-        app_manager_.get(), kTestUser1, EasyUnlockAuthAttempt::TYPE_SIGNIN,
-        EasyUnlockAuthAttempt::FinalizedCallback()));
+    auth_attempt_.reset(
+        new EasyUnlockAuthAttempt(app_manager_.get(), test_account_id1_,
+                                  EasyUnlockAuthAttempt::TYPE_SIGNIN,
+                                  EasyUnlockAuthAttempt::FinalizedCallback()));
   }
 
   void TearDown() override {
@@ -376,7 +381,7 @@
 
  protected:
   void InitScreenLock() {
-    lock_handler_.reset(new TestLockHandler(kTestUser1));
+    lock_handler_.reset(new TestLockHandler(test_account_id1_));
     lock_handler_->set_state(TestLockHandler::STATE_ATTEMPTING_SIGNIN);
     proximity_auth::ScreenlockBridge::Get()->SetLockHandler(
         lock_handler_.get());
@@ -386,6 +391,9 @@
   scoped_ptr<FakeAppManager> app_manager_;
   scoped_ptr<TestLockHandler> lock_handler_;
 
+  const AccountId test_account_id1_ = AccountId::FromUserEmail(kTestUser1);
+  const AccountId test_account_id2_ = AccountId::FromUserEmail(kTestUser2);
+
  private:
   DISALLOW_COPY_AND_ASSIGN(EasyUnlockAuthAttemptSigninTest);
 };
@@ -450,7 +458,7 @@
   ASSERT_EQ(1u, app_manager_->auth_attempt_count());
   EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
 
-  auth_attempt_->FinalizeSignin(kTestUser1, "", GetSessionKey());
+  auth_attempt_->FinalizeSignin(test_account_id1_, "", GetSessionKey());
 
   EXPECT_EQ(TestLockHandler::STATE_SIGNIN_CANCELED, lock_handler_->state());
 }
@@ -465,7 +473,7 @@
   ASSERT_EQ(1u, app_manager_->auth_attempt_count());
   EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
 
-  auth_attempt_->FinalizeSignin(kTestUser1, GetWrappedSecret(), "");
+  auth_attempt_->FinalizeSignin(test_account_id1_, GetWrappedSecret(), "");
 
   EXPECT_EQ(TestLockHandler::STATE_SIGNIN_CANCELED, lock_handler_->state());
 }
@@ -481,7 +489,7 @@
   EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
 
   lock_handler_->set_expected_secret(GetSecret());
-  auth_attempt_->FinalizeSignin(kTestUser1, GetWrappedSecret(),
+  auth_attempt_->FinalizeSignin(test_account_id1_, GetWrappedSecret(),
                                 GetSessionKey());
 
   EXPECT_EQ(TestLockHandler::STATE_SIGNIN_DONE, lock_handler_->state());
@@ -497,7 +505,8 @@
   ASSERT_EQ(1u, app_manager_->auth_attempt_count());
   EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
 
-  auth_attempt_->FinalizeSignin(kTestUser1, "wrong_secret", GetSessionKey());
+  auth_attempt_->FinalizeSignin(test_account_id1_, "wrong_secret",
+                                GetSessionKey());
 
   EXPECT_EQ(TestLockHandler::STATE_SIGNIN_CANCELED, lock_handler_->state());
 }
@@ -512,7 +521,8 @@
   ASSERT_EQ(1u, app_manager_->auth_attempt_count());
   EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
 
-  auth_attempt_->FinalizeSignin(kTestUser1, GetWrappedSecret(), "invalid_key");
+  auth_attempt_->FinalizeSignin(test_account_id1_, GetWrappedSecret(),
+                                "invalid_key");
 
   EXPECT_EQ(TestLockHandler::STATE_SIGNIN_CANCELED, lock_handler_->state());
 }
@@ -527,7 +537,7 @@
   ASSERT_EQ(1u, app_manager_->auth_attempt_count());
   EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
 
-  auth_attempt_->FinalizeUnlock(kTestUser1, true);
+  auth_attempt_->FinalizeUnlock(test_account_id1_, true);
 
   EXPECT_EQ(TestLockHandler::STATE_SIGNIN_CANCELED, lock_handler_->state());
 }
@@ -544,12 +554,12 @@
 
   lock_handler_->set_expected_secret(GetSecret());
 
-  auth_attempt_->FinalizeSignin(kTestUser2, GetWrappedSecret(),
+  auth_attempt_->FinalizeSignin(test_account_id2_, GetWrappedSecret(),
                                 GetSessionKey());
 
   EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
 
-  auth_attempt_->FinalizeSignin(kTestUser1, GetWrappedSecret(),
+  auth_attempt_->FinalizeSignin(test_account_id1_, GetWrappedSecret(),
                                 GetSessionKey());
 
   EXPECT_EQ(TestLockHandler::STATE_SIGNIN_DONE, lock_handler_->state());
diff --git a/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc b/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc
index e551c527..79f51b5 100644
--- a/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc
+++ b/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc
@@ -103,16 +103,13 @@
 }  // namespace
 
 EasyUnlockScreenlockStateHandler::EasyUnlockScreenlockStateHandler(
-    const std::string& user_email,
+    const AccountId& account_id,
     HardlockState initial_hardlock_state,
     proximity_auth::ScreenlockBridge* screenlock_bridge)
     : state_(ScreenlockState::INACTIVE),
-      user_email_(user_email),
+      account_id_(account_id),
       screenlock_bridge_(screenlock_bridge),
-      hardlock_state_(initial_hardlock_state),
-      hardlock_ui_shown_(false),
-      is_trial_run_(false),
-      did_see_locked_phone_(false) {
+      hardlock_state_(initial_hardlock_state) {
   DCHECK(screenlock_bridge_);
   screenlock_bridge_->AddObserver(this);
 }
@@ -147,7 +144,7 @@
     return;
 
   // Do nothing when auth type is online.
-  if (screenlock_bridge_->lock_handler()->GetAuthType(user_email_) ==
+  if (screenlock_bridge_->lock_handler()->GetAuthType(account_id_) ==
       proximity_auth::ScreenlockBridge::LockHandler::ONLINE_SIGN_IN) {
     return;
   }
@@ -167,7 +164,7 @@
       GetIconForState(state_);
 
   if (icon == proximity_auth::ScreenlockBridge::USER_POD_CUSTOM_ICON_NONE) {
-    screenlock_bridge_->lock_handler()->HideUserPodCustomIcon(user_email_);
+    screenlock_bridge_->lock_handler()->HideUserPodCustomIcon(account_id_);
     return;
   }
 
@@ -188,7 +185,7 @@
         l10n_util::GetStringUTF16(IDS_SMART_LOCK_SPINNER_ACCESSIBILITY_LABEL));
   }
 
-  screenlock_bridge_->lock_handler()->ShowUserPodCustomIcon(user_email_,
+  screenlock_bridge_->lock_handler()->ShowUserPodCustomIcon(account_id_,
                                                             icon_options);
 }
 
@@ -251,8 +248,7 @@
 }
 
 void EasyUnlockScreenlockStateHandler::OnFocusedUserChanged(
-    const std::string& user_id) {
-}
+    const AccountId& account_id) {}
 
 void EasyUnlockScreenlockStateHandler::RefreshScreenlockState() {
   ScreenlockState last_state = state_;
@@ -270,7 +266,7 @@
   // Do not override online signin.
   const proximity_auth::ScreenlockBridge::LockHandler::AuthType
       existing_auth_type =
-          screenlock_bridge_->lock_handler()->GetAuthType(user_email_);
+          screenlock_bridge_->lock_handler()->GetAuthType(account_id_);
   if (existing_auth_type ==
       proximity_auth::ScreenlockBridge::LockHandler::ONLINE_SIGN_IN)
     return;
@@ -278,13 +274,13 @@
   if (existing_auth_type !=
       proximity_auth::ScreenlockBridge::LockHandler::OFFLINE_PASSWORD) {
     screenlock_bridge_->lock_handler()->SetAuthType(
-        user_email_,
+        account_id_,
         proximity_auth::ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
         base::string16());
   }
 
   if (hardlock_state_ == NO_PAIRING) {
-    screenlock_bridge_->lock_handler()->HideUserPodCustomIcon(user_email_);
+    screenlock_bridge_->lock_handler()->HideUserPodCustomIcon(account_id_);
     hardlock_ui_shown_ = false;
     return;
   }
@@ -325,7 +321,7 @@
   }
   icon_options.SetTooltip(tooltip, true /* autoshow */);
 
-  screenlock_bridge_->lock_handler()->ShowUserPodCustomIcon(user_email_,
+  screenlock_bridge_->lock_handler()->ShowUserPodCustomIcon(account_id_,
                                                             icon_options);
   hardlock_ui_shown_ = true;
 }
@@ -376,7 +372,7 @@
   // Do not override online signin.
   const proximity_auth::ScreenlockBridge::LockHandler::AuthType
       existing_auth_type =
-          screenlock_bridge_->lock_handler()->GetAuthType(user_email_);
+          screenlock_bridge_->lock_handler()->GetAuthType(account_id_);
   DCHECK_NE(proximity_auth::ScreenlockBridge::LockHandler::ONLINE_SIGN_IN,
             existing_auth_type);
 
@@ -384,7 +380,7 @@
     if (existing_auth_type !=
         proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK) {
       screenlock_bridge_->lock_handler()->SetAuthType(
-          user_email_,
+          account_id_,
           proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK,
           l10n_util::GetStringUTF16(
               IDS_EASY_UNLOCK_SCREENLOCK_USER_POD_AUTH_VALUE));
@@ -392,7 +388,7 @@
   } else if (existing_auth_type !=
              proximity_auth::ScreenlockBridge::LockHandler::OFFLINE_PASSWORD) {
     screenlock_bridge_->lock_handler()->SetAuthType(
-        user_email_,
+        account_id_,
         proximity_auth::ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
         base::string16());
   }
diff --git a/chrome/browser/signin/easy_unlock_screenlock_state_handler.h b/chrome/browser/signin/easy_unlock_screenlock_state_handler.h
index c47dac80..88e6a3d7 100644
--- a/chrome/browser/signin/easy_unlock_screenlock_state_handler.h
+++ b/chrome/browser/signin/easy_unlock_screenlock_state_handler.h
@@ -10,6 +10,7 @@
 #include "base/strings/string16.h"
 #include "components/proximity_auth/screenlock_bridge.h"
 #include "components/proximity_auth/screenlock_state.h"
+#include "components/signin/core/account_id/account_id.h"
 
 class PrefService;
 
@@ -30,13 +31,13 @@
                                // on a new Chromebook.
   };
 
-  // |user_email|: The email for the user associated with the profile to which
-  //     this class is attached.
+  // |account_id|: The account id of the user associated with the profile to
+  //     which this class is attached.
   // |initial_hardlock_state|: The initial hardlock state.
   // |screenlock_bridge|: The screenlock bridge used to update the screen lock
   //     state.
   EasyUnlockScreenlockStateHandler(
-      const std::string& user_email,
+      const AccountId& account_id,
       HardlockState initial_hardlock_state,
       proximity_auth::ScreenlockBridge* screenlock_bridge);
   ~EasyUnlockScreenlockStateHandler() override;
@@ -75,7 +76,7 @@
   void OnScreenDidUnlock(
       proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type)
       override;
-  void OnFocusedUserChanged(const std::string& user_id) override;
+  void OnFocusedUserChanged(const AccountId& account_id) override;
 
   // Forces refresh of the Easy Unlock screenlock UI.
   void RefreshScreenlockState();
@@ -94,20 +95,20 @@
   void UpdateScreenlockAuthType();
 
   proximity_auth::ScreenlockState state_;
-  std::string user_email_;
+  const AccountId account_id_;
   proximity_auth::ScreenlockBridge* screenlock_bridge_;
 
   // State of hardlock.
   HardlockState hardlock_state_;
-  bool hardlock_ui_shown_;
+  bool hardlock_ui_shown_ = false;
 
   // Whether this is the trial Easy Unlock run. If this is the case, a
   // tutorial message should be shown and hard-locking be disabled. The trial
   // run should be set if the screen was locked by the Easy Unlock setup app.
-  bool is_trial_run_;
+  bool is_trial_run_ = false;
 
   // Whether the user's phone was ever locked while on the current lock screen.
-  bool did_see_locked_phone_;
+  bool did_see_locked_phone_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(EasyUnlockScreenlockStateHandler);
 };
diff --git a/chrome/browser/signin/easy_unlock_screenlock_state_handler_unittest.cc b/chrome/browser/signin/easy_unlock_screenlock_state_handler_unittest.cc
index 0e1c7e0..69aec94 100644
--- a/chrome/browser/signin/easy_unlock_screenlock_state_handler_unittest.cc
+++ b/chrome/browser/signin/easy_unlock_screenlock_state_handler_unittest.cc
@@ -46,11 +46,10 @@
 // Fake lock handler to be used in these tests.
 class TestLockHandler : public proximity_auth::ScreenlockBridge::LockHandler {
  public:
-  explicit TestLockHandler(const std::string& user_email)
-      : user_email_(user_email),
+  explicit TestLockHandler(const AccountId& account_id)
+      : account_id_(account_id),
         show_icon_count_(0u),
-        auth_type_(OFFLINE_PASSWORD) {
-  }
+        auth_type_(OFFLINE_PASSWORD) {}
   ~TestLockHandler() override {}
 
   // proximity_auth::ScreenlockBridge::LockHandler implementation:
@@ -59,17 +58,21 @@
   }
 
   void ShowUserPodCustomIcon(
-      const std::string& user_email,
+      const AccountId& account_id,
       const proximity_auth::ScreenlockBridge::UserPodCustomIconOptions& icon)
       override {
-    ASSERT_EQ(user_email_, user_email);
+    ASSERT_TRUE(account_id_ == account_id)
+        << "account_id_=" << account_id_.Serialize()
+        << " != account_id=" << account_id.Serialize();
     ++show_icon_count_;
     last_custom_icon_ = icon.ToDictionaryValue().Pass();
     ValidateCustomIcon();
   }
 
-  void HideUserPodCustomIcon(const std::string& user_email) override {
-    ASSERT_EQ(user_email_, user_email);
+  void HideUserPodCustomIcon(const AccountId& account_id) override {
+    ASSERT_TRUE(account_id_ == account_id)
+        << "account_id_=" << account_id_.Serialize()
+        << " != account_id=" << account_id.Serialize();
     last_custom_icon_.reset();
   }
 
@@ -77,10 +80,12 @@
     ASSERT_FALSE(true) << "Should not be reached.";
   }
 
-  void SetAuthType(const std::string& user_email,
+  void SetAuthType(const AccountId& account_id,
                    AuthType auth_type,
                    const base::string16& auth_value) override {
-    ASSERT_EQ(user_email_, user_email);
+    ASSERT_TRUE(account_id_ == account_id)
+        << "account_id_=" << account_id_.Serialize()
+        << " != account_id=" << account_id.Serialize();
     // Generally, this is allowed, but EasyUnlockScreenlockStateHandler should
     // avoid resetting the same auth type.
     EXPECT_NE(auth_type_, auth_type);
@@ -89,8 +94,10 @@
     auth_value_ = auth_value;
   }
 
-  AuthType GetAuthType(const std::string& user_email) const override {
-    EXPECT_EQ(user_email_, user_email);
+  AuthType GetAuthType(const AccountId& account_id) const override {
+    EXPECT_TRUE(account_id_ == account_id)
+        << "account_id_=" << account_id_.Serialize()
+        << " != account_id=" << account_id.Serialize();
     return auth_type_;
   }
 
@@ -98,11 +105,11 @@
     return LOCK_SCREEN;
   }
 
-  void Unlock(const std::string& user_email) override {
+  void Unlock(const AccountId& account_id) override {
     ASSERT_FALSE(true) << "Should not be reached.";
   }
 
-  void AttemptEasySignin(const std::string& user_email,
+  void AttemptEasySignin(const AccountId& account_id,
                          const std::string& secret,
                          const std::string& key_label) override {
     ASSERT_FALSE(true) << "Should not be reached.";
@@ -189,9 +196,9 @@
     }
   }
 
-  // The fake user email used in test. All methods called on |this| should be
+  // The fake account id used in test. All methods called on |this| should be
   // associated with this user.
-  const std::string user_email_;
+  const AccountId account_id_;
 
   // The last icon set using |SetUserPodCustomIcon|. Call to
   // |HideUserPodcustomIcon| resets it.
@@ -207,20 +214,19 @@
 
 class EasyUnlockScreenlockStateHandlerTest : public testing::Test {
  public:
-  EasyUnlockScreenlockStateHandlerTest() : user_email_("test_user@gmail.com") {}
+  EasyUnlockScreenlockStateHandlerTest() {}
   ~EasyUnlockScreenlockStateHandlerTest() override {}
 
   void SetUp() override {
     // Create and inject fake lock handler to the screenlock bridge.
-    lock_handler_.reset(new TestLockHandler(user_email_));
+    lock_handler_.reset(new TestLockHandler(account_id_));
     proximity_auth::ScreenlockBridge* screenlock_bridge =
         proximity_auth::ScreenlockBridge::Get();
     screenlock_bridge->SetLockHandler(lock_handler_.get());
 
     // Create the screenlock state handler object that will be tested.
     state_handler_.reset(new EasyUnlockScreenlockStateHandler(
-        user_email_,
-        EasyUnlockScreenlockStateHandler::NO_HARDLOCK,
+        account_id_, EasyUnlockScreenlockStateHandler::NO_HARDLOCK,
         screenlock_bridge));
   }
 
@@ -235,7 +241,7 @@
   scoped_ptr<EasyUnlockScreenlockStateHandler> state_handler_;
 
   // The user associated with |state_handler_|.
-  const std::string user_email_;
+  const AccountId account_id_ = AccountId::FromUserEmail("test_user@gmail.com");
 
   // Faked lock handler given to proximity_auth::ScreenlockBridge during the
   // test. Abstracts the screen lock UI.
@@ -248,7 +254,7 @@
 
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
 
   ASSERT_TRUE(lock_handler_->HasCustomIcon());
   EXPECT_EQ(kUnlockedIconId, lock_handler_->GetCustomIconId());
@@ -266,7 +272,7 @@
 
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
 
   ASSERT_TRUE(lock_handler_->HasCustomIcon());
   EXPECT_EQ(kUnlockedIconId, lock_handler_->GetCustomIconId());
@@ -289,7 +295,7 @@
 
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
 
   ASSERT_TRUE(lock_handler_->HasCustomIcon());
   EXPECT_EQ(kSpinnerIconId, lock_handler_->GetCustomIconId());
@@ -306,14 +312,14 @@
 
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
 
   state_handler_->SetHardlockState(
       EasyUnlockScreenlockStateHandler::USER_HARDLOCK);
 
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
 
   ASSERT_TRUE(lock_handler_->HasCustomIcon());
   EXPECT_EQ(kHardlockedIconId, lock_handler_->GetCustomIconId());
@@ -333,14 +339,14 @@
 
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
 
   state_handler_->SetHardlockState(
       EasyUnlockScreenlockStateHandler::NO_PAIRING);
 
   EXPECT_FALSE(lock_handler_->HasCustomIcon());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
 }
 
 TEST_F(EasyUnlockScreenlockStateHandlerTest, StatesWithLockedIcon) {
@@ -359,7 +365,7 @@
 
     EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
     EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
-              lock_handler_->GetAuthType(user_email_));
+              lock_handler_->GetAuthType(account_id_));
 
     ASSERT_TRUE(lock_handler_->HasCustomIcon());
     EXPECT_EQ(kLockedIconId, lock_handler_->GetCustomIconId());
@@ -377,7 +383,7 @@
 
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
 
   ASSERT_TRUE(lock_handler_->HasCustomIcon());
   ASSERT_FALSE(lock_handler_->IsCustomIconTooltipAutoshown());
@@ -386,7 +392,7 @@
 
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
 
   ASSERT_TRUE(lock_handler_->HasCustomIcon());
   ASSERT_TRUE(lock_handler_->IsCustomIconTooltipAutoshown());
@@ -398,7 +404,7 @@
 
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
 
   ASSERT_TRUE(lock_handler_->HasCustomIcon());
 
@@ -406,7 +412,7 @@
 
   EXPECT_EQ(0u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
 
   ASSERT_FALSE(lock_handler_->HasCustomIcon());
 }
@@ -416,17 +422,17 @@
 
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
   ASSERT_TRUE(lock_handler_->HasCustomIcon());
 
   proximity_auth::ScreenlockBridge::Get()->SetLockHandler(NULL);
-  lock_handler_.reset(new TestLockHandler(user_email_));
+  lock_handler_.reset(new TestLockHandler(account_id_));
   EXPECT_EQ(0u, lock_handler_->GetAndResetShowIconCount());
   proximity_auth::ScreenlockBridge::Get()->SetLockHandler(lock_handler_.get());
 
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
   ASSERT_TRUE(lock_handler_->HasCustomIcon());
 }
 
@@ -435,11 +441,11 @@
 
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
   ASSERT_TRUE(lock_handler_->HasCustomIcon());
 
   proximity_auth::ScreenlockBridge::Get()->SetLockHandler(NULL);
-  lock_handler_.reset(new TestLockHandler(user_email_));
+  lock_handler_.reset(new TestLockHandler(account_id_));
   EXPECT_EQ(0u, lock_handler_->GetAndResetShowIconCount());
 
   state_handler_->ChangeState(ScreenlockState::BLUETOOTH_CONNECTING);
@@ -448,7 +454,7 @@
 
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
   ASSERT_TRUE(lock_handler_->HasCustomIcon());
   EXPECT_EQ(kSpinnerIconId, lock_handler_->GetCustomIconId());
 }
@@ -476,7 +482,7 @@
   }
 
   proximity_auth::ScreenlockBridge::Get()->SetLockHandler(NULL);
-  lock_handler_.reset(new TestLockHandler(user_email_));
+  lock_handler_.reset(new TestLockHandler(account_id_));
   proximity_auth::ScreenlockBridge::Get()->SetLockHandler(lock_handler_.get());
 
   for (size_t i = 0; i < states.size(); ++i) {
@@ -589,14 +595,14 @@
 
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
 
   state_handler_->SetHardlockState(
       EasyUnlockScreenlockStateHandler::USER_HARDLOCK);
 
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
   ASSERT_TRUE(lock_handler_->HasCustomIcon());
   EXPECT_EQ(kHardlockedIconId, lock_handler_->GetCustomIconId());
 
@@ -608,7 +614,7 @@
   ASSERT_TRUE(lock_handler_->HasCustomIcon());
   EXPECT_EQ(0u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
 }
 
 TEST_F(EasyUnlockScreenlockStateHandlerTest,
@@ -623,7 +629,7 @@
       EasyUnlockScreenlockStateHandler::NO_HARDLOCK);
 
   proximity_auth::ScreenlockBridge::Get()->SetLockHandler(NULL);
-  lock_handler_.reset(new TestLockHandler(user_email_));
+  lock_handler_.reset(new TestLockHandler(account_id_));
   EXPECT_EQ(0u, lock_handler_->GetAndResetShowIconCount());
   proximity_auth::ScreenlockBridge::Get()->SetLockHandler(lock_handler_.get());
 
@@ -633,21 +639,21 @@
   EXPECT_TRUE(lock_handler_->HasCustomIcon());
 
   proximity_auth::ScreenlockBridge::Get()->SetLockHandler(NULL);
-  lock_handler_.reset(new TestLockHandler(user_email_));
+  lock_handler_.reset(new TestLockHandler(account_id_));
   EXPECT_EQ(0u, lock_handler_->GetAndResetShowIconCount());
   proximity_auth::ScreenlockBridge::Get()->SetLockHandler(lock_handler_.get());
 
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_TRUE(lock_handler_->HasCustomIcon());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
   EXPECT_EQ(kLockedIconId, lock_handler_->GetCustomIconId());
 
   state_handler_->ChangeState(ScreenlockState::AUTHENTICATED);
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_TRUE(lock_handler_->HasCustomIcon());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
   EXPECT_TRUE(lock_handler_->CustomIconHardlocksOnClick());
 }
 
@@ -658,13 +664,13 @@
   EXPECT_EQ(2u, lock_handler_->GetAndResetShowIconCount());
 
   proximity_auth::ScreenlockBridge::Get()->SetLockHandler(NULL);
-  lock_handler_.reset(new TestLockHandler(user_email_));
+  lock_handler_.reset(new TestLockHandler(account_id_));
   EXPECT_EQ(0u, lock_handler_->GetAndResetShowIconCount());
   proximity_auth::ScreenlockBridge::Get()->SetLockHandler(lock_handler_.get());
 
   EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
   ASSERT_TRUE(lock_handler_->HasCustomIcon());
   EXPECT_EQ(kHardlockedIconId, lock_handler_->GetCustomIconId());
 
@@ -672,12 +678,12 @@
   EXPECT_EQ(0u, lock_handler_->GetAndResetShowIconCount());
   EXPECT_TRUE(lock_handler_->HasCustomIcon());
   EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
-            lock_handler_->GetAuthType(user_email_));
+            lock_handler_->GetAuthType(account_id_));
 }
 
 TEST_F(EasyUnlockScreenlockStateHandlerTest, NoOverrideOnlineSignin) {
   lock_handler_->SetAuthType(
-      user_email_,
+      account_id_,
       proximity_auth::ScreenlockBridge::LockHandler::ONLINE_SIGN_IN,
       base::string16());
 
@@ -697,7 +703,7 @@
   for (size_t i = 0; i < states.size(); ++i) {
     state_handler_->ChangeState(states[i]);
     EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::ONLINE_SIGN_IN,
-              lock_handler_->GetAuthType(user_email_));
+              lock_handler_->GetAuthType(account_id_));
     EXPECT_FALSE(lock_handler_->HasCustomIcon());
   }
 
@@ -712,7 +718,7 @@
   for (size_t i = 0; i < hardlock_states.size(); ++i) {
     state_handler_->SetHardlockState(hardlock_states[i]);
     EXPECT_EQ(proximity_auth::ScreenlockBridge::LockHandler::ONLINE_SIGN_IN,
-              lock_handler_->GetAuthType(user_email_));
+              lock_handler_->GetAuthType(account_id_));
     EXPECT_FALSE(lock_handler_->HasCustomIcon());
   }
 }
diff --git a/chrome/browser/signin/easy_unlock_service.cc b/chrome/browser/signin/easy_unlock_service.cc
index 1dd6a91..5fa95359 100644
--- a/chrome/browser/signin/easy_unlock_service.cc
+++ b/chrome/browser/signin/easy_unlock_service.cc
@@ -303,25 +303,25 @@
 }
 
 // static
-void EasyUnlockService::ResetLocalStateForUser(const std::string& user_id) {
-  DCHECK(!user_id.empty());
+void EasyUnlockService::ResetLocalStateForUser(const AccountId& account_id) {
+  DCHECK(account_id.is_valid());
 
   PrefService* local_state = GetLocalState();
   if (!local_state)
     return;
 
   DictionaryPrefUpdate update(local_state, prefs::kEasyUnlockHardlockState);
-  update->RemoveWithoutPathExpansion(user_id, NULL);
+  update->RemoveWithoutPathExpansion(account_id.GetUserEmail(), NULL);
 
 #if defined(OS_CHROMEOS)
-  EasyUnlockTpmKeyManager::ResetLocalStateForUser(user_id);
+  EasyUnlockTpmKeyManager::ResetLocalStateForUser(account_id);
 #endif
 }
 
 // static
 EasyUnlockService::UserSettings EasyUnlockService::GetUserSettings(
-    const std::string& user_id) {
-  DCHECK(!user_id.empty());
+    const AccountId& account_id) {
+  DCHECK(account_id.is_valid());
   UserSettings user_settings;
 
   PrefService* local_state = GetLocalState();
@@ -334,8 +334,8 @@
     return user_settings;
 
   const base::DictionaryValue* user_prefs_dict;
-  if (!all_user_prefs_dict->GetDictionaryWithoutPathExpansion(user_id,
-                                                              &user_prefs_dict))
+  if (!all_user_prefs_dict->GetDictionaryWithoutPathExpansion(
+          account_id.GetUserEmail(), &user_prefs_dict))
     return user_settings;
 
   user_prefs_dict->GetBooleanWithoutPathExpansion(
@@ -397,14 +397,14 @@
 
 void EasyUnlockService::SetHardlockState(
     EasyUnlockScreenlockStateHandler::HardlockState state) {
-  const std::string user_id = GetUserEmail();
-  if (user_id.empty())
+  const AccountId& account_id = GetAccountId();
+  if (!account_id.is_valid())
     return;
 
   if (state == GetHardlockState())
     return;
 
-  SetHardlockStateForUser(user_id, state);
+  SetHardlockStateForUser(account_id, state);
 }
 
 EasyUnlockScreenlockStateHandler::HardlockState
@@ -418,8 +418,8 @@
 
 bool EasyUnlockService::GetPersistedHardlockState(
     EasyUnlockScreenlockStateHandler::HardlockState* state) const {
-  std::string user_id = GetUserEmail();
-  if (user_id.empty())
+  const AccountId& account_id = GetAccountId();
+  if (!account_id.is_valid())
     return false;
 
   PrefService* local_state = GetLocalState();
@@ -429,7 +429,9 @@
   const base::DictionaryValue* dict =
       local_state->GetDictionary(prefs::kEasyUnlockHardlockState);
   int state_int;
-  if (dict && dict->GetIntegerWithoutPathExpansion(user_id, &state_int)) {
+  if (dict &&
+      dict->GetIntegerWithoutPathExpansion(account_id.GetUserEmail(),
+                                           &state_int)) {
     *state =
         static_cast<EasyUnlockScreenlockStateHandler::HardlockState>(state_int);
     return true;
@@ -461,7 +463,7 @@
     return NULL;
   if (!screenlock_state_handler_) {
     screenlock_state_handler_.reset(new EasyUnlockScreenlockStateHandler(
-        GetUserEmail(), GetHardlockState(),
+        GetAccountId(), GetHardlockState(),
         proximity_auth::ScreenlockBridge::Get()));
   }
   return screenlock_state_handler_.get();
@@ -485,7 +487,7 @@
     auth_attempt_.reset();
 
     if (!handler->InStateValidOnRemoteAuthFailure())
-      HandleAuthFailure(GetUserEmail());
+      HandleAuthFailure(GetAccountId());
   }
 
   FOR_EACH_OBSERVER(
@@ -501,29 +503,30 @@
   return handler->state();
 }
 
-void EasyUnlockService::AttemptAuth(const std::string& user_id) {
-  AttemptAuth(user_id, AttemptAuthCallback());
+void EasyUnlockService::AttemptAuth(const AccountId& account_id) {
+  AttemptAuth(account_id, AttemptAuthCallback());
 }
 
-void EasyUnlockService::AttemptAuth(const std::string& user_id,
+void EasyUnlockService::AttemptAuth(const AccountId& account_id,
                                     const AttemptAuthCallback& callback) {
   const EasyUnlockAuthAttempt::Type auth_attempt_type =
       GetType() == TYPE_REGULAR ? EasyUnlockAuthAttempt::TYPE_UNLOCK
                                 : EasyUnlockAuthAttempt::TYPE_SIGNIN;
-  const std::string user_email = GetUserEmail();
-  if (user_email.empty()) {
-    LOG(ERROR) << "Empty user email. Refresh token might go bad.";
+  if (!GetAccountId().is_valid()) {
+    LOG(ERROR) << "Empty user account. Refresh token might go bad.";
     if (!callback.is_null()) {
       const bool kFailure = false;
-      callback.Run(auth_attempt_type, kFailure, user_id, std::string(),
+      callback.Run(auth_attempt_type, kFailure, account_id, std::string(),
                    std::string());
     }
     return;
   }
 
-  CHECK_EQ(GetUserEmail(), user_id);
+  CHECK(GetAccountId() == account_id)
+      << "Check failed: " << GetAccountId().Serialize() << " vs "
+      << account_id.Serialize();
 
-  auth_attempt_.reset(new EasyUnlockAuthAttempt(app_manager_.get(), user_id,
+  auth_attempt_.reset(new EasyUnlockAuthAttempt(app_manager_.get(), account_id,
                                                 auth_attempt_type, callback));
   if (!auth_attempt_->Start())
     auth_attempt_.reset();
@@ -534,7 +537,7 @@
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery) &&
       proximity_auth_system_) {
-    proximity_auth_system_->OnAuthAttempted(user_id);
+    proximity_auth_system_->OnAuthAttempted(account_id);
   }
 }
 
@@ -543,7 +546,7 @@
     return;
 
   this->OnWillFinalizeUnlock(success);
-  auth_attempt_->FinalizeUnlock(GetUserEmail(), success);
+  auth_attempt_->FinalizeUnlock(GetAccountId(), success);
   auth_attempt_.reset();
   // TODO(isherman): If observing screen unlock events, is there a race
   // condition in terms of reading the service's state vs. the app setting the
@@ -552,7 +555,7 @@
   // Make sure that the lock screen is updated on failure.
   if (!success) {
     RecordEasyUnlockScreenUnlockEvent(EASY_UNLOCK_FAILURE);
-    HandleAuthFailure(GetUserEmail());
+    HandleAuthFailure(GetAccountId());
   }
 }
 
@@ -561,18 +564,18 @@
     return;
   std::string wrapped_secret = GetWrappedSecret();
   if (!wrapped_secret.empty())
-    auth_attempt_->FinalizeSignin(GetUserEmail(), wrapped_secret, key);
+    auth_attempt_->FinalizeSignin(GetAccountId(), wrapped_secret, key);
   auth_attempt_.reset();
 
   // Processing empty key is equivalent to auth cancellation. In this case the
   // signin request will not actually be processed by login stack, so the lock
   // screen state should be set from here.
   if (key.empty())
-    HandleAuthFailure(GetUserEmail());
+    HandleAuthFailure(GetAccountId());
 }
 
-void EasyUnlockService::HandleAuthFailure(const std::string& user_id) {
-  if (user_id != GetUserEmail())
+void EasyUnlockService::HandleAuthFailure(const AccountId& account_id) {
+  if (account_id != GetAccountId())
     return;
 
   if (!screenlock_state_handler_.get())
@@ -584,8 +587,8 @@
 
 void EasyUnlockService::CheckCryptohomeKeysAndMaybeHardlock() {
 #if defined(OS_CHROMEOS)
-  std::string user_id = GetUserEmail();
-  if (user_id.empty())
+  const AccountId& account_id = GetAccountId();
+  if (!account_id.is_valid())
     return;
 
   const base::ListValue* device_list = GetRemoteDevices();
@@ -613,9 +616,9 @@
   DCHECK(key_manager);
 
   key_manager->GetDeviceDataList(
-      chromeos::UserContext(AccountId::FromUserEmail(user_id)),
+      chromeos::UserContext(account_id),
       base::Bind(&EasyUnlockService::OnCryptohomeKeysFetchedForChecking,
-                 weak_ptr_factory_.GetWeakPtr(), user_id, paired_devices));
+                 weak_ptr_factory_.GetWeakPtr(), account_id, paired_devices));
 #endif
 }
 
@@ -704,14 +707,15 @@
 }
 
 void EasyUnlockService::NotifyUserUpdated() {
-  std::string user_id = GetUserEmail();
-  if (user_id.empty())
+  const AccountId& account_id = GetAccountId();
+  if (!account_id.is_valid())
     return;
 
   // Notify the easy unlock app that the user info changed.
   bool logged_in = GetType() == TYPE_REGULAR;
   bool data_ready = logged_in || GetRemoteDevices() != NULL;
-  app_manager_->SendUserUpdatedEvent(user_id, logged_in, data_ready);
+  app_manager_->SendUserUpdatedEvent(account_id.GetUserEmail(), logged_in,
+                                     data_ready);
 }
 
 void EasyUnlockService::NotifyTurnOffOperationStatusChanged() {
@@ -764,18 +768,19 @@
 }
 
 void EasyUnlockService::SetHardlockStateForUser(
-      const std::string& user_id,
-      EasyUnlockScreenlockStateHandler::HardlockState state) {
-  DCHECK(!user_id.empty());
+    const AccountId& account_id,
+    EasyUnlockScreenlockStateHandler::HardlockState state) {
+  DCHECK(account_id.is_valid());
 
   PrefService* local_state = GetLocalState();
   if (!local_state)
     return;
 
   DictionaryPrefUpdate update(local_state, prefs::kEasyUnlockHardlockState);
-  update->SetIntegerWithoutPathExpansion(user_id, static_cast<int>(state));
+  update->SetIntegerWithoutPathExpansion(account_id.GetUserEmail(),
+                                         static_cast<int>(state));
 
-  if (GetUserEmail() == user_id)
+  if (GetAccountId() == account_id)
     SetScreenlockHardlockedState(state);
 }
 
@@ -834,7 +839,7 @@
 }
 
 void EasyUnlockService::SetProximityAuthDevices(
-    const std::string& user_id,
+    const AccountId& account_id,
     const proximity_auth::RemoteDeviceList& remote_devices) {
   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
           proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery))
@@ -849,20 +854,20 @@
         proximity_auth_client()));
   }
 
-  proximity_auth_system_->SetRemoteDevicesForUser(user_id, remote_devices);
+  proximity_auth_system_->SetRemoteDevicesForUser(account_id, remote_devices);
   proximity_auth_system_->Start();
 }
 
 #if defined(OS_CHROMEOS)
 void EasyUnlockService::OnCryptohomeKeysFetchedForChecking(
-    const std::string& user_id,
+    const AccountId& account_id,
     const std::set<std::string> paired_devices,
     bool success,
     const chromeos::EasyUnlockDeviceKeyDataList& key_data_list) {
-  DCHECK(!user_id.empty() && !paired_devices.empty());
+  DCHECK(account_id.is_valid() && !paired_devices.empty());
 
   if (!success) {
-    SetHardlockStateForUser(user_id,
+    SetHardlockStateForUser(account_id,
                             EasyUnlockScreenlockStateHandler::NO_PAIRING);
     return;
   }
@@ -874,10 +879,9 @@
   if (paired_devices != devices_in_cryptohome ||
       GetHardlockState() == EasyUnlockScreenlockStateHandler::NO_PAIRING) {
     SetHardlockStateForUser(
-        user_id,
-        devices_in_cryptohome.empty()
-            ? EasyUnlockScreenlockStateHandler::PAIRING_ADDED
-            : EasyUnlockScreenlockStateHandler::PAIRING_CHANGED);
+        account_id, devices_in_cryptohome.empty()
+                        ? EasyUnlockScreenlockStateHandler::PAIRING_ADDED
+                        : EasyUnlockScreenlockStateHandler::PAIRING_CHANGED);
   }
 }
 #endif
@@ -896,7 +900,7 @@
 }
 
 void EasyUnlockService::EnsureTpmKeyPresentIfNeeded() {
-  if (tpm_key_checked_ || GetType() != TYPE_REGULAR || GetUserEmail().empty() ||
+  if (tpm_key_checked_ || GetType() != TYPE_REGULAR || GetAccountId().empty() ||
       GetHardlockState() == EasyUnlockScreenlockStateHandler::NO_PAIRING) {
     return;
   }
diff --git a/chrome/browser/signin/easy_unlock_service.h b/chrome/browser/signin/easy_unlock_service.h
index e57590f..6910d99 100644
--- a/chrome/browser/signin/easy_unlock_service.h
+++ b/chrome/browser/signin/easy_unlock_service.h
@@ -25,6 +25,8 @@
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_types.h"
 #endif
 
+class AccountId;
+
 namespace base {
 class DictionaryValue;
 class ListValue;
@@ -85,10 +87,10 @@
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
   // Removes the hardlock state for the given user.
-  static void ResetLocalStateForUser(const std::string& user_id);
+  static void ResetLocalStateForUser(const AccountId& account_id);
 
   // Returns the user's preferences.
-  static UserSettings GetUserSettings(const std::string& user_id);
+  static UserSettings GetUserSettings(const AccountId& account_id);
 
   // Returns the identifier for the device.
   static std::string GetDeviceId();
@@ -97,7 +99,7 @@
   virtual Type GetType() const = 0;
 
   // Returns the user currently associated with the service.
-  virtual std::string GetUserEmail() const = 0;
+  virtual AccountId GetAccountId() const = 0;
 
   // Launches Easy Unlock setup app.
   virtual void LaunchSetup() = 0;
@@ -132,11 +134,11 @@
   virtual std::string GetWrappedSecret() const = 0;
 
   // Records metrics for Easy sign-in outcome for the given user.
-  virtual void RecordEasySignInOutcome(const std::string& user_id,
+  virtual void RecordEasySignInOutcome(const AccountId& account_id,
                                        bool success) const = 0;
 
   // Records metrics for password based flow for the given user.
-  virtual void RecordPasswordLoginEvent(const std::string& user_id) const = 0;
+  virtual void RecordPasswordLoginEvent(const AccountId& account_id) const = 0;
 
   // Starts auto pairing.
   typedef base::Callback<void(bool success, const std::string& error)>
@@ -183,12 +185,12 @@
 
   // Starts an auth attempt for the user associated with the service. The
   // attempt type (unlock vs. signin) will depend on the service type.
-  void AttemptAuth(const std::string& user_id);
+  void AttemptAuth(const AccountId& account_id);
 
   // Similar to above but a callback is invoked after the auth attempt is
   // finalized instead of default unlock/sign-in.
   typedef EasyUnlockAuthAttempt::FinalizedCallback AttemptAuthCallback;
-  void AttemptAuth(const std::string& user_id,
+  void AttemptAuth(const AccountId& account_id,
                    const AttemptAuthCallback& callback);
 
   // Finalizes the previously started auth attempt for easy unlock. If called on
@@ -202,7 +204,7 @@
   void FinalizeSignin(const std::string& secret);
 
   // Handles Easy Unlock auth failure for the user.
-  void HandleAuthFailure(const std::string& user_id);
+  void HandleAuthFailure(const AccountId& account_id);
 
   // Checks the consistency between pairing data and cryptohome keys. Set
   // hardlock state if the two do not match.
@@ -289,7 +291,7 @@
   // Saves hardlock state for the given user. Update UI if the currently
   // associated user is the same.
   void SetHardlockStateForUser(
-      const std::string& user_id,
+      const AccountId& account_id,
       EasyUnlockScreenlockStateHandler::HardlockState state);
 
   // Returns the authentication event for a recent password sign-in or unlock,
@@ -297,9 +299,9 @@
   EasyUnlockAuthEvent GetPasswordAuthEvent() const;
 
   // Called by subclasses when remote devices allowed to unlock the screen
-  // are loaded for |user_id|.
+  // are loaded for |account_id|.
   void SetProximityAuthDevices(
-      const std::string& user_id,
+      const AccountId& account_id,
       const proximity_auth::RemoteDeviceList& remote_devices);
 
  private:
@@ -321,7 +323,7 @@
 #if defined(OS_CHROMEOS)
   // Callback for get key operation from CheckCryptohomeKeysAndMaybeHardlock.
   void OnCryptohomeKeysFetchedForChecking(
-      const std::string& user_id,
+      const AccountId& account_id,
       const std::set<std::string> paired_devices,
       bool success,
       const chromeos::EasyUnlockDeviceKeyDataList& key_data_list);
diff --git a/chrome/browser/signin/easy_unlock_service_regular.cc b/chrome/browser/signin/easy_unlock_service_regular.cc
index 2a9e3d0..a5b817a1 100644
--- a/chrome/browser/signin/easy_unlock_service_regular.cc
+++ b/chrome/browser/signin/easy_unlock_service_regular.cc
@@ -99,7 +99,7 @@
 
 void EasyUnlockServiceRegular::LoadRemoteDevices() {
   if (device_manager_->unlock_keys().empty()) {
-    SetProximityAuthDevices(GetUserEmail(), proximity_auth::RemoteDeviceList());
+    SetProximityAuthDevices(GetAccountId(), proximity_auth::RemoteDeviceList());
     return;
   }
 
@@ -115,7 +115,7 @@
 
 void EasyUnlockServiceRegular::OnRemoteDevicesLoaded(
     const proximity_auth::RemoteDeviceList& remote_devices) {
-  SetProximityAuthDevices(GetUserEmail(), remote_devices);
+  SetProximityAuthDevices(GetAccountId(), remote_devices);
 
 #if defined(OS_CHROMEOS)
   // We need to store a copy of |remote devices_| in the TPM, so it can be
@@ -153,7 +153,7 @@
   return EasyUnlockService::TYPE_REGULAR;
 }
 
-std::string EasyUnlockServiceRegular::GetUserEmail() const {
+AccountId EasyUnlockServiceRegular::GetAccountId() const {
   const SigninManagerBase* signin_manager =
       SigninManagerFactory::GetForProfileIfExists(profile());
   // |profile| has to be a signed-in profile with SigninManager already
@@ -161,7 +161,9 @@
   DCHECK(signin_manager);
   const std::string user_email =
       signin_manager->GetAuthenticatedAccountInfo().email;
-  return user_email.empty() ? user_email : gaia::CanonicalizeEmail(user_email);
+  return user_email.empty()
+             ? EmptyAccountId()
+             : AccountId::FromUserEmail(gaia::CanonicalizeEmail(user_email));
 }
 
 void EasyUnlockServiceRegular::LaunchSetup() {
@@ -212,7 +214,7 @@
     EasyUnlockScreenlockStateHandler::HardlockState state_on_success,
     bool success) {
   if (success)
-    SetHardlockStateForUser(GetUserEmail(), state_on_success);
+    SetHardlockStateForUser(GetAccountId(), state_on_success);
 
   // Even if the refresh keys operation suceeded, we still fetch and check the
   // cryptohome keys against the keys in local preferences as a sanity check.
@@ -369,13 +371,13 @@
 }
 
 void EasyUnlockServiceRegular::RecordEasySignInOutcome(
-    const std::string& user_id,
+    const AccountId& account_id,
     bool success) const {
   NOTREACHED();
 }
 
 void EasyUnlockServiceRegular::RecordPasswordLoginEvent(
-    const std::string& user_id) const {
+    const AccountId& account_id) const {
   NOTREACHED();
 }
 
@@ -543,7 +545,7 @@
 }
 
 void EasyUnlockServiceRegular::OnFocusedUserChanged(
-    const std::string& user_id) {
+    const AccountId& account_id) {
   // Nothing to do.
 }
 
@@ -589,8 +591,8 @@
 
   DictionaryPrefUpdate update(local_state,
                               prefs::kEasyUnlockLocalStateUserPrefs);
-  std::string user_email = GetUserEmail();
-  update->SetWithoutPathExpansion(user_email, user_prefs_dict.Pass());
+  update->SetWithoutPathExpansion(GetAccountId().GetUserEmail(),
+                                  user_prefs_dict.Pass());
 }
 
 cryptauth::GcmDeviceInfo EasyUnlockServiceRegular::GetGcmDeviceInfo() {
diff --git a/chrome/browser/signin/easy_unlock_service_regular.h b/chrome/browser/signin/easy_unlock_service_regular.h
index 2a45797..9998d88 100644
--- a/chrome/browser/signin/easy_unlock_service_regular.h
+++ b/chrome/browser/signin/easy_unlock_service_regular.h
@@ -77,7 +77,7 @@
 
   // EasyUnlockService implementation:
   EasyUnlockService::Type GetType() const override;
-  std::string GetUserEmail() const override;
+  AccountId GetAccountId() const override;
   void LaunchSetup() override;
   const base::DictionaryValue* GetPermitAccess() const override;
   void SetPermitAccess(const base::DictionaryValue& permit) override;
@@ -90,9 +90,9 @@
   TurnOffFlowStatus GetTurnOffFlowStatus() const override;
   std::string GetChallenge() const override;
   std::string GetWrappedSecret() const override;
-  void RecordEasySignInOutcome(const std::string& user_id,
+  void RecordEasySignInOutcome(const AccountId& account_id,
                                bool success) const override;
-  void RecordPasswordLoginEvent(const std::string& user_id) const override;
+  void RecordPasswordLoginEvent(const AccountId& account_id) const override;
   void StartAutoPairing(const AutoPairingResultCallback& callback) override;
   void SetAutoPairingResult(bool success, const std::string& error) override;
   void InitializeInternal() override;
@@ -116,8 +116,7 @@
   void OnScreenDidUnlock(
       proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type)
       override;
-  void OnFocusedUserChanged(const std::string& user_id) override;
-
+  void OnFocusedUserChanged(const AccountId& account_id) override;
 
   // Callback when the controlling pref changes.
   void OnPrefsChanged();
diff --git a/chrome/browser/signin/easy_unlock_service_signin_chromeos.cc b/chrome/browser/signin/easy_unlock_service_signin_chromeos.cc
index 862bc56f..18aa774 100644
--- a/chrome/browser/signin/easy_unlock_service_signin_chromeos.cc
+++ b/chrome/browser/signin/easy_unlock_service_signin_chromeos.cc
@@ -45,7 +45,7 @@
 }
 
 void LoadDataForUser(
-    const std::string& user_id,
+    const AccountId& account_id,
     uint32 backoff_ms,
     const chromeos::EasyUnlockKeyManager::GetDeviceDataListCallback& callback);
 
@@ -56,7 +56,7 @@
 // |LoadDataForUser| call with some backoff. If no further retires are allowed,
 // it invokes |callback| with the |LoadDataForUser| results.
 void RetryDataLoadOnError(
-    const std::string& user_id,
+    const AccountId& account_id,
     uint32 backoff_ms,
     const chromeos::EasyUnlockKeyManager::GetDeviceDataListCallback& callback,
     bool success,
@@ -74,13 +74,13 @@
 
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&LoadDataForUser, user_id, next_backoff_ms, callback),
+      base::Bind(&LoadDataForUser, account_id, next_backoff_ms, callback),
       base::TimeDelta::FromMilliseconds(next_backoff_ms));
 }
 
 // Loads device data list associated with the user's Easy unlock keys.
 void LoadDataForUser(
-    const std::string& user_id,
+    const AccountId& account_id,
     uint32 backoff_ms,
     const chromeos::EasyUnlockKeyManager::GetDeviceDataListCallback& callback) {
   chromeos::EasyUnlockKeyManager* key_manager =
@@ -88,8 +88,8 @@
   DCHECK(key_manager);
 
   key_manager->GetDeviceDataList(
-      chromeos::UserContext(AccountId::FromUserEmail(user_id)),
-      base::Bind(&RetryDataLoadOnError, user_id, backoff_ms, callback));
+      chromeos::UserContext(account_id),
+      base::Bind(&RetryDataLoadOnError, account_id, backoff_ms, callback));
 }
 
 }  // namespace
@@ -102,28 +102,25 @@
 
 EasyUnlockServiceSignin::EasyUnlockServiceSignin(Profile* profile)
     : EasyUnlockService(profile),
-      allow_cryptohome_backoff_(true),
-      service_active_(false),
+      account_id_(EmptyAccountId()),
       user_pod_last_focused_timestamp_(base::TimeTicks::Now()),
-      weak_ptr_factory_(this) {
-}
+      weak_ptr_factory_(this) {}
 
 EasyUnlockServiceSignin::~EasyUnlockServiceSignin() {
 }
 
-void EasyUnlockServiceSignin::SetCurrentUser(const std::string& user_id) {
-  OnFocusedUserChanged(user_id);
+void EasyUnlockServiceSignin::SetCurrentUser(const AccountId& account_id) {
+  OnFocusedUserChanged(account_id);
 }
 
 void EasyUnlockServiceSignin::WrapChallengeForUserAndDevice(
-    const std::string& user_id,
+    const AccountId& account_id,
     const std::string& device_public_key,
     const std::string& channel_binding_data,
     base::Callback<void(const std::string& wraped_challenge)> callback) {
-  std::map<std::string, UserData*>::const_iterator it =
-      user_data_.find(user_id);
+  auto it = user_data_.find(account_id);
   if (it == user_data_.end() || it->second->state != USER_DATA_STATE_LOADED) {
-    PA_LOG(ERROR) << "TPM data not loaded for " << user_id;
+    PA_LOG(ERROR) << "TPM data not loaded for " << account_id.Serialize();
     callback.Run(std::string());
     return;
   }
@@ -134,16 +131,18 @@
                         &device_public_key_base64);
   for (const auto& device_data : it->second->devices) {
     if (device_data.public_key == device_public_key_base64) {
-      PA_LOG(INFO) << "Wrapping challenge for " << user_id << "...";
+      PA_LOG(INFO) << "Wrapping challenge for " << account_id.Serialize()
+                   << "...";
       challenge_wrapper_.reset(new chromeos::EasyUnlockChallengeWrapper(
-          device_data.challenge, channel_binding_data, user_id,
+          device_data.challenge, channel_binding_data, account_id,
           EasyUnlockTpmKeyManagerFactory::GetInstance()->Get(profile())));
       challenge_wrapper_->WrapChallenge(callback);
       return;
     }
   }
 
-  PA_LOG(ERROR) << "Unable to find device record for " << user_id;
+  PA_LOG(ERROR) << "Unable to find device record for "
+                << account_id.Serialize();
   callback.Run(std::string());
 }
 
@@ -151,8 +150,8 @@
   return EasyUnlockService::TYPE_SIGNIN;
 }
 
-std::string EasyUnlockServiceSignin::GetUserEmail() const {
-  return user_id_;
+AccountId EasyUnlockServiceSignin::GetAccountId() const {
+  return account_id_;
 }
 
 void EasyUnlockServiceSignin::LaunchSetup() {
@@ -160,7 +159,7 @@
 }
 
 const base::DictionaryValue* EasyUnlockServiceSignin::GetPermitAccess() const {
-  return NULL;
+  return nullptr;
 }
 
 void EasyUnlockServiceSignin::SetPermitAccess(
@@ -175,7 +174,7 @@
 const base::ListValue* EasyUnlockServiceSignin::GetRemoteDevices() const {
   const UserData* data = FindLoadedDataForCurrentUser();
   if (!data)
-    return NULL;
+    return nullptr;
   return &data->remote_devices_value;
 }
 
@@ -221,9 +220,11 @@
 }
 
 void EasyUnlockServiceSignin::RecordEasySignInOutcome(
-    const std::string& user_id,
+    const AccountId& account_id,
     bool success) const {
-  DCHECK_EQ(GetUserEmail(), user_id);
+  DCHECK(GetAccountId() == account_id)
+      << "GetAccountId()=" << GetAccountId().Serialize()
+      << " != account_id=" << account_id.Serialize();
 
   RecordEasyUnlockSigninEvent(
       success ? EASY_UNLOCK_SUCCESS : EASY_UNLOCK_FAILURE);
@@ -235,10 +236,10 @@
 }
 
 void EasyUnlockServiceSignin::RecordPasswordLoginEvent(
-    const std::string& user_id) const {
+    const AccountId& account_id) const {
   // This happens during tests, where a user could log in without the user pod
   // being focused.
-  if (GetUserEmail() != user_id)
+  if (GetAccountId() != account_id)
     return;
 
   if (!IsEnabled())
@@ -270,8 +271,8 @@
   proximity_auth::ScreenlockBridge* screenlock_bridge =
       proximity_auth::ScreenlockBridge::Get();
   screenlock_bridge->AddObserver(this);
-  if (!screenlock_bridge->focused_user_id().empty())
-    OnFocusedUserChanged(screenlock_bridge->focused_user_id());
+  if (screenlock_bridge->focused_account_id().is_valid())
+    OnFocusedUserChanged(screenlock_bridge->focused_account_id());
 }
 
 void EasyUnlockServiceSignin::ShutdownInternal() {
@@ -287,8 +288,7 @@
 }
 
 bool EasyUnlockServiceSignin::IsAllowedInternal() const {
-  return service_active_ &&
-         !user_id_.empty() &&
+  return service_active_ && account_id_.is_valid() &&
          !chromeos::LoginState::Get()->IsUserLoggedIn();
 }
 
@@ -328,15 +328,18 @@
   Shutdown();
 }
 
-void EasyUnlockServiceSignin::OnFocusedUserChanged(const std::string& user_id) {
-  if (user_id_ == user_id)
+void EasyUnlockServiceSignin::OnFocusedUserChanged(
+    const AccountId& account_id) {
+  if (account_id_ == account_id)
     return;
 
-  // Setting or clearing the user_id may changed |IsAllowed| value, so in these
+  // Setting or clearing the account_id may changed |IsAllowed| value, so in
+  // these
   // cases update the app state. Otherwise, it's enough to notify the app the
   // user data has been updated.
-  bool should_update_app_state = user_id_.empty() != user_id.empty();
-  user_id_ = user_id;
+  const bool should_update_app_state =
+      account_id_.is_valid() != account_id.is_valid();
+  account_id_ = account_id;
   user_pod_last_focused_timestamp_ = base::TimeTicks::Now();
 
   ResetScreenlockState();
@@ -371,39 +374,38 @@
   if (!base::SysInfo::IsRunningOnChromeOS())
     return;
 
-  if (user_id_.empty() || !service_active_)
+  if (account_id_.is_valid() || !service_active_)
     return;
 
-  std::map<std::string, UserData*>::iterator it = user_data_.find(user_id_);
+  const auto it = user_data_.find(account_id_);
   if (it == user_data_.end())
-    user_data_.insert(std::make_pair(user_id_, new UserData()));
+    user_data_.insert(std::make_pair(account_id_, new UserData()));
 
-  UserData* data = user_data_[user_id_];
+  UserData* data = user_data_[account_id_];
 
   if (data->state != USER_DATA_STATE_INITIAL)
     return;
   data->state = USER_DATA_STATE_LOADING;
 
   LoadDataForUser(
-      user_id_,
+      account_id_,
       allow_cryptohome_backoff_ ? 0u : kMaxCryptohomeBackoffIntervalMs,
       base::Bind(&EasyUnlockServiceSignin::OnUserDataLoaded,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 user_id_));
+                 weak_ptr_factory_.GetWeakPtr(), account_id_));
 }
 
 void EasyUnlockServiceSignin::OnUserDataLoaded(
-    const std::string& user_id,
+    const AccountId& account_id,
     bool success,
     const chromeos::EasyUnlockDeviceKeyDataList& devices) {
   allow_cryptohome_backoff_ = false;
 
-  UserData* data = user_data_[user_id];
+  UserData* data = user_data_[account_id];
   data->state = USER_DATA_STATE_LOADED;
   if (success) {
     data->devices = devices;
     chromeos::EasyUnlockKeyManager::DeviceDataListToRemoteDeviceList(
-        user_id, devices, &data->remote_devices_value);
+        account_id, devices, &data->remote_devices_value);
 
     // User could have a NO_HARDLOCK state but has no remote devices if
     // previous user session shuts down before
@@ -413,17 +415,17 @@
     if (devices.empty() &&
         GetPersistedHardlockState(&hardlock_state) &&
         hardlock_state == EasyUnlockScreenlockStateHandler::NO_HARDLOCK) {
-      SetHardlockStateForUser(user_id,
+      SetHardlockStateForUser(account_id,
                               EasyUnlockScreenlockStateHandler::NO_PAIRING);
     }
   }
 
   // If the fetched data belongs to the currently focused user, notify the app
   // that it has to refresh it's user data.
-  if (user_id == user_id_)
+  if (account_id == account_id_)
     NotifyUserUpdated();
 
-  if (user_id != user_id || devices.empty())
+  if (devices.empty())
     return;
 
   proximity_auth::RemoteDeviceList remote_devices;
@@ -447,8 +449,9 @@
             ? proximity_auth::RemoteDevice::BLUETOOTH_LE
             : proximity_auth::RemoteDevice::BLUETOOTH_CLASSIC;
     proximity_auth::RemoteDevice remote_device(
-        user_id, std::string(), decoded_public_key, bluetooth_type,
-        device.bluetooth_address, decoded_psk, decoded_challenge);
+        account_id.GetUserEmail(), std::string(), decoded_public_key,
+        bluetooth_type, device.bluetooth_address, decoded_psk,
+        decoded_challenge);
     remote_devices.push_back(remote_device);
     PA_LOG(INFO) << "Loaded Remote Device:\n"
                  << "  user id: " << remote_device.user_id << "\n"
@@ -458,19 +461,18 @@
                  << "  type:" << static_cast<int>(remote_device.bluetooth_type);
   }
 
-  SetProximityAuthDevices(user_id, remote_devices);
+  SetProximityAuthDevices(account_id, remote_devices);
 }
 
 const EasyUnlockServiceSignin::UserData*
     EasyUnlockServiceSignin::FindLoadedDataForCurrentUser() const {
-  if (user_id_.empty())
-    return NULL;
+  if (account_id_.is_valid())
+    return nullptr;
 
-  std::map<std::string, UserData*>::const_iterator it =
-      user_data_.find(user_id_);
+  const auto it = user_data_.find(account_id_);
   if (it == user_data_.end())
-    return NULL;
+    return nullptr;
   if (it->second->state != USER_DATA_STATE_LOADED)
-    return NULL;
+    return nullptr;
   return it->second;
 }
diff --git a/chrome/browser/signin/easy_unlock_service_signin_chromeos.h b/chrome/browser/signin/easy_unlock_service_signin_chromeos.h
index 8dd90f3..9496f89 100644
--- a/chrome/browser/signin/easy_unlock_service_signin_chromeos.h
+++ b/chrome/browser/signin/easy_unlock_service_signin_chromeos.h
@@ -31,17 +31,18 @@
   explicit EasyUnlockServiceSignin(Profile* profile);
   ~EasyUnlockServiceSignin() override;
 
-  // Sets |user_id| as the current user of the service. Note this does
+  // Sets |account_id| as the current user of the service. Note this does
   // not change the focused user on the login screen.
-  void SetCurrentUser(const std::string& user_id);
+  void SetCurrentUser(const AccountId& account_id);
 
-  // Wraps the challenge for the remote device identified by |user_id| and the
+  // Wraps the challenge for the remote device identified by |account_id| and
+  // the
   // |device_public_key|. The |channel_binding_data| is signed by the TPM
   // included in the wrapped challenge.
   // |callback| will be invoked when wrapping is complete. If the user data is
   // not loaded yet, then |callback| will be invoked with an empty string.
   void WrapChallengeForUserAndDevice(
-      const std::string& user_id,
+      const AccountId& account_id,
       const std::string& device_public_key,
       const std::string& channel_binding_data,
       base::Callback<void(const std::string& wraped_challenge)> callback);
@@ -78,7 +79,7 @@
 
   // EasyUnlockService implementation:
   EasyUnlockService::Type GetType() const override;
-  std::string GetUserEmail() const override;
+  AccountId GetAccountId() const override;
   void LaunchSetup() override;
   const base::DictionaryValue* GetPermitAccess() const override;
   void SetPermitAccess(const base::DictionaryValue& permit) override;
@@ -91,9 +92,9 @@
   TurnOffFlowStatus GetTurnOffFlowStatus() const override;
   std::string GetChallenge() const override;
   std::string GetWrappedSecret() const override;
-  void RecordEasySignInOutcome(const std::string& user_id,
+  void RecordEasySignInOutcome(const AccountId& account_id,
                                bool success) const override;
-  void RecordPasswordLoginEvent(const std::string& user_id) const override;
+  void RecordPasswordLoginEvent(const AccountId& account_id) const override;
   void StartAutoPairing(const AutoPairingResultCallback& callback) override;
   void SetAutoPairingResult(bool success, const std::string& error) override;
   void InitializeInternal() override;
@@ -108,7 +109,7 @@
   void OnScreenDidUnlock(
       proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type)
       override;
-  void OnFocusedUserChanged(const std::string& user_id) override;
+  void OnFocusedUserChanged(const AccountId& account_id) override;
 
   // chromeos::LoginState::Observer implementation:
   void LoggedInStateChanged() override;
@@ -118,30 +119,29 @@
   void LoadCurrentUserDataIfNeeded();
 
   // Callback invoked when the user's device data is loaded from cryptohome.
-  void OnUserDataLoaded(
-      const std::string& user_id,
-      bool success,
-      const chromeos::EasyUnlockDeviceKeyDataList& data);
+  void OnUserDataLoaded(const AccountId& account_id,
+                        bool success,
+                        const chromeos::EasyUnlockDeviceKeyDataList& data);
 
   // If the device data has been loaded for the current user, returns it.
   // Otherwise, returns NULL.
   const UserData* FindLoadedDataForCurrentUser() const;
 
   // User id of the user currently associated with the service.
-  std::string user_id_;
+  AccountId account_id_;
 
-  // Maps user ids to their fetched cryptohome key data.
-  std::map<std::string, UserData*> user_data_;
+  // Maps account ids to their fetched cryptohome key data.
+  std::map<AccountId, UserData*> user_data_;
 
   // Whether failed attempts to load user data should be retried.
   // This is to handle case where cryptohome daemon is not started in time the
   // service attempts to load some data. Retries will be allowed only until the
   // first data load finishes (even if it fails).
-  bool allow_cryptohome_backoff_;
+  bool allow_cryptohome_backoff_ = true;
 
   // Whether the service has been successfully initialized, and has not been
   // shut down.
-  bool service_active_;
+  bool service_active_ = false;
 
   // The timestamp for the most recent time when a user pod was focused.
   base::TimeTicks user_pod_last_focused_timestamp_;
diff --git a/chrome/browser/site_details_browsertest.cc b/chrome/browser/site_details_browsertest.cc
index 7c24045..c871e1e 100644
--- a/chrome/browser/site_details_browsertest.cc
+++ b/chrome/browser/site_details_browsertest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/site_details.h"
 
+#include <utility>
+
 #include "base/bind_helpers.h"
 #include "base/files/file_path.h"
 #include "base/message_loop/message_loop.h"
@@ -119,15 +121,17 @@
     manifest.Set("name", name)
         .Set("version", "1.0")
         .Set("manifest_version", 2)
-        .Set("web_accessible_resources", ListBuilder()
-                                             .Append("blank_iframe.html")
-                                             .Append("http_iframe.html")
-                                             .Append("two_http_iframes.html"));
+        .Set("web_accessible_resources",
+             std::move(ListBuilder()
+                           .Append("blank_iframe.html")
+                           .Append("http_iframe.html")
+                           .Append("two_http_iframes.html")));
 
     if (has_background_process) {
-      manifest.Set("background",
-                   DictionaryBuilder().Set("scripts",
-                                           ListBuilder().Append("script.js")));
+      manifest.Set(
+          "background",
+          DictionaryBuilder().Set(
+              "scripts", std::move(ListBuilder().Append("script.js"))));
       dir->WriteFile(FILE_PATH_LITERAL("script.js"),
                      "console.log('" + name + " running');");
     }
@@ -174,10 +178,11 @@
     manifest.Set("name", name)
         .Set("version", "1.0")
         .Set("manifest_version", 2)
-        .Set("app", DictionaryBuilder()
-                        .Set("urls", ListBuilder().Append(app_url.spec()))
-                        .Set("launch", DictionaryBuilder().Set(
-                                           "web_url", app_url.spec())));
+        .Set("app",
+             DictionaryBuilder()
+                 .Set("urls", std::move(ListBuilder().Append(app_url.spec())))
+                 .Set("launch",
+                      DictionaryBuilder().Set("web_url", app_url.spec())));
     dir->WriteManifest(manifest.ToJSON());
 
     const Extension* extension = LoadExtension(dir->unpacked_path());
diff --git a/chrome/browser/ssl/chrome_security_state_model_client.cc b/chrome/browser/ssl/chrome_security_state_model_client.cc
index 4892437..627cd1c1 100644
--- a/chrome/browser/ssl/chrome_security_state_model_client.cc
+++ b/chrome/browser/ssl/chrome_security_state_model_client.cc
@@ -13,6 +13,7 @@
 #include "content/public/browser/cert_store.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/origin_util.h"
 #include "content/public/common/ssl_status.h"
 #include "net/cert/x509_certificate.h"
 
@@ -53,6 +54,10 @@
   return false;
 }
 
+bool ChromeSecurityStateModelClient::IsOriginSecure(const GURL& url) {
+  return content::IsOriginSecure(url);
+}
+
 void ChromeSecurityStateModelClient::GetVisibleSecurityState(
     SecurityStateModel::VisibleSecurityState* state) {
   content::NavigationEntry* entry =
diff --git a/chrome/browser/ssl/chrome_security_state_model_client.h b/chrome/browser/ssl/chrome_security_state_model_client.h
index 78241bae..6e87cfb 100644
--- a/chrome/browser/ssl/chrome_security_state_model_client.h
+++ b/chrome/browser/ssl/chrome_security_state_model_client.h
@@ -29,6 +29,7 @@
       SecurityStateModel::VisibleSecurityState* state) override;
   bool RetrieveCert(scoped_refptr<net::X509Certificate>* cert) override;
   bool UsedPolicyInstalledCertificate() override;
+  bool IsOriginSecure(const GURL& url) override;
 
  private:
   explicit ChromeSecurityStateModelClient(content::WebContents* web_contents);
diff --git a/chrome/browser/ssl/security_state_model.cc b/chrome/browser/ssl/security_state_model.cc
index f4fe950..c179fbc 100644
--- a/chrome/browser/ssl/security_state_model.cc
+++ b/chrome/browser/ssl/security_state_model.cc
@@ -7,21 +7,16 @@
 #include "base/command_line.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/prefs/pref_service.h"
 #include "chrome/browser/ssl/security_state_model_client.h"
-#include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/pref_names.h"
-#include "content/public/common/origin_util.h"
 #include "net/ssl/ssl_cipher_suite_names.h"
 #include "net/ssl/ssl_connection_status_flags.h"
 
 namespace {
 
-// TODO(estark): move this to SecurityStateModelClient as this is
-// embedder-specific logic. https://crbug.com/515071
 SecurityStateModel::SecurityLevel GetSecurityLevelForNonSecureFieldTrial() {
+  // TODO(estark): componentize switches::kMarkNonSecureAs.
+  // https://crbug.com/515071
   std::string choice =
       base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
           switches::kMarkNonSecureAs);
@@ -102,7 +97,7 @@
       return SecurityStateModel::NONE;
 
     case content::SECURITY_STYLE_UNAUTHENTICATED: {
-      if (!content::IsOriginSecure(url) && url.IsStandard())
+      if (!client->IsOriginSecure(url) && url.IsStandard())
         return GetSecurityLevelForNonSecureFieldTrial();
       return SecurityStateModel::NONE;
     }
diff --git a/chrome/browser/ssl/security_state_model_client.h b/chrome/browser/ssl/security_state_model_client.h
index 512ec036..646d35a 100644
--- a/chrome/browser/ssl/security_state_model_client.h
+++ b/chrome/browser/ssl/security_state_model_client.h
@@ -34,6 +34,9 @@
   // certificate installed by the system administrator.
   virtual bool UsedPolicyInstalledCertificate() = 0;
 
+  // Returns true if the given |url|'s origin should be considered secure.
+  virtual bool IsOriginSecure(const GURL& url) = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SecurityStateModelClient);
 };
diff --git a/chrome/browser/ssl/security_state_model_unittest.cc b/chrome/browser/ssl/security_state_model_unittest.cc
index 0a6b7bc..d2fbe6bc 100644
--- a/chrome/browser/ssl/security_state_model_unittest.cc
+++ b/chrome/browser/ssl/security_state_model_unittest.cc
@@ -8,6 +8,7 @@
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/cert_store.h"
+#include "content/public/common/origin_util.h"
 #include "content/public/test/mock_render_process_host.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/base/test_data_directory.h"
@@ -74,6 +75,10 @@
 
   bool UsedPolicyInstalledCertificate() override { return false; }
 
+  bool IsOriginSecure(const GURL& url) override {
+    return content::IsOriginSecure(url);
+  }
+
  private:
   content::SecurityStyle initial_security_style_;
   scoped_refptr<net::X509Certificate> cert_;
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc
index 061b4f9..c56e085c 100644
--- a/chrome/browser/ssl/ssl_browser_tests.cc
+++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -555,6 +555,36 @@
   net::EmbeddedTestServer https_server_mismatched_;
   net::SpawnedTestServer wss_server_expired_;
 
+ protected:
+  // Navigates to an interstitial and clicks through the certificate
+  // error; then navigates to a page at |path| that loads unsafe content.
+  void SetUpUnsafeContentsWithUserException(const std::string& path) {
+    ASSERT_TRUE(https_server_.Start());
+    // Note that it is necessary to user https_server_mismatched_ here over the
+    // other invalid cert servers. This is because the test relies on the two
+    // servers having different hosts since SSL exceptions are per-host, not per
+    // origin, and https_server_mismatched_ uses 'localhost' rather than
+    // '127.0.0.1'.
+    ASSERT_TRUE(https_server_mismatched_.Start());
+
+    // Navigate to an unsafe site. Proceed with interstitial page to indicate
+    // the user approves the bad certificate.
+    ui_test_utils::NavigateToURL(
+        browser(), https_server_mismatched_.GetURL("/ssl/blank_page.html"));
+    WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+    CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID,
+                                   AuthState::SHOWING_INTERSTITIAL);
+    ProceedThroughInterstitial(tab);
+    CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID,
+                                   AuthState::NONE);
+
+    std::string replacement_path;
+    GetFilePathWithHostAndPortReplacement(
+        path, https_server_mismatched_.host_port_pair(), &replacement_path);
+    ui_test_utils::NavigateToURL(browser(),
+                                 https_server_.GetURL(replacement_path));
+  }
+
  private:
   typedef net::SpawnedTestServer::SSLOptions SSLOptions;
 
@@ -2125,10 +2155,7 @@
 
 // This test, and the related test TestUnsafeContentsWithUserException, verify
 // that if unsafe content is loaded but the host of that unsafe content has a
-// user exception, the content runs and the security style remains
-// authenticated. This is not necessarily the behavior that should exist, but it
-// is verification that it does behave that way. See https://crbug.com/477868
-// for more inforamtion on this.
+// user exception, the content runs and the security style is downgraded.
 IN_PROC_BROWSER_TEST_F(SSLUITest, TestUnsafeContentsInWorkerWithUserException) {
   ASSERT_TRUE(https_server_.Start());
   // Note that it is necessary to user https_server_mismatched_ here over the
@@ -2158,44 +2185,19 @@
   ui_test_utils::NavigateToURL(
       browser(), https_server_.GetURL(page_with_unsafe_worker_path));
   CheckWorkerLoadResult(tab, true);  // Worker loads insecure content
-  CheckAuthenticatedState(tab, CertError::NONE);
+  CheckAuthenticationBrokenState(tab, CertError::NONE,
+                                 AuthState::RAN_INSECURE_CONTENT);
 }
 
 // Visits a page with unsafe content and makes sure that if a user exception to
 // the certificate error is present, the image is loaded and script executes.
-//
-// See the comment above SSLUITest.TestUnsafeContentsInWorkerWithUserException
-// for a discussion about the desired behavior.
 IN_PROC_BROWSER_TEST_F(SSLUITest, TestUnsafeContentsWithUserException) {
-  ASSERT_TRUE(https_server_.Start());
-  // Note that it is necessary to user https_server_mismatched_ here over the
-  // other invalid cert servers. This is because the test relies on the two
-  // servers having different hosts since SSL exceptions are per-host, not per
-  // origin, and https_server_mismatched_ uses 'localhost' rather than
-  // '127.0.0.1'.
-  ASSERT_TRUE(https_server_mismatched_.Start());
-
-  // Navigate to an unsafe site. Proceed with interstitial page to indicate
-  // the user approves the bad certificate.
-  ui_test_utils::NavigateToURL(
-      browser(), https_server_mismatched_.GetURL("/ssl/blank_page.html"));
   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
-  CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID,
-                                 AuthState::SHOWING_INTERSTITIAL);
-  ProceedThroughInterstitial(tab);
-  CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID,
-                                 AuthState::NONE);
-
-  std::string replacement_path;
-  GetFilePathWithHostAndPortReplacement(
-      "/ssl/page_with_unsafe_contents.html",
-      https_server_mismatched_.host_port_pair(), &replacement_path);
-  ui_test_utils::NavigateToURL(browser(),
-                               https_server_.GetURL(replacement_path));
-
-  // When the bad content is filtered, the state is expected to be
-  // authenticated.
-  CheckAuthenticatedState(tab, AuthState::NONE);
+  ASSERT_NO_FATAL_FAILURE(SetUpUnsafeContentsWithUserException(
+      "/ssl/page_with_unsafe_contents.html"));
+  CheckAuthenticationBrokenState(
+      tab, CertError::NONE,
+      AuthState::RAN_INSECURE_CONTENT | AuthState::DISPLAYED_INSECURE_CONTENT);
 
   int img_width;
   EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
@@ -2209,7 +2211,38 @@
   EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
       tab, "window.domAutomationController.send(IsFooSet());", &js_result));
   EXPECT_TRUE(js_result);
-  CheckAuthenticatedState(tab, CertError::NONE);
+
+  // Test that active subresources with the same certificate errors as
+  // the main resources don't cause mixed content UI downgrades. (Such
+  // errors would be confusing and duplicative.)
+  std::string replacement_path;
+  GetFilePathWithHostAndPortReplacement(
+      "/ssl/page_with_unsafe_contents.html",
+      https_server_mismatched_.host_port_pair(), &replacement_path);
+  ui_test_utils::NavigateToURL(
+      browser(), https_server_mismatched_.GetURL(replacement_path));
+  js_result = false;
+  EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+      tab, "window.domAutomationController.send(IsFooSet());", &js_result));
+  EXPECT_TRUE(js_result);
+  CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID,
+                                 AuthState::NONE);
+}
+
+// Like the test above, but only displaying inactive content (an image).
+IN_PROC_BROWSER_TEST_F(SSLUITest, TestUnsafeImageWithUserException) {
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_NO_FATAL_FAILURE(
+      SetUpUnsafeContentsWithUserException("/ssl/page_with_unsafe_image.html"));
+  CheckAuthenticatedState(tab, AuthState::DISPLAYED_INSECURE_CONTENT);
+
+  int img_width;
+  EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
+      tab, "window.domAutomationController.send(ImageWidth());", &img_width));
+  // In order to check that the image was loaded, we check its width.
+  // The actual image (Google logo) is 114 pixels wide, so we assume a good
+  // image is greater than 100.
+  EXPECT_GT(img_width, 100);
 }
 
 // Test that when the browser blocks displaying insecure content (images), the
diff --git a/chrome/browser/storage/durable_storage_permission_context.cc b/chrome/browser/storage/durable_storage_permission_context.cc
index 370d2ae..ccbb11b 100644
--- a/chrome/browser/storage/durable_storage_permission_context.cc
+++ b/chrome/browser/storage/durable_storage_permission_context.cc
@@ -17,6 +17,7 @@
 #include "components/content_settings/core/browser/website_settings_registry.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_security_policy.h"
+#include "content/public/browser/permission_type.h"
 #include "content/public/common/origin_util.h"
 #include "url/gurl.h"
 
@@ -24,7 +25,9 @@
 
 DurableStoragePermissionContext::DurableStoragePermissionContext(
     Profile* profile)
-    : PermissionContextBase(profile, CONTENT_SETTINGS_TYPE_DURABLE_STORAGE) {}
+    : PermissionContextBase(profile,
+                            content::PermissionType::DURABLE_STORAGE,
+                            CONTENT_SETTINGS_TYPE_DURABLE_STORAGE) {}
 
 void DurableStoragePermissionContext::DecidePermission(
     content::WebContents* web_contents,
diff --git a/chrome/browser/storage/durable_storage_permission_infobar_delegate_android.cc b/chrome/browser/storage/durable_storage_permission_infobar_delegate_android.cc
index de64590..2036ca47 100644
--- a/chrome/browser/storage/durable_storage_permission_infobar_delegate_android.cc
+++ b/chrome/browser/storage/durable_storage_permission_infobar_delegate_android.cc
@@ -18,21 +18,22 @@
     InfoBarService* infobar_service,
     const GURL& requesting_frame,
     const std::string& display_languages,
-    ContentSettingsType type,
     const PermissionSetCallback& callback) {
   return infobar_service->AddInfoBar(
       infobar_service->CreateConfirmInfoBar(scoped_ptr<ConfirmInfoBarDelegate>(
           new DurableStoragePermissionInfoBarDelegateAndroid(
-              requesting_frame, display_languages, type, callback))));
+              requesting_frame, display_languages, callback))));
 }
 
 DurableStoragePermissionInfoBarDelegateAndroid::
     DurableStoragePermissionInfoBarDelegateAndroid(
         const GURL& requesting_frame,
         const std::string& display_languages,
-        ContentSettingsType type,
         const PermissionSetCallback& callback)
-    : PermissionInfobarDelegate(requesting_frame, type, callback),
+    : PermissionInfobarDelegate(requesting_frame,
+                                content::PermissionType::DURABLE_STORAGE,
+                                CONTENT_SETTINGS_TYPE_DURABLE_STORAGE,
+                                callback),
       requesting_frame_(requesting_frame),
       display_languages_(display_languages) {}
 
diff --git a/chrome/browser/storage/durable_storage_permission_infobar_delegate_android.h b/chrome/browser/storage/durable_storage_permission_infobar_delegate_android.h
index 1a2d8021..a8b4829 100644
--- a/chrome/browser/storage/durable_storage_permission_infobar_delegate_android.h
+++ b/chrome/browser/storage/durable_storage_permission_infobar_delegate_android.h
@@ -23,14 +23,12 @@
   static infobars::InfoBar* Create(InfoBarService* infobar_service,
                                    const GURL& requesting_frame,
                                    const std::string& display_languages,
-                                   ContentSettingsType type,
                                    const PermissionSetCallback& callback);
 
  private:
   DurableStoragePermissionInfoBarDelegateAndroid(
       const GURL& requesting_frame,
       const std::string& display_languages,
-      ContentSettingsType type,
       const PermissionSetCallback& callback);
   ~DurableStoragePermissionInfoBarDelegateAndroid() override = default;
 
diff --git a/chrome/browser/sync/profile_sync_service_factory.cc b/chrome/browser/sync/profile_sync_service_factory.cc
index 6f16ae9..567bf7bb 100644
--- a/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/chrome/browser/sync/profile_sync_service_factory.cc
@@ -134,6 +134,8 @@
 
 KeyedService* ProfileSyncServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
+  ProfileSyncService::InitParams init_params;
+
   Profile* profile = Profile::FromBrowserContext(context);
 
   SigninManagerBase* signin = SigninManagerFactory::GetForProfile(profile);
@@ -147,10 +149,10 @@
   // once http://crbug.com/171406 has been fixed.
   AboutSigninInternalsFactory::GetForProfile(profile);
 
-  scoped_ptr<SigninManagerWrapper> signin_wrapper(
-      new SupervisedUserSigninManagerWrapper(profile, signin));
+  init_params.signin_wrapper =
+      make_scoped_ptr(new SupervisedUserSigninManagerWrapper(profile, signin));
 
-  ProfileOAuth2TokenService* token_service =
+  init_params.oauth2_token_service =
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
 
   // TODO(tim): Currently, AUTO/MANUAL settings refer to the *first* time sync
@@ -159,23 +161,27 @@
   // intervention). We can get rid of the browser_default eventually, but
   // need to take care that ProfileSyncService doesn't get tripped up between
   // those two cases. Bug 88109.
-  browser_sync::ProfileSyncServiceStartBehavior behavior =
-      browser_defaults::kSyncAutoStarts ? browser_sync::AUTO_START
-                                        : browser_sync::MANUAL_START;
+  init_params.start_behavior = browser_defaults::kSyncAutoStarts
+                                   ? browser_sync::AUTO_START
+                                   : browser_sync::MANUAL_START;
 
-  auto chrome_sync_client =
+  init_params.sync_client =
       make_scoped_ptr(new browser_sync::ChromeSyncClient(profile));
 
-  auto pss = make_scoped_ptr(new ProfileSyncService(
-      std::move(chrome_sync_client), std::move(signin_wrapper), token_service,
-      behavior, base::Bind(&UpdateNetworkTime), profile->GetPath(),
-      profile->GetRequestContext(), profile->GetDebugName(),
-      chrome::GetChannel(),
+  init_params.network_time_update_callback = base::Bind(&UpdateNetworkTime);
+  init_params.base_directory = profile->GetPath();
+  init_params.url_request_context = profile->GetRequestContext();
+  init_params.debug_identifier = profile->GetDebugName();
+  init_params.channel = chrome::GetChannel();
+
+  init_params.db_thread = content::BrowserThread::GetMessageLoopProxyForThread(
+      content::BrowserThread::DB);
+  init_params.file_thread =
       content::BrowserThread::GetMessageLoopProxyForThread(
-          content::BrowserThread::DB),
-      content::BrowserThread::GetMessageLoopProxyForThread(
-          content::BrowserThread::FILE),
-      content::BrowserThread::GetBlockingPool()));
+          content::BrowserThread::FILE);
+  init_params.blocking_pool = content::BrowserThread::GetBlockingPool();
+
+  auto pss = make_scoped_ptr(new ProfileSyncService(std::move(init_params)));
 
   // Will also initialize the sync client.
   pss->Initialize();
diff --git a/chrome/browser/sync/profile_sync_service_mock.cc b/chrome/browser/sync/profile_sync_service_mock.cc
index e5c8a3fb..a267d80a1 100644
--- a/chrome/browser/sync/profile_sync_service_mock.cc
+++ b/chrome/browser/sync/profile_sync_service_mock.cc
@@ -4,66 +4,14 @@
 
 #include "chrome/browser/sync/profile_sync_service_mock.h"
 
-#include "base/prefs/pref_service.h"
-#include "base/prefs/testing_pref_store.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
-#include "chrome/browser/sync/chrome_sync_client.h"
-#include "chrome/browser/sync/profile_sync_test_util.h"
-#include "chrome/common/channel_info.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
-#include "components/signin/core/browser/signin_manager.h"
-#include "components/sync_driver/signin_manager_wrapper.h"
-#include "components/sync_driver/sync_api_component_factory_mock.h"
+#include <utility>
 
-ProfileSyncServiceMock::ProfileSyncServiceMock(Profile* profile)
-    : ProfileSyncServiceMock(
-          make_scoped_ptr(new browser_sync::ChromeSyncClient(profile)),
-          profile) {
-  static_cast<browser_sync::ChromeSyncClient*>(GetSyncClient())
-      ->SetSyncApiComponentFactoryForTesting(
-          make_scoped_ptr(new SyncApiComponentFactoryMock()));
+ProfileSyncServiceMock::ProfileSyncServiceMock(InitParams init_params)
+    : ProfileSyncService(std::move(init_params)) {
+  ON_CALL(*this, IsSyncRequested()).WillByDefault(testing::Return(true));
 }
 
-ProfileSyncServiceMock::ProfileSyncServiceMock(
-    scoped_ptr<sync_driver::SyncClient> sync_client,
-    Profile* profile)
-    : ProfileSyncService(
-          sync_client.Pass(),
-          make_scoped_ptr(new SigninManagerWrapper(
-              SigninManagerFactory::GetForProfile(profile))),
-          ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
-          browser_sync::MANUAL_START,
-          base::Bind(&EmptyNetworkTimeUpdate),
-          profile->GetPath(),
-          profile->GetRequestContext(),
-          profile->GetDebugName(),
-          chrome::GetChannel(),
-          content::BrowserThread::GetMessageLoopProxyForThread(
-              content::BrowserThread::DB),
-          content::BrowserThread::GetMessageLoopProxyForThread(
-              content::BrowserThread::FILE),
-          content::BrowserThread::GetBlockingPool()) {
-    ON_CALL(*this, IsSyncRequested()).WillByDefault(testing::Return(true));
-}
+ProfileSyncServiceMock::ProfileSyncServiceMock(InitParams* init_params)
+    : ProfileSyncServiceMock(std::move(*init_params)) {}
 
-ProfileSyncServiceMock::~ProfileSyncServiceMock() {
-}
-
-// static
-TestingProfile* ProfileSyncServiceMock::MakeSignedInTestingProfile() {
-  TestingProfile* profile = new TestingProfile();
-  SigninManagerFactory::GetForProfile(profile)->
-      SetAuthenticatedAccountInfo("12345", "foo");
-  return profile;
-}
-
-// static
-scoped_ptr<KeyedService> ProfileSyncServiceMock::BuildMockProfileSyncService(
-    content::BrowserContext* profile) {
-  return make_scoped_ptr(
-      new ProfileSyncServiceMock(static_cast<Profile*>(profile)));
-}
+ProfileSyncServiceMock::~ProfileSyncServiceMock() {}
diff --git a/chrome/browser/sync/profile_sync_service_mock.h b/chrome/browser/sync/profile_sync_service_mock.h
index d1a4528..4527c6f 100644
--- a/chrome/browser/sync/profile_sync_service_mock.h
+++ b/chrome/browser/sync/profile_sync_service_mock.h
@@ -8,10 +8,8 @@
 #include <string>
 #include <vector>
 
-#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
-#include "chrome/test/base/testing_profile.h"
 #include "components/browser_sync/browser/profile_sync_service.h"
 #include "components/sync_driver/change_processor.h"
 #include "components/sync_driver/data_type_controller.h"
@@ -21,42 +19,24 @@
 #include "sync/protocol/sync_protocol_error.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
-using ::testing::Invoke;
-
-namespace sync_driver {
-class SyncClient;
-}
-
 class ProfileSyncServiceMock : public ProfileSyncService {
  public:
-  explicit ProfileSyncServiceMock(Profile* profile);
-  ProfileSyncServiceMock(scoped_ptr<sync_driver::SyncClient> sync_client,
-                         Profile* profile);
+  explicit ProfileSyncServiceMock(InitParams init_params);
+  // The second constructor defers to the first one. Use it when you need to
+  // create a StrictMock or NiceMock of ProfileSyncServiceMock, because those
+  // template classes cannot handle the input class having constructors with
+  // arguments passed by value. Otherwise use the constructor above for cleaner
+  // code.
+  explicit ProfileSyncServiceMock(InitParams* init_params);
+
   virtual ~ProfileSyncServiceMock();
 
-  // A utility used by sync tests to create a TestingProfile with a Google
-  // Services username stored in a (Testing)PrefService.
-  static TestingProfile* MakeSignedInTestingProfile();
-
-  // Helper routine to be used in conjunction with
-  // BrowserContextKeyedServiceFactory::SetTestingFactory().
-  static scoped_ptr<KeyedService> BuildMockProfileSyncService(
-      content::BrowserContext* profile);
-
   MOCK_METHOD4(OnBackendInitialized,
       void(const syncer::WeakHandle<syncer::JsBackend>&,
            const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&,
            const std::string&,
            bool));
   MOCK_METHOD0(OnSyncCycleCompleted, void());
-  MOCK_METHOD0(OnAuthError, void());
-  MOCK_METHOD4(OnUserSubmittedAuth,
-               void(const std::string& username,
-                    const std::string& password,
-                    const std::string& captcha,
-                    const std::string& access_code));
-  MOCK_METHOD0(OnUserCancelledDialog, void());
-  MOCK_CONST_METHOD0(GetAuthenticatedUsername, base::string16());
   MOCK_METHOD2(OnUserChoseDatatypes,
                void(bool sync_everything,
                     syncer::ModelTypeSet chosen_types));
@@ -64,7 +44,6 @@
   MOCK_METHOD2(OnUnrecoverableError,
                void(const tracked_objects::Location& location,
                const std::string& message));
-  MOCK_METHOD1(DisableDatatype, void(const syncer::SyncError&));
   MOCK_CONST_METHOD0(GetUserShare, syncer::UserShare*());
   MOCK_METHOD0(RequestStart, void());
   MOCK_METHOD1(RequestStop, void(ProfileSyncService::SyncStopDataFate));
@@ -101,7 +80,6 @@
   MOCK_CONST_METHOD1(IsDataTypeControllerRunning, bool(syncer::ModelType));
 
   // DataTypeManagerObserver mocks.
-  MOCK_METHOD0(OnConfigureBlocked, void());
   MOCK_METHOD1(OnConfigureDone,
                void(const sync_driver::DataTypeManager::ConfigureResult&));
   MOCK_METHOD0(OnConfigureStart, void());
@@ -114,7 +92,6 @@
   MOCK_CONST_METHOD0(IsPassphraseRequiredForDecryption, bool());
   MOCK_CONST_METHOD0(IsUsingSecondaryPassphrase, bool());
   MOCK_CONST_METHOD0(GetPassphraseType, syncer::PassphraseType());
-  MOCK_CONST_METHOD0(GetPassphraseTime, base::Time());
   MOCK_CONST_METHOD0(GetExplicitPassphraseTime, base::Time());
 
   MOCK_METHOD1(SetDecryptionPassphrase, bool(const std::string& passphrase));
diff --git a/chrome/browser/sync/profile_sync_service_startup_unittest.cc b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
index 7c3afc81..57bbb39 100644
--- a/chrome/browser/sync/profile_sync_service_startup_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/files/file_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
@@ -59,6 +61,34 @@
 const char kEmail[] = "test_user@gmail.com";
 const char kDummyPassword[] = "";
 
+ProfileSyncService::InitParams GetInitParams(
+    scoped_ptr<sync_driver::SyncClient> sync_client,
+    Profile* profile,
+    scoped_ptr<SigninManagerWrapper> signin_wrapper,
+    ProfileOAuth2TokenService* oauth2_token_service,
+    browser_sync::ProfileSyncServiceStartBehavior start_behavior) {
+  ProfileSyncService::InitParams init_params;
+
+  init_params.signin_wrapper = std::move(signin_wrapper);
+  init_params.oauth2_token_service = oauth2_token_service;
+  init_params.start_behavior = start_behavior;
+  init_params.sync_client = std::move(sync_client);
+  init_params.network_time_update_callback =
+      base::Bind(&EmptyNetworkTimeUpdate);
+  init_params.base_directory = profile->GetPath();
+  init_params.url_request_context = profile->GetRequestContext();
+  init_params.debug_identifier = profile->GetDebugName();
+  init_params.channel = chrome::GetChannel();
+  init_params.db_thread = content::BrowserThread::GetMessageLoopProxyForThread(
+      content::BrowserThread::DB);
+  init_params.file_thread =
+      content::BrowserThread::GetMessageLoopProxyForThread(
+          content::BrowserThread::FILE);
+  init_params.blocking_pool = content::BrowserThread::GetBlockingPool();
+
+  return init_params;
+}
+
 }  // namespace
 
 ACTION_P(InvokeOnConfigureStart, pss) {
@@ -85,20 +115,11 @@
       scoped_ptr<SigninManagerWrapper> signin_wrapper,
       ProfileOAuth2TokenService* oauth2_token_service,
       browser_sync::ProfileSyncServiceStartBehavior start_behavior)
-      : ProfileSyncService(sync_client.Pass(),
-                           signin_wrapper.Pass(),
-                           oauth2_token_service,
-                           start_behavior,
-                           base::Bind(&EmptyNetworkTimeUpdate),
-                           profile->GetPath(),
-                           profile->GetRequestContext(),
-                           profile->GetDebugName(),
-                           chrome::GetChannel(),
-                           content::BrowserThread::GetMessageLoopProxyForThread(
-                               content::BrowserThread::DB),
-                           content::BrowserThread::GetMessageLoopProxyForThread(
-                               content::BrowserThread::FILE),
-                           content::BrowserThread::GetBlockingPool()) {}
+      : ProfileSyncService(GetInitParams(std::move(sync_client),
+                                         profile,
+                                         std::move(signin_wrapper),
+                                         oauth2_token_service,
+                                         start_behavior)) {}
 
  protected:
   bool NeedBackup() const override { return false; }
diff --git a/chrome/browser/sync/profile_sync_test_util.cc b/chrome/browser/sync/profile_sync_test_util.cc
index 221af6d..143ca63 100644
--- a/chrome/browser/sync/profile_sync_test_util.cc
+++ b/chrome/browser/sync/profile_sync_test_util.cc
@@ -8,6 +8,17 @@
 #include "base/location.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/sync/chrome_sync_client.h"
+#include "chrome/common/channel_info.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/browser_sync/browser/profile_sync_service.h"
+#include "components/signin/core/browser/signin_manager.h"
+#include "components/sync_driver/signin_manager_wrapper.h"
+#include "components/sync_driver/startup_controller.h"
+#include "components/sync_driver/sync_api_component_factory_mock.h"
 
 using content::BrowserThread;
 
@@ -48,3 +59,58 @@
   content::NotificationService::current()->Notify(type, source, details);
   done_event_.Signal();
 }
+
+ProfileSyncService::InitParams CreateProfileSyncServiceParamsForTest(
+    Profile* profile) {
+  auto sync_client =
+      make_scoped_ptr(new browser_sync::ChromeSyncClient(profile));
+
+  sync_client->SetSyncApiComponentFactoryForTesting(
+      make_scoped_ptr(new SyncApiComponentFactoryMock()));
+
+  ProfileSyncService::InitParams init_params =
+      CreateProfileSyncServiceParamsForTest(std::move(sync_client), profile);
+
+  return init_params;
+}
+
+ProfileSyncService::InitParams CreateProfileSyncServiceParamsForTest(
+    scoped_ptr<sync_driver::SyncClient> sync_client,
+    Profile* profile) {
+  ProfileSyncService::InitParams init_params;
+
+  init_params.signin_wrapper = make_scoped_ptr(
+      new SigninManagerWrapper(SigninManagerFactory::GetForProfile(profile)));
+  init_params.oauth2_token_service =
+      ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
+  init_params.start_behavior = browser_sync::MANUAL_START;
+  init_params.sync_client = std::move(sync_client);
+  init_params.network_time_update_callback =
+      base::Bind(&EmptyNetworkTimeUpdate);
+  init_params.base_directory = profile->GetPath();
+  init_params.url_request_context = profile->GetRequestContext();
+  init_params.debug_identifier = profile->GetDebugName();
+  init_params.channel = chrome::GetChannel();
+  init_params.db_thread = content::BrowserThread::GetMessageLoopProxyForThread(
+      content::BrowserThread::DB);
+  init_params.file_thread =
+      content::BrowserThread::GetMessageLoopProxyForThread(
+          content::BrowserThread::FILE);
+  init_params.blocking_pool = content::BrowserThread::GetBlockingPool();
+
+  return init_params;
+}
+
+scoped_ptr<TestingProfile> MakeSignedInTestingProfile() {
+  auto profile = make_scoped_ptr(new TestingProfile());
+  SigninManagerFactory::GetForProfile(profile.get())
+      ->SetAuthenticatedAccountInfo("12345", "foo");
+  return profile;
+}
+
+scoped_ptr<KeyedService> BuildMockProfileSyncService(
+    content::BrowserContext* context) {
+  return make_scoped_ptr(
+      new ProfileSyncServiceMock(CreateProfileSyncServiceParamsForTest(
+          Profile::FromBrowserContext(context))));
+}
diff --git a/chrome/browser/sync/profile_sync_test_util.h b/chrome/browser/sync/profile_sync_test_util.h
index c884d1d..e3dfe1a1 100644
--- a/chrome/browser/sync/profile_sync_test_util.h
+++ b/chrome/browser/sync/profile_sync_test_util.h
@@ -8,8 +8,10 @@
 #include <string>
 
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/synchronization/waitable_event.h"
+#include "chrome/browser/sync/profile_sync_service_mock.h"
 #include "components/sync_driver/sync_service_observer.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
@@ -23,6 +25,19 @@
 class TimeDelta;
 }
 
+namespace content {
+class BrowserContext;
+}
+
+namespace sync_driver {
+class SyncClient;
+}
+
+class KeyedService;
+class Profile;
+class ProfileSyncServiceMock;
+class TestingProfile;
+
 // An empty syncer::NetworkTimeUpdateCallback. Used in various tests to
 // instantiate ProfileSyncService.
 void EmptyNetworkTimeUpdate(const base::Time&,
@@ -72,4 +87,20 @@
   base::Thread* notify_thread_;
 };
 
+// Helper methods for constructing ProfileSyncService mocks.
+ProfileSyncService::InitParams CreateProfileSyncServiceParamsForTest(
+    Profile* profile);
+ProfileSyncService::InitParams CreateProfileSyncServiceParamsForTest(
+    scoped_ptr<sync_driver::SyncClient> sync_client,
+    Profile* profile);
+
+// A utility used by sync tests to create a TestingProfile with a Google
+// Services username stored in a (Testing)PrefService.
+scoped_ptr<TestingProfile> MakeSignedInTestingProfile();
+
+// Helper routine to be used in conjunction with
+// BrowserContextKeyedServiceFactory::SetTestingFactory().
+scoped_ptr<KeyedService> BuildMockProfileSyncService(
+    content::BrowserContext* context);
+
 #endif  // CHROME_BROWSER_SYNC_PROFILE_SYNC_TEST_UTIL_H_
diff --git a/chrome/browser/sync/sync_error_notifier_ash_unittest.cc b/chrome/browser/sync/sync_error_notifier_ash_unittest.cc
index f5ba371..9284b6e 100644
--- a/chrome/browser/sync/sync_error_notifier_ash_unittest.cc
+++ b/chrome/browser/sync/sync_error_notifier_ash_unittest.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/notifications/notification.h"
 #include "chrome/browser/notifications/notification_ui_manager.h"
 #include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/browser/sync/profile_sync_test_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
@@ -110,7 +111,8 @@
     gfx::Screen::SetScreenTypeDelegate(&screen_type_delegate_);
 #endif
 
-    service_.reset(new NiceMock<ProfileSyncServiceMock>(profile_));
+    service_.reset(new ProfileSyncServiceMock(
+        CreateProfileSyncServiceParamsForTest(profile_)));
 
     FakeLoginUIService* login_ui_service = static_cast<FakeLoginUIService*>(
         LoginUIServiceFactory::GetInstance()->SetTestingFactoryAndUse(
@@ -173,15 +175,16 @@
   scoped_ptr<TestingProfileManager> profile_manager_;
   scoped_ptr<SyncErrorController> error_controller_;
   scoped_ptr<SyncErrorNotifier> error_notifier_;
-  scoped_ptr<NiceMock<ProfileSyncServiceMock> > service_;
+  scoped_ptr<ProfileSyncServiceMock> service_;
   TestingProfile* profile_;
   FakeLoginUI login_ui_;
   NotificationUIManager* notification_ui_manager_;
 
+ private:
   DISALLOW_COPY_AND_ASSIGN(SyncErrorNotifierTest);
 };
 
-} // namespace
+}  // namespace
 
 // Test that SyncErrorNotifier shows an notification if a passphrase is
 // required.
diff --git a/chrome/browser/sync/sync_global_error_unittest.cc b/chrome/browser/sync/sync_global_error_unittest.cc
index 2dba9e0c..80836d8 100644
--- a/chrome/browser/sync/sync_global_error_unittest.cc
+++ b/chrome/browser/sync/sync_global_error_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/browser/sync/profile_sync_test_util.h"
 #include "chrome/browser/sync/sync_global_error_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
@@ -62,7 +62,7 @@
   ~SyncGlobalErrorTest() override {}
 
   void SetUp() override {
-    profile_.reset(ProfileSyncServiceMock::MakeSignedInTestingProfile());
+    profile_ = MakeSignedInTestingProfile();
 
     BrowserWithTestWindowTest::SetUp();
   }
@@ -77,7 +77,7 @@
 
 // Utility function to test that SyncGlobalError behaves correctly for the given
 // error condition.
-void VerifySyncGlobalErrorResult(NiceMock<ProfileSyncServiceMock>* service,
+void VerifySyncGlobalErrorResult(ProfileSyncServiceMock* service,
                                  FakeLoginUIService* login_ui_service,
                                  Browser* browser,
                                  SyncErrorController* error,
@@ -119,11 +119,12 @@
   }
 }
 
-} // namespace
+}  // namespace
 
 // Test that SyncGlobalError shows an error if a passphrase is required.
 TEST_F(SyncGlobalErrorTest, PassphraseGlobalError) {
-  NiceMock<ProfileSyncServiceMock> service(profile());
+  ProfileSyncServiceMock service(
+      CreateProfileSyncServiceParamsForTest(profile()));
 
   FakeLoginUIService* login_ui_service = static_cast<FakeLoginUIService*>(
       LoginUIServiceFactory::GetInstance()->SetTestingFactoryAndUse(
diff --git a/chrome/browser/sync/sync_startup_tracker_unittest.cc b/chrome/browser/sync/sync_startup_tracker_unittest.cc
index cd49e63..f3e8bd0 100644
--- a/chrome/browser/sync/sync_startup_tracker_unittest.cc
+++ b/chrome/browser/sync/sync_startup_tracker_unittest.cc
@@ -4,8 +4,9 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/browser/sync/profile_sync_test_util.h"
 #include "chrome/browser/sync/sync_startup_tracker.h"
+#include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -33,8 +34,7 @@
     profile_.reset(new TestingProfile());
     mock_pss_ = static_cast<ProfileSyncServiceMock*>(
         ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-            profile_.get(),
-            ProfileSyncServiceMock::BuildMockProfileSyncService));
+            profile_.get(), BuildMockProfileSyncService));
 
     // Make gmock not spam the output with information about these uninteresting
     // calls.
diff --git a/chrome/browser/sync/sync_ui_util_unittest.cc b/chrome/browser/sync/sync_ui_util_unittest.cc
index 7b58c11..4d18c0a 100644
--- a/chrome/browser/sync/sync_ui_util_unittest.cc
+++ b/chrome/browser/sync/sync_ui_util_unittest.cc
@@ -10,8 +10,10 @@
 #include "chrome/browser/signin/chrome_signin_client_factory.h"
 #include "chrome/browser/signin/signin_error_controller_factory.h"
 #include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/browser/sync/profile_sync_test_util.h"
 #include "chrome/browser/sync/sync_ui_util.h"
 #include "chrome/grit/generated_resources.h"
+#include "chrome/test/base/testing_profile.h"
 #include "components/signin/core/browser/fake_auth_status_provider.h"
 #include "components/signin/core/browser/fake_signin_manager.h"
 #include "components/signin/core/browser/signin_manager.h"
@@ -52,7 +54,7 @@
 #if !defined(OS_CHROMEOS)
 // Utility function to test that GetStatusLabelsForSyncGlobalError returns
 // the correct results for the given states.
-void VerifySyncGlobalErrorResult(NiceMock<ProfileSyncServiceMock>* service,
+void VerifySyncGlobalErrorResult(ProfileSyncServiceMock* service,
                                  GoogleServiceAuthError::State error_state,
                                  bool is_signed_in,
                                  bool is_error) {
@@ -71,8 +73,7 @@
 }
 #endif
 
-} // namespace
-
+}  // namespace
 
 class SyncUIUtilTest : public testing::Test {
  private:
@@ -83,9 +84,9 @@
 // Test that GetStatusLabelsForSyncGlobalError returns an error if a
 // passphrase is required.
 TEST_F(SyncUIUtilTest, PassphraseGlobalError) {
-  scoped_ptr<Profile> profile(
-      ProfileSyncServiceMock::MakeSignedInTestingProfile());
-  NiceMock<ProfileSyncServiceMock> service(profile.get());
+  scoped_ptr<Profile> profile = MakeSignedInTestingProfile();
+  ProfileSyncServiceMock service(
+      CreateProfileSyncServiceParamsForTest(profile.get()));
   browser_sync::SyncBackendHost::Status status;
   EXPECT_CALL(service, QueryDetailedSyncStatus(_))
               .WillRepeatedly(Return(false));
@@ -103,9 +104,9 @@
 // Test that GetStatusLabelsForSyncGlobalError returns an error if a
 // passphrase is required and not for auth errors.
 TEST_F(SyncUIUtilTest, AuthAndPassphraseGlobalError) {
-  scoped_ptr<Profile> profile(
-      ProfileSyncServiceMock::MakeSignedInTestingProfile());
-  NiceMock<ProfileSyncServiceMock> service(profile.get());
+  scoped_ptr<Profile> profile(MakeSignedInTestingProfile());
+  ProfileSyncServiceMock service(
+      CreateProfileSyncServiceParamsForTest(profile.get()));
   browser_sync::SyncBackendHost::Status status;
   EXPECT_CALL(service, QueryDetailedSyncStatus(_))
               .WillRepeatedly(Return(false));
@@ -132,9 +133,10 @@
 // Test that GetStatusLabelsForSyncGlobalError does not indicate errors for
 // auth errors (these are reported through SigninGlobalError).
 TEST_F(SyncUIUtilTest, AuthStateGlobalError) {
-  scoped_ptr<Profile> profile(
-      ProfileSyncServiceMock::MakeSignedInTestingProfile());
-  NiceMock<ProfileSyncServiceMock> service(profile.get());
+  scoped_ptr<Profile> profile(MakeSignedInTestingProfile());
+  ProfileSyncService::InitParams init_params =
+      CreateProfileSyncServiceParamsForTest(profile.get());
+  NiceMock<ProfileSyncServiceMock> service(&init_params);
 
   browser_sync::SyncBackendHost::Status status;
   EXPECT_CALL(service, QueryDetailedSyncStatus(_))
@@ -202,7 +204,7 @@
 
 // Loads a ProfileSyncServiceMock to emulate one of a number of distinct cases
 // in order to perform tests on the generated messages.
-void GetDistinctCase(ProfileSyncServiceMock& service,
+void GetDistinctCase(ProfileSyncServiceMock* service,
                      FakeSigninManagerForSyncUIUtilTest* signin,
                      FakeAuthStatusProvider* provider,
                      int caseNumber) {
@@ -211,123 +213,115 @@
   // immutable so can only be allocated in this method.
   switch (caseNumber) {
     case STATUS_CASE_SETUP_IN_PROGRESS: {
-      EXPECT_CALL(service, HasSyncSetupCompleted())
-                  .WillRepeatedly(Return(false));
-      EXPECT_CALL(service, IsFirstSetupInProgress())
-                  .WillRepeatedly(Return(true));
+      EXPECT_CALL(*service, HasSyncSetupCompleted())
+          .WillRepeatedly(Return(false));
+      EXPECT_CALL(*service, IsFirstSetupInProgress())
+          .WillRepeatedly(Return(true));
       browser_sync::SyncBackendHost::Status status;
-      EXPECT_CALL(service, QueryDetailedSyncStatus(_))
-                  .WillRepeatedly(DoAll(SetArgPointee<0>(status),
-                                  Return(false)));
+      EXPECT_CALL(*service, QueryDetailedSyncStatus(_))
+          .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false)));
       return;
     }
-   case STATUS_CASE_SETUP_ERROR: {
-      EXPECT_CALL(service, HasSyncSetupCompleted())
-                  .WillRepeatedly(Return(false));
-      EXPECT_CALL(service, IsFirstSetupInProgress())
-                  .WillRepeatedly(Return(false));
-      EXPECT_CALL(service, HasUnrecoverableError())
-                  .WillRepeatedly(Return(true));
+    case STATUS_CASE_SETUP_ERROR: {
+      EXPECT_CALL(*service, HasSyncSetupCompleted())
+          .WillRepeatedly(Return(false));
+      EXPECT_CALL(*service, IsFirstSetupInProgress())
+          .WillRepeatedly(Return(false));
+      EXPECT_CALL(*service, HasUnrecoverableError())
+          .WillRepeatedly(Return(true));
       browser_sync::SyncBackendHost::Status status;
-      EXPECT_CALL(service, QueryDetailedSyncStatus(_))
-                  .WillRepeatedly(DoAll(SetArgPointee<0>(status),
-                                  Return(false)));
+      EXPECT_CALL(*service, QueryDetailedSyncStatus(_))
+          .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false)));
       return;
     }
     case STATUS_CASE_AUTHENTICATING: {
-      EXPECT_CALL(service, HasSyncSetupCompleted())
-                  .WillRepeatedly(Return(true));
-      EXPECT_CALL(service, IsSyncActive()).WillRepeatedly(Return(true));
-      EXPECT_CALL(service, IsPassphraseRequired())
-                  .WillRepeatedly(Return(false));
+      EXPECT_CALL(*service, HasSyncSetupCompleted())
+          .WillRepeatedly(Return(true));
+      EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true));
+      EXPECT_CALL(*service, IsPassphraseRequired())
+          .WillRepeatedly(Return(false));
       browser_sync::SyncBackendHost::Status status;
-      EXPECT_CALL(service, QueryDetailedSyncStatus(_))
-                  .WillRepeatedly(DoAll(SetArgPointee<0>(status),
-                                  Return(false)));
-      EXPECT_CALL(service, HasUnrecoverableError())
-                  .WillRepeatedly(Return(false));
+      EXPECT_CALL(*service, QueryDetailedSyncStatus(_))
+          .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false)));
+      EXPECT_CALL(*service, HasUnrecoverableError())
+          .WillRepeatedly(Return(false));
       signin->set_auth_in_progress();
       return;
     }
     case STATUS_CASE_AUTH_ERROR: {
-      EXPECT_CALL(service, HasSyncSetupCompleted())
-                  .WillRepeatedly(Return(true));
-      EXPECT_CALL(service, IsSyncActive()).WillRepeatedly(Return(true));
-      EXPECT_CALL(service, IsPassphraseRequired())
-                  .WillRepeatedly(Return(false));
+      EXPECT_CALL(*service, HasSyncSetupCompleted())
+          .WillRepeatedly(Return(true));
+      EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true));
+      EXPECT_CALL(*service, IsPassphraseRequired())
+          .WillRepeatedly(Return(false));
       browser_sync::SyncBackendHost::Status status;
-      EXPECT_CALL(service, QueryDetailedSyncStatus(_))
-                  .WillRepeatedly(DoAll(SetArgPointee<0>(status),
-                                  Return(false)));
+      EXPECT_CALL(*service, QueryDetailedSyncStatus(_))
+          .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false)));
       provider->SetAuthError(
           signin->GetAuthenticatedAccountId(),
           GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE));
-      EXPECT_CALL(service, HasUnrecoverableError())
-                  .WillRepeatedly(Return(false));
+      EXPECT_CALL(*service, HasUnrecoverableError())
+          .WillRepeatedly(Return(false));
       return;
     }
     case STATUS_CASE_PROTOCOL_ERROR: {
-      EXPECT_CALL(service, HasSyncSetupCompleted())
-                  .WillRepeatedly(Return(true));
-      EXPECT_CALL(service, IsSyncActive()).WillRepeatedly(Return(true));
-      EXPECT_CALL(service, IsPassphraseRequired())
-                  .WillRepeatedly(Return(false));
+      EXPECT_CALL(*service, HasSyncSetupCompleted())
+          .WillRepeatedly(Return(true));
+      EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true));
+      EXPECT_CALL(*service, IsPassphraseRequired())
+          .WillRepeatedly(Return(false));
       syncer::SyncProtocolError protocolError;
       protocolError.action = syncer::STOP_AND_RESTART_SYNC;
       browser_sync::SyncBackendHost::Status status;
       status.sync_protocol_error = protocolError;
-      EXPECT_CALL(service, QueryDetailedSyncStatus(_))
-                  .WillRepeatedly(DoAll(SetArgPointee<0>(status),
-                                  Return(false)));
-      EXPECT_CALL(service, HasUnrecoverableError())
-                  .WillRepeatedly(Return(false));
+      EXPECT_CALL(*service, QueryDetailedSyncStatus(_))
+          .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false)));
+      EXPECT_CALL(*service, HasUnrecoverableError())
+          .WillRepeatedly(Return(false));
       return;
     }
     case STATUS_CASE_PASSPHRASE_ERROR: {
-      EXPECT_CALL(service, HasSyncSetupCompleted())
-                  .WillRepeatedly(Return(true));
-      EXPECT_CALL(service, IsSyncActive()).WillRepeatedly(Return(true));
+      EXPECT_CALL(*service, HasSyncSetupCompleted())
+          .WillRepeatedly(Return(true));
+      EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true));
       browser_sync::SyncBackendHost::Status status;
-      EXPECT_CALL(service, QueryDetailedSyncStatus(_))
-                  .WillRepeatedly(DoAll(SetArgPointee<0>(status),
-                                  Return(false)));
-      EXPECT_CALL(service, HasUnrecoverableError())
-                  .WillRepeatedly(Return(false));
-      EXPECT_CALL(service, IsPassphraseRequired())
-                  .WillRepeatedly(Return(true));
-      EXPECT_CALL(service, IsPassphraseRequiredForDecryption())
-                  .WillRepeatedly(Return(true));
+      EXPECT_CALL(*service, QueryDetailedSyncStatus(_))
+          .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false)));
+      EXPECT_CALL(*service, HasUnrecoverableError())
+          .WillRepeatedly(Return(false));
+      EXPECT_CALL(*service, IsPassphraseRequired())
+          .WillRepeatedly(Return(true));
+      EXPECT_CALL(*service, IsPassphraseRequiredForDecryption())
+          .WillRepeatedly(Return(true));
       return;
     }
     case STATUS_CASE_SYNCED: {
-      EXPECT_CALL(service, HasSyncSetupCompleted())
-              .WillRepeatedly(Return(true));
-      EXPECT_CALL(service, IsSyncActive()).WillRepeatedly(Return(true));
-      EXPECT_CALL(service, IsPassphraseRequired())
-                  .WillRepeatedly(Return(false));
+      EXPECT_CALL(*service, HasSyncSetupCompleted())
+          .WillRepeatedly(Return(true));
+      EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true));
+      EXPECT_CALL(*service, IsPassphraseRequired())
+          .WillRepeatedly(Return(false));
       browser_sync::SyncBackendHost::Status status;
-      EXPECT_CALL(service, QueryDetailedSyncStatus(_))
-                  .WillRepeatedly(DoAll(SetArgPointee<0>(status),
-                                  Return(false)));
-      EXPECT_CALL(service, HasUnrecoverableError())
-                  .WillRepeatedly(Return(false));
-      EXPECT_CALL(service, IsPassphraseRequired())
-                  .WillRepeatedly(Return(false));
+      EXPECT_CALL(*service, QueryDetailedSyncStatus(_))
+          .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false)));
+      EXPECT_CALL(*service, HasUnrecoverableError())
+          .WillRepeatedly(Return(false));
+      EXPECT_CALL(*service, IsPassphraseRequired())
+          .WillRepeatedly(Return(false));
       return;
     }
     case STATUS_CASE_SYNC_DISABLED_BY_POLICY: {
-      EXPECT_CALL(service, IsManaged()).WillRepeatedly(Return(true));
-      EXPECT_CALL(service, HasSyncSetupCompleted())
+      EXPECT_CALL(*service, IsManaged()).WillRepeatedly(Return(true));
+      EXPECT_CALL(*service, HasSyncSetupCompleted())
           .WillRepeatedly(Return(false));
-      EXPECT_CALL(service, IsSyncActive()).WillRepeatedly(Return(false));
-      EXPECT_CALL(service, IsPassphraseRequired())
-                  .WillRepeatedly(Return(false));
+      EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(false));
+      EXPECT_CALL(*service, IsPassphraseRequired())
+          .WillRepeatedly(Return(false));
       browser_sync::SyncBackendHost::Status status;
-      EXPECT_CALL(service, QueryDetailedSyncStatus(_))
-                  .WillRepeatedly(DoAll(SetArgPointee<0>(status),
-                                  Return(false)));
-      EXPECT_CALL(service, HasUnrecoverableError())
-                  .WillRepeatedly(Return(false));
+      EXPECT_CALL(*service, QueryDetailedSyncStatus(_))
+          .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false)));
+      EXPECT_CALL(*service, HasUnrecoverableError())
+          .WillRepeatedly(Return(false));
       return;
     }
     default:
@@ -342,14 +336,16 @@
   std::set<base::string16> messages;
   for (int idx = 0; idx != NUMBER_OF_STATUS_CASES; idx++) {
     scoped_ptr<Profile> profile(new TestingProfile());
-    ProfileSyncServiceMock service(profile.get());
+    ProfileSyncService::InitParams init_params =
+        CreateProfileSyncServiceParamsForTest(profile.get());
+    NiceMock<ProfileSyncServiceMock> service(&init_params);
     GoogleServiceAuthError error = GoogleServiceAuthError::AuthErrorNone();
     EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(error));
     FakeSigninManagerForSyncUIUtilTest signin(profile.get());
     signin.SetAuthenticatedAccountInfo(kTestGaiaId, kTestUser);
     scoped_ptr<FakeAuthStatusProvider> provider(new FakeAuthStatusProvider(
         SigninErrorControllerFactory::GetForProfile(profile.get())));
-    GetDistinctCase(service, &signin, provider.get(), idx);
+    GetDistinctCase(&service, &signin, provider.get(), idx);
     base::string16 status_label;
     base::string16 link_label;
     sync_ui_util::GetStatusLabels(profile.get(), &service, signin,
@@ -377,16 +373,17 @@
 // honored.
 TEST_F(SyncUIUtilTest, HtmlNotIncludedInStatusIfNotRequested) {
   for (int idx = 0; idx != NUMBER_OF_STATUS_CASES; idx++) {
-    scoped_ptr<Profile> profile(
-        ProfileSyncServiceMock::MakeSignedInTestingProfile());
-    ProfileSyncServiceMock service(profile.get());
+    scoped_ptr<Profile> profile(MakeSignedInTestingProfile());
+    ProfileSyncService::InitParams init_params =
+        CreateProfileSyncServiceParamsForTest(profile.get());
+    NiceMock<ProfileSyncServiceMock> service(&init_params);
     GoogleServiceAuthError error = GoogleServiceAuthError::AuthErrorNone();
     EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(error));
     FakeSigninManagerForSyncUIUtilTest signin(profile.get());
     signin.SetAuthenticatedAccountInfo(kTestGaiaId, kTestUser);
     scoped_ptr<FakeAuthStatusProvider> provider(new FakeAuthStatusProvider(
         SigninErrorControllerFactory::GetForProfile(profile.get())));
-    GetDistinctCase(service, &signin, provider.get(), idx);
+    GetDistinctCase(&service, &signin, provider.get(), idx);
     base::string16 status_label;
     base::string16 link_label;
     sync_ui_util::GetStatusLabels(profile.get(), &service, signin,
diff --git a/chrome/browser/sync/test_profile_sync_service.cc b/chrome/browser/sync/test_profile_sync_service.cc
index 2a724d8..9a9bb71 100644
--- a/chrome/browser/sync/test_profile_sync_service.cc
+++ b/chrome/browser/sync/test_profile_sync_service.cc
@@ -37,6 +37,26 @@
 using syncer::TestInternalComponentsFactory;
 using syncer::UserShare;
 
+namespace {
+
+ProfileSyncService::InitParams GetInitParams(
+    Profile* profile,
+    SigninManagerBase* signin,
+    ProfileOAuth2TokenService* oauth2_token_service,
+    browser_sync::ProfileSyncServiceStartBehavior behavior) {
+  ProfileSyncService::InitParams init_params =
+      CreateProfileSyncServiceParamsForTest(profile);
+
+  init_params.signin_wrapper =
+      make_scoped_ptr(new SigninManagerWrapper(signin));
+  init_params.oauth2_token_service = oauth2_token_service;
+  init_params.start_behavior = behavior;
+
+  return init_params;
+}
+
+}  // namespace
+
 namespace browser_sync {
 
 SyncBackendHostForProfileSyncTest::SyncBackendHostForProfileSyncTest(
@@ -127,20 +147,7 @@
     ProfileOAuth2TokenService* oauth2_token_service,
     browser_sync::ProfileSyncServiceStartBehavior behavior)
     : ProfileSyncService(
-          make_scoped_ptr(new browser_sync::ChromeSyncClient(profile)),
-          make_scoped_ptr(new SigninManagerWrapper(signin)),
-          oauth2_token_service,
-          behavior,
-          base::Bind(&EmptyNetworkTimeUpdate),
-          profile->GetPath(),
-          profile->GetRequestContext(),
-          profile->GetDebugName(),
-          chrome::GetChannel(),
-          content::BrowserThread::GetMessageLoopProxyForThread(
-              content::BrowserThread::DB),
-          content::BrowserThread::GetMessageLoopProxyForThread(
-              content::BrowserThread::FILE),
-          content::BrowserThread::GetBlockingPool()) {
+          GetInitParams(profile, signin, oauth2_token_service, behavior)) {
   static_cast<browser_sync::ChromeSyncClient*>(GetSyncClient())
       ->SetSyncApiComponentFactoryForTesting(
           make_scoped_ptr(new SyncApiComponentFactoryMock));
diff --git a/chrome/browser/tab_contents/view_source_browsertest.cc b/chrome/browser/tab_contents/view_source_browsertest.cc
index d2ef0c1..b4740b5e 100644
--- a/chrome/browser/tab_contents/view_source_browsertest.cc
+++ b/chrome/browser/tab_contents/view_source_browsertest.cc
@@ -131,3 +131,55 @@
   ASSERT_TRUE(browser()->tab_strip_model()->GetWebContentsAt(0)->
                   GetController().GetActiveEntry()->IsViewSourceMode());
 }
+
+// This test ensures that view-source session history navigations work
+// correctly when switching processes. See https://crbug.com/544868.
+IN_PROC_BROWSER_TEST_F(ViewSourceTest,
+                       ViewSourceCrossProcessAndBack) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  GURL url_viewsource(content::kViewSourceScheme + std::string(":") +
+                      embedded_test_server()->GetURL(kTestHtml).spec());
+  ui_test_utils::NavigateToURL(browser(), url_viewsource);
+  EXPECT_FALSE(chrome::CanViewSource(browser()));
+  EXPECT_EQ(1, browser()->tab_strip_model()->count());
+
+  // Open another tab to the same origin, so the process is kept alive while
+  // the original tab is navigated cross-process. This is required for the
+  // original bug to reproduce.
+  {
+    GURL url = embedded_test_server()->GetURL("/title1.html");
+    ui_test_utils::UrlLoadObserver load_complete(
+        url, content::NotificationService::AllSources());
+    EXPECT_TRUE(content::ExecuteScript(
+        browser()->tab_strip_model()->GetActiveWebContents(),
+        "window.open('" + url.spec() + "');"));
+    load_complete.Wait();
+    EXPECT_EQ(2, browser()->tab_strip_model()->count());
+  }
+
+  // Switch back to the first tab and navigate it cross-process.
+  browser()->tab_strip_model()->ActivateTabAt(0, true);
+  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIVersionURL));
+  EXPECT_TRUE(chrome::CanViewSource(browser()));
+
+  // Navigate back in session history to ensure view-source mode is still
+  // active.
+  {
+    ui_test_utils::UrlLoadObserver load_complete(
+        url_viewsource, content::NotificationService::AllSources());
+    chrome::GoBack(browser(), CURRENT_TAB);
+    load_complete.Wait();
+  }
+
+  // Check whether the page is in view-source mode or not by checking if an
+  // expected element on the page exists or not. In view-source mode it
+  // should not be found.
+  bool result = false;
+  EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+      browser()->tab_strip_model()->GetActiveWebContents(),
+      "domAutomationController.send(document.getElementById('bar') === null);",
+      &result));
+  EXPECT_TRUE(result);
+  EXPECT_FALSE(chrome::CanViewSource(browser()));
+}
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc
index 229ee242..483adde 100644
--- a/chrome/browser/themes/theme_service.cc
+++ b/chrome/browser/themes/theme_service.cc
@@ -125,7 +125,6 @@
   void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
                                   const extensions::Extension* extension,
                                   bool is_update,
-                                  bool from_ephemeral,
                                   const std::string& old_name) override {
     if (extension->is_theme()) {
       // The theme may be initially disabled. Wait till it is loaded (if ever).
diff --git a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
index b0e78a2..c062826 100644
--- a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
+++ b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
@@ -559,7 +559,7 @@
   // Simulate changing the original language and translating.
   process()->sink().ClearMessages();
   std::string new_original_lang = infobar->language_code_at(0);
-  infobar->UpdateOriginalLanguageIndex(0);
+  infobar->UpdateOriginalLanguage(new_original_lang);
   infobar->Translate();
   EXPECT_TRUE(GetTranslateMessage(&original_lang, &target_lang));
   EXPECT_EQ(new_original_lang, original_lang);
@@ -572,7 +572,7 @@
   // Simulate changing the target language and translating.
   process()->sink().ClearMessages();
   std::string new_target_lang = infobar->language_code_at(1);
-  infobar->UpdateTargetLanguageIndex(1);
+  infobar->UpdateTargetLanguage(new_target_lang);
   infobar->Translate();
   EXPECT_TRUE(GetTranslateMessage(&original_lang, &target_lang));
   EXPECT_EQ(new_original_lang, original_lang);
@@ -589,7 +589,7 @@
   ASSERT_TRUE(infobar != NULL);
   EXPECT_EQ(translate::TRANSLATE_STEP_BEFORE_TRANSLATE,
             infobar->translate_step());
-  infobar->UpdateTargetLanguageIndex(1);
+  infobar->UpdateTargetLanguage(new_target_lang);
   infobar->ToggleAlwaysTranslate();
   ReloadAndWait(true);
   infobar = GetTranslateInfoBar();
diff --git a/chrome/browser/ui/android/infobars/translate_infobar.cc b/chrome/browser/ui/android/infobars/translate_infobar.cc
index 233236e..e208f76b 100644
--- a/chrome/browser/ui/android/infobars/translate_infobar.cc
+++ b/chrome/browser/ui/android/infobars/translate_infobar.cc
@@ -6,6 +6,7 @@
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
 #include "base/android/jni_weak_ref.h"
 #include "chrome/browser/translate/chrome_translate_client.h"
 #include "components/translate/core/browser/translate_infobar_delegate.h"
@@ -33,17 +34,32 @@
 ScopedJavaLocalRef<jobject> TranslateInfoBar::CreateRenderInfoBar(JNIEnv* env) {
   translate::TranslateInfoBarDelegate* delegate = GetDelegate();
   std::vector<base::string16> languages;
+  std::vector<std::string> codes;
   languages.reserve(delegate->num_languages());
-  for (size_t i = 0; i < delegate->num_languages(); ++i)
+  codes.reserve(delegate->num_languages());
+  for (size_t i = 0; i < delegate->num_languages(); ++i) {
     languages.push_back(delegate->language_name_at(i));
-
+    codes.push_back(delegate->language_code_at(i));
+  }
+  DCHECK(codes.size() == languages.size());
   base::android::ScopedJavaLocalRef<jobjectArray> java_languages =
       base::android::ToJavaArrayOfStrings(env, languages);
+  base::android::ScopedJavaLocalRef<jobjectArray> java_codes =
+      base::android::ToJavaArrayOfStrings(env, codes);
+
+  ScopedJavaLocalRef<jstring> source_language_code =
+      base::android::ConvertUTF8ToJavaString(
+          env, delegate->original_language_code());
+
+  ScopedJavaLocalRef<jstring> target_language_code =
+      base::android::ConvertUTF8ToJavaString(env,
+                                             delegate->target_language_code());
+
   return Java_TranslateInfoBar_show(
-      env, delegate->translate_step(), delegate->original_language_index(),
-      delegate->target_language_index(), delegate->ShouldAlwaysTranslate(),
+      env, delegate->translate_step(), source_language_code.obj(),
+      target_language_code.obj(), delegate->ShouldAlwaysTranslate(),
       ShouldDisplayNeverTranslateInfoBarOnCancel(),
-      delegate->triggered_from_menu(), java_languages.obj());
+      delegate->triggered_from_menu(), java_languages.obj(), java_codes.obj());
 }
 
 void TranslateInfoBar::ProcessButton(int action) {
@@ -87,14 +103,19 @@
 
 void TranslateInfoBar::ApplyTranslateOptions(JNIEnv* env,
                                              const JavaParamRef<jobject>& obj,
-                                             int source_language_index,
-                                             int target_language_index,
+                                             jstring source_language_code,
+                                             jstring target_language_code,
                                              bool always_translate,
                                              bool never_translate_language,
                                              bool never_translate_site) {
+  DCHECK(env);
+  std::string source_code =
+      base::android::ConvertJavaStringToUTF8(env, source_language_code);
+  std::string target_code =
+      base::android::ConvertJavaStringToUTF8(env, target_language_code);
   translate::TranslateInfoBarDelegate* delegate = GetDelegate();
-  delegate->UpdateOriginalLanguageIndex(source_language_index);
-  delegate->UpdateTargetLanguageIndex(target_language_index);
+  delegate->UpdateOriginalLanguage(source_code);
+  delegate->UpdateTargetLanguage(target_code);
 
   if (delegate->ShouldAlwaysTranslate() != always_translate)
     delegate->ToggleAlwaysTranslate();
diff --git a/chrome/browser/ui/android/infobars/translate_infobar.h b/chrome/browser/ui/android/infobars/translate_infobar.h
index c877fd8..8f0540f 100644
--- a/chrome/browser/ui/android/infobars/translate_infobar.h
+++ b/chrome/browser/ui/android/infobars/translate_infobar.h
@@ -23,8 +23,8 @@
   // JNI methods specific to translate.
   void ApplyTranslateOptions(JNIEnv* env,
                              const base::android::JavaParamRef<jobject>& obj,
-                             int source_language_index,
-                             int target_language_index,
+                             jstring source_language_code,
+                             jstring target_language_code,
                              bool always_translate,
                              bool never_translate_language,
                              bool never_translate_site);
diff --git a/chrome/browser/ui/app_list/app_list_test_util.cc b/chrome/browser/ui/app_list/app_list_test_util.cc
index e67800b..ba33a98 100644
--- a/chrome/browser/ui/app_list/app_list_test_util.cc
+++ b/chrome/browser/ui/app_list/app_list_test_util.cc
@@ -29,7 +29,6 @@
   // - 1 dummy extension (which should not be visible in the launcher)
   // - 2 packaged extension apps
   // - 1 hosted extension app
-  // - 1 ephemeral app (which should not be visible in the launcher)
   base::FilePath source_install_dir =
       data_dir().AppendASCII("app_list").AppendASCII("Extensions");
   base::FilePath pref_path = source_install_dir
@@ -38,6 +37,6 @@
   InitializeInstalledExtensionService(pref_path, source_install_dir);
   service_->Init();
 
-  // There should be 5 extensions in the test profile.
-  ASSERT_EQ(5U, registry()->enabled_extensions().size());
+  // There should be 4 extensions in the test profile.
+  ASSERT_EQ(4U, registry()->enabled_extensions().size());
 }
diff --git a/chrome/browser/ui/app_list/arc/arc_app_item.cc b/chrome/browser/ui/app_list/arc/arc_app_item.cc
index 2e1a312..225ac4b 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_item.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_item.cc
@@ -73,7 +73,10 @@
 }
 
 void ArcAppItem::Activate(int event_flags) {
-  DCHECK(ready_);
+  if (!ready()) {
+    VLOG(2) << "Cannot launch not-ready app:" << id() << ".";
+    return;
+  }
 
   ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context_);
   scoped_ptr<ArcAppListPrefs::AppInfo> app_info = prefs->GetApp(id());
diff --git a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
index df39fe6..b43abf5 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
@@ -290,6 +290,17 @@
   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 an attempt to launch of a not-ready app.
+  bridge_service()->SendRefreshAppList(std::vector<arc::AppInfo>());
+  item_first = FindArcItem(GetAppId(app_first));
+  ASSERT_NE(nullptr, item_first);
+  size_t launch_request_count_before =
+      bridge_service()->launch_requests().size();
+  item_first->Activate(0);
+  // Number of launch requests must not change.
+  EXPECT_EQ(launch_request_count_before,
+            bridge_service()->launch_requests().size());
 }
 
 TEST_F(ArcAppModelBuilderTest, RequestIcons) {
diff --git a/chrome/browser/ui/app_list/model_pref_updater.cc b/chrome/browser/ui/app_list/model_pref_updater.cc
index ea79bd9..8c0255723 100644
--- a/chrome/browser/ui/app_list/model_pref_updater.cc
+++ b/chrome/browser/ui/app_list/model_pref_updater.cc
@@ -10,6 +10,10 @@
 #include "ui/app_list/app_list_item.h"
 #include "ui/app_list/app_list_model.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/ui/app_list/arc/arc_app_item.h"
+#endif
+
 namespace app_list {
 
 ModelPrefUpdater::ModelPrefUpdater(AppListPrefs* app_list_prefs,
@@ -41,6 +45,10 @@
     info.item_type = AppListPrefs::AppListInfo::FOLDER_ITEM;
   else if (item->GetItemType() == ExtensionAppItem::kItemType)
     info.item_type = AppListPrefs::AppListInfo::APP_ITEM;
+#if defined(OS_CHROMEOS)
+  else if (item->GetItemType() == ArcAppItem::kItemType)
+    info.item_type = AppListPrefs::AppListInfo::APP_ITEM;
+#endif
   else
     NOTREACHED();
 
diff --git a/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider_unittest.cc
index dede321..54b8a56a 100644
--- a/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/browser/sync/profile_sync_test_util.h"
 #include "chrome/browser/ui/app_list/app_list_test_util.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/suggestions/proto/suggestions.pb.h"
@@ -55,7 +55,7 @@
   void SetUp() override {
     AppListTestBase::SetUp();
 
-    profile_.reset(ProfileSyncServiceMock::MakeSignedInTestingProfile());
+    profile_ = MakeSignedInTestingProfile();
     suggestions_search_.reset(
         new SuggestionsSearchProvider(profile_.get(), NULL));
 
diff --git a/chrome/browser/ui/app_list/search/webstore/webstore_result.cc b/chrome/browser/ui/app_list/search/webstore/webstore_result.cc
index d160709..f97a5f0 100644
--- a/chrome/browser/ui/app_list/search/webstore/webstore_result.cc
+++ b/chrome/browser/ui/app_list/search/webstore/webstore_result.cc
@@ -22,7 +22,6 @@
 #include "chrome/grit/generated_resources.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
-#include "extensions/browser/extension_util.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_urls.h"
 #include "grit/theme_resources.h"
@@ -127,7 +126,8 @@
 
   const bool is_otr = profile_->IsOffTheRecord();
   const bool is_installed =
-      extensions::util::IsExtensionInstalledPermanently(app_id_, profile_);
+      extension_registry_->GetExtensionById(
+          app_id_, extensions::ExtensionRegistry::EVERYTHING) != nullptr;
 
   if (!is_otr && !is_installed && !is_installing()) {
     actions.push_back(Action(
@@ -228,8 +228,8 @@
   SetIsInstalling(false);
   UpdateActions();
 
-  if (extensions::util::IsExtensionInstalledPermanently(extension->id(),
-                                                        profile_)) {
+  if (extension_registry_->GetExtensionById(
+          app_id_, extensions::ExtensionRegistry::EVERYTHING)) {
     NotifyItemInstalled();
   }
 }
diff --git a/chrome/browser/ui/ash/launcher/browser_status_monitor.cc b/chrome/browser/ui/ash/launcher/browser_status_monitor.cc
index a3eb043..e1b81d3 100644
--- a/chrome/browser/ui/ash/launcher/browser_status_monitor.cc
+++ b/chrome/browser/ui/ash/launcher/browser_status_monitor.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/ui/settings_window_manager_observer.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/web_applications/web_app.h"
+#include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "grit/ash_resources.h"
diff --git a/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc b/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc
index 72095f4..4ffd8fa9 100644
--- a/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc
+++ b/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/settings_window_manager.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "components/strings/grit/components_strings.h"
 #include "grit/ash_resources.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h b/chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h
deleted file mode 100644
index 4927693..0000000
--- a/chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_BUBBLE_DELEGATE_H_
-#define CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_BUBBLE_DELEGATE_H_
-
-class BookmarkBubbleDelegate {
- public:
-  virtual ~BookmarkBubbleDelegate() {}
-  virtual void OnSignInLinkClicked() = 0;
-};
-
-#endif  // CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_BUBBLE_DELEGATE_H_
diff --git a/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h
index e14bea5..0ef22e8 100644
--- a/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h
+++ b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h
@@ -7,16 +7,16 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h"
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "chrome/browser/ui/host_desktop.h"
+#include "chrome/browser/ui/sync/bubble_sync_promo_delegate.h"
 
 class Browser;
 class Profile;
 
 // Delegate of the bookmark bubble to load the sign in page in a browser
 // when the sign in link is clicked.
-class BookmarkBubbleSignInDelegate : public BookmarkBubbleDelegate,
+class BookmarkBubbleSignInDelegate : public BubbleSyncPromoDelegate,
                                      public chrome::BrowserListObserver {
  public:
   explicit BookmarkBubbleSignInDelegate(Browser* browser);
@@ -24,7 +24,7 @@
  private:
   ~BookmarkBubbleSignInDelegate() override;
 
-  // BookmarkBubbleDelegate:
+  // BubbleSyncPromoDelegate:
   void OnSignInLinkClicked() override;
 
   // chrome::BrowserListObserver:
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 5226b856..90186dd 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -3196,6 +3196,7 @@
   run_loop.Run();
   EXPECT_TRUE(js_result_getter.GetResult());
 }
+
 }  // namespace
 
 // flaky new test: http://crbug.com/471703
@@ -3223,3 +3224,96 @@
 
   CheckDisplayModeMQ(ASCIIToUTF16("fullscreen"), app_contents);
 }
+
+// Test to ensure the bounds of popup, devtool, and app windows are properly
+// restored.
+IN_PROC_BROWSER_TEST_F(BrowserTest, TestPopupBounds) {
+  {
+    // Minimum size that a popup window should have appended to its height when
+    // drawn (popup window bounds are for the content, not the window). This is
+    // the size of the toolbar on views platforms.
+    const int minimum_popup_padding = 29;
+
+    // Creates an untrusted popup window and asserts that the eventual height is
+    // padded with the toolbar and title bar height (initial height is content
+    // height).
+    Browser::CreateParams params(Browser::TYPE_POPUP, browser()->profile(),
+                                 chrome::HOST_DESKTOP_TYPE_NATIVE);
+    params.initial_bounds = gfx::Rect(0, 0, 100, 122);
+    Browser* browser = new Browser(params);
+    gfx::Rect bounds = browser->window()->GetBounds();
+
+    // Should be EXPECT_EQ, but this width is inconsistent across platforms.
+    // See https://crbug.com/567925.
+    EXPECT_GE(bounds.width(), 100);
+
+    // EXPECT_GE as Mac will have a larger height with the additional title bar.
+    EXPECT_GE(bounds.height(), 122 + minimum_popup_padding);
+    browser->window()->Close();
+  }
+
+  {
+    // Creates a trusted popup window and asserts that the eventual height
+    // doesn't change (initial height is window height).
+    Browser::CreateParams params(Browser::TYPE_POPUP, browser()->profile(),
+                                 chrome::HOST_DESKTOP_TYPE_NATIVE);
+    params.initial_bounds = gfx::Rect(0, 0, 100, 122);
+    params.trusted_source = true;
+    Browser* browser = new Browser(params);
+    gfx::Rect bounds = browser->window()->GetBounds();
+
+    // Should be EXPECT_EQ, but this width is inconsistent across platforms.
+    // See https://crbug.com/567925.
+    EXPECT_GE(bounds.width(), 100);
+    EXPECT_EQ(122, bounds.height());
+    browser->window()->Close();
+  }
+
+  {
+    // Creates an untrusted app window and asserts that the eventual height
+    // doesn't change.
+    Browser::CreateParams params = Browser::CreateParams::CreateForApp(
+        "app-name", false, gfx::Rect(0, 0, 100, 122), browser()->profile(),
+        chrome::HOST_DESKTOP_TYPE_NATIVE);
+    Browser* browser = new Browser(params);
+    gfx::Rect bounds = browser->window()->GetBounds();
+
+    // Should be EXPECT_EQ, but this width is inconsistent across platforms.
+    // See https://crbug.com/567925.
+    EXPECT_GE(bounds.width(), 100);
+    EXPECT_EQ(122, bounds.height());
+    browser->window()->Close();
+  }
+
+  {
+    // Creates a trusted app window and asserts that the eventual height
+    // doesn't change.
+    Browser::CreateParams params = Browser::CreateParams::CreateForApp(
+        "app-name", true, gfx::Rect(0, 0, 100, 122), browser()->profile(),
+        chrome::HOST_DESKTOP_TYPE_NATIVE);
+    Browser* browser = new Browser(params);
+    gfx::Rect bounds = browser->window()->GetBounds();
+
+    // Should be EXPECT_EQ, but this width is inconsistent across platforms.
+    // See https://crbug.com/567925.
+    EXPECT_GE(bounds.width(), 100);
+    EXPECT_EQ(122, bounds.height());
+    browser->window()->Close();
+  }
+
+  {
+    // Creates a devtools window and asserts that the eventual height
+    // doesn't change.
+    Browser::CreateParams params = Browser::CreateParams::CreateForDevTools(
+        browser()->profile(), chrome::HOST_DESKTOP_TYPE_NATIVE);
+    params.initial_bounds = gfx::Rect(0, 0, 100, 122);
+    Browser* browser = new Browser(params);
+    gfx::Rect bounds = browser->window()->GetBounds();
+
+    // Should be EXPECT_EQ, but this width is inconsistent across platforms.
+    // See https://crbug.com/567925.
+    EXPECT_GE(bounds.width(), 100);
+    EXPECT_EQ(122, bounds.height());
+    browser->window()->Close();
+  }
+}
diff --git a/chrome/browser/ui/browser_window_state.cc b/chrome/browser/ui/browser_window_state.cc
index c59e7fd8..3c903bf26 100644
--- a/chrome/browser/ui/browser_window_state.cc
+++ b/chrome/browser/ui/browser_window_state.cc
@@ -112,6 +112,13 @@
     ((browser->type() == Browser::TYPE_POPUP) && browser->is_trusted_source());
 }
 
+bool SavedBoundsAreContentBounds(const Browser* browser) {
+  // Pop ups such as devtools or bookmark app windows should behave as per other
+  // windows with persisted sizes - treating the saved bounds as window bounds.
+  return browser->is_type_popup() && !browser->is_app() &&
+         !browser->is_trusted_source();
+}
+
 void SaveWindowPlacement(const Browser* browser,
                          const gfx::Rect& bounds,
                          ui::WindowShowState show_state) {
diff --git a/chrome/browser/ui/browser_window_state.h b/chrome/browser/ui/browser_window_state.h
index b951d38..bfeeda03 100644
--- a/chrome/browser/ui/browser_window_state.h
+++ b/chrome/browser/ui/browser_window_state.h
@@ -41,6 +41,10 @@
 
 bool ShouldSaveWindowPlacement(const Browser* browser);
 
+// Returns true if the saved bounds for this window should be treated as the
+// bounds of the content area, not the whole window.
+bool SavedBoundsAreContentBounds(const Browser* browser);
+
 void SaveWindowPlacement(const Browser* browser,
                          const gfx::Rect& bounds,
                          ui::WindowShowState show_state);
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index 15e43a11..0e38799 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -376,12 +376,12 @@
 
     [self layoutSubviews];
 
-    // For a popup window, |desiredContentRect| contains the desired height of
-    // the content, not of the whole window.  Now that all the views are laid
-    // out, measure the current content area size and grow if needed.  The
-    // window has not been placed onscreen yet, so this extra resize will not
-    // cause visible jank.
-    if (browser_->is_type_popup()) {
+    // For non-trusted, non-app popup windows, |desiredContentRect| contains the
+    // desired height of the content, not of the whole window.  Now that all the
+    // views are laid out, measure the current content area size and grow if
+    // needed. The window has not been placed onscreen yet, so this extra resize
+    // will not cause visible jank.
+    if (chrome::SavedBoundsAreContentBounds(browser_.get())) {
       CGFloat deltaH = desiredContentRect.height() -
                        NSHeight([[self tabContentArea] frame]);
       // Do not shrink the window, as that may break minimum size invariants.
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.h b/chrome/browser/ui/cocoa/browser_window_controller_private.h
index b096a20..5a90be33 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_private.h
+++ b/chrome/browser/ui/cocoa/browser_window_controller_private.h
@@ -180,6 +180,10 @@
 - (void)windowDidExitFullScreen:(NSNotification*)notification;
 - (void)windowWillExitFullScreen:(NSNotification*)notification;
 
+// Hides or unhides any displayed modal sheet for fullscreen transition.
+// Modal sheets should be hidden at the beginning and then shown at the end.
+- (void)setSheetHiddenForFullscreenTransition:(BOOL)shoudHide;
+
 // Adjusts the UI and destroys the exit bubble when we are exiting fullscreen.
 - (void)adjustUIForExitingFullscreen;
 
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
index 2aa6a4cc..b808efe0 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -25,6 +25,7 @@
 #include "chrome/browser/ui/browser_window_state.h"
 #import "chrome/browser/ui/cocoa/browser_window_fullscreen_transition.h"
 #import "chrome/browser/ui/cocoa/browser_window_layout.h"
+#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h"
 #import "chrome/browser/ui/cocoa/custom_frame_view.h"
 #import "chrome/browser/ui/cocoa/dev_tools_controller.h"
 #import "chrome/browser/ui/cocoa/fast_resize_view.h"
@@ -700,6 +701,8 @@
   enteringAppKitFullscreenOnPrimaryScreen_ =
       [[[self window] screen] isEqual:[[NSScreen screens] firstObject]];
 
+  [self setSheetHiddenForFullscreenTransition:YES];
+
   // If we are using custom fullscreen animations, the layout will resize
   // in startCustomAnimationToEnterFullScreenWithDuration. In order to prevent
   // multiple resizing messages from being sent to the renderer, we should call
@@ -758,15 +761,17 @@
     base::MessageLoop::current()->PostTask(FROM_HERE, callback);
   }
 
+  [self setSheetHiddenForFullscreenTransition:NO];
+
   if (notification)  // For System Fullscreen when non-nil.
     [self deregisterForContentViewResizeNotifications];
+
   enteringAppKitFullscreen_ = NO;
   enteringImmersiveFullscreen_ = NO;
   enteringPresentationMode_ = NO;
   isUsingCustomAnimation_ = NO;
 
   [self showFullscreenExitBubbleIfNecessary];
-  [self layoutSubviews];
   browser_->WindowFullscreenStateChanged();
 }
 
@@ -778,10 +783,19 @@
   // Like windowWillEnterFullScreen, if we use custom animations,
   // adjustUIForExitingFullscreen should be called after the layout resizes in
   // startCustomAnimationToExitFullScreenWithDuration.
-  if (isUsingCustomAnimation_)
+  if (isUsingCustomAnimation_) {
     blockLayoutSubviews_ = YES;
-  else
+    [self setSheetHiddenForFullscreenTransition:YES];
+
+    // In OSX 10.11, when the NSFullScreenWindowMask is added or removed,
+    // the window's frame and layer changes slightly which causes a janky
+    // movement. As a result, we should disable the content view's autoresize
+    // at the beginning of the animation and set it back to its original value
+    // at the end of the animation.
+    [self.chromeContentView setAutoresizesSubviews:NO];
+  } else {
     [self adjustUIForExitingFullscreen];
+  }
 }
 
 - (void)windowDidExitFullScreen:(NSNotification*)notification {
@@ -791,6 +805,9 @@
     [self deregisterForContentViewResizeNotifications];
 
   browser_->WindowFullscreenStateChanged();
+  [self.chromeContentView setAutoresizesSubviews:YES];
+
+  [self setSheetHiddenForFullscreenTransition:NO];
 
   exitingAppKitFullscreen_ = NO;
   isUsingCustomAnimation_ = NO;
@@ -814,10 +831,25 @@
   fullscreenTransition_.reset();
   isUsingCustomAnimation_ = NO;
   blockLayoutSubviews_ = NO;
+
   // Force a relayout to try and get the window back into a reasonable state.
+  [self.chromeContentView setAutoresizesSubviews:YES];
   [self layoutSubviews];
 }
 
+- (void)setSheetHiddenForFullscreenTransition:(BOOL)shoudHide {
+  if (!isUsingCustomAnimation_)
+    return;
+
+  ConstrainedWindowSheetController* sheetController =
+      [ConstrainedWindowSheetController
+          controllerForParentWindow:[self window]];
+  if (shoudHide)
+    [sheetController hideSheetForFullscreenTransition];
+  else
+    [sheetController unhideSheetForFullscreenTransition];
+}
+
 - (void)adjustUIForExitingFullscreen {
   [self destroyFullscreenExitBubbleIfNecessary];
   [self adjustUIForExitingFullscreenAndStopOmniboxSliding];
@@ -1166,7 +1198,7 @@
 
   NSArray* customWindows =
       [fullscreenTransition_ customWindowsForFullScreenTransition];
-  isUsingCustomAnimation_ = !customWindows;
+  isUsingCustomAnimation_ = customWindows != nil;
   return customWindows;
 }
 
@@ -1185,7 +1217,7 @@
 
   NSArray* customWindows =
       [fullscreenTransition_ customWindowsForFullScreenTransition];
-  isUsingCustomAnimation_ = !customWindows;
+  isUsingCustomAnimation_ = customWindows != nil;
   return customWindows;
 }
 
diff --git a/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm b/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm
index e3f0291a..3b8b6312 100644
--- a/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm
+++ b/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm
@@ -113,9 +113,6 @@
   // The initial origin of the content view.
   NSPoint initialContentViewOrigin_;
 
-  // The initial value of the content view's autoresizeSubviews property.
-  BOOL initialContentViewAutoresizesSubviews_;
-
   // Whether the instance is in the process of changing the size of
   // |primaryWindow_|.
   BOOL changingPrimaryWindowSize_;
@@ -331,14 +328,6 @@
                    finalFrame_.size.width, finalFrame_.size.height);
     [primaryWindow_ forceContentViewFrame:relativeContentFinalFrame];
 
-    // In OSX 10.11, when the NSFullScreenWindowMask is added or removed,
-    // the window's frame and layer changes slightly which causes a janky
-    // movement. As a result, we should disable the content view's autoresize
-    // at the beginning of the animation and set it back to its original value
-    // at the end of the animation.
-    initialContentViewAutoresizesSubviews_ = [contentView autoresizesSubviews];
-    [contentView setAutoresizesSubviews:NO];
-
     fullscreenTabStripBackgroundView_.reset(
         [[FullscreenTabStripBackgroundView alloc]
             initWithFrame:finalFrame_
@@ -491,7 +480,6 @@
       NSView* content = [primaryWindow_ contentView];
       [content setFrameOrigin:initialContentViewOrigin_];
       [self changePrimaryWindowToFinalFrame];
-      [content setAutoresizesSubviews:initialContentViewAutoresizesSubviews_];
 
       [tabStripBackgroundView_ setHidden:NO];
       [fullscreenTabStripBackgroundView_ removeFromSuperview];
diff --git a/chrome/browser/ui/cocoa/certificate_viewer_mac.mm b/chrome/browser/ui/cocoa/certificate_viewer_mac.mm
index e5f6a9a..e562222 100644
--- a/chrome/browser/ui/cocoa/certificate_viewer_mac.mm
+++ b/chrome/browser/ui/cocoa/certificate_viewer_mac.mm
@@ -167,20 +167,11 @@
 
   oldResizesSubviews_ = [[sheetWindow contentView] autoresizesSubviews];
   [[sheetWindow contentView] setAutoresizesSubviews:NO];
-
-  oldSheetFrame_ = [sheetWindow frame];
-  NSRect overlayFrame = [overlayWindow_ frame];
-  oldSheetFrame_.origin.x -= NSMinX(overlayFrame);
-  oldSheetFrame_.origin.y -= NSMinY(overlayFrame);
-  [sheetWindow setFrame:ui::kWindowSizeDeterminedLater display:NO];
 }
 
 - (void)unhideSheet {
   NSWindow* sheetWindow = [overlayWindow_ attachedSheet];
-  NSRect overlayFrame = [overlayWindow_ frame];
-  oldSheetFrame_.origin.x += NSMinX(overlayFrame);
-  oldSheetFrame_.origin.y += NSMinY(overlayFrame);
-  [sheetWindow setFrame:oldSheetFrame_ display:NO];
+
   [[sheetWindow contentView] setAutoresizesSubviews:oldResizesSubviews_];
   [[overlayWindow_ attachedSheet] setAlphaValue:1.0];
 }
diff --git a/chrome/browser/ui/cocoa/certificate_viewer_mac_browsertest.mm b/chrome/browser/ui/cocoa/certificate_viewer_mac_browsertest.mm
index fd42510..ca0fc71 100644
--- a/chrome/browser/ui/cocoa/certificate_viewer_mac_browsertest.mm
+++ b/chrome/browser/ui/cocoa/certificate_viewer_mac_browsertest.mm
@@ -71,7 +71,7 @@
   // Switch to another tab and verify that the sheet is hidden.
   AddBlankTabAndShow(browser());
   EXPECT_EQ(0.0, [sheetWindow alphaValue]);
-  EXPECT_NSEQ(ui::kWindowSizeDeterminedLater, [sheetWindow frame]);
+  EXPECT_NSEQ(sheetFrame, [sheetWindow frame]);
 
   // Switch back and verify that the sheet is shown.
   chrome::SelectNumberedTab(browser(), 0);
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac_browsertest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac_browsertest.mm
index 5456a25..8e6ceda 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac_browsertest.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac_browsertest.mm
@@ -10,6 +10,8 @@
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h"
+#include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
+#include "chrome/browser/ui/exclusive_access/fullscreen_controller_test.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/browser/web_contents.h"
@@ -154,3 +156,29 @@
                                             TabStripModel::CLOSE_USER_GESTURE));
   EXPECT_EQ(1, tab_strip->count());
 }
+
+// Test that the sheet is still visible after entering and exiting fullscreen.
+IN_PROC_BROWSER_TEST_F(ConstrainedWindowMacTest, BrowserWindowFullscreen) {
+  NiceMock<ConstrainedWindowDelegateMock> delegate;
+  ConstrainedWindowMac dialog(&delegate, tab1_, sheet_);
+  EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
+
+  // Toggle fullscreen twice: one for entering and one for exiting.
+  // Check to see if the sheet is visible.
+  for (int i = 0; i < 2; i++) {
+    {
+      // NOTIFICATION_FULLSCREEN_CHANGED is sent asynchronously. Wait for the
+      // notification before testing the sheet's visibility.
+      scoped_ptr<FullscreenNotificationObserver> waiter(
+          new FullscreenNotificationObserver());
+      browser()
+          ->exclusive_access_manager()
+          ->fullscreen_controller()
+          ->ToggleBrowserFullscreenMode();
+      waiter->Wait();
+    }
+    EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
+  }
+
+  dialog.CloseWebContentsModalDialog();
+}
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h
index b299d6b3..bd6da1f0 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h
@@ -28,6 +28,10 @@
   base::scoped_nsobject<NSWindow> parentWindow_;
   base::scoped_nsobject<NSView> activeView_;
 
+  // Flag to prevent the sheet from updating its position if it's hidden during
+  // fullscreen. Otherwise, we will get janky movements during the animation.
+  BOOL isSheetHiddenForFullscreen_;
+
   // Class that bridges the cross-platform web_modal APIs to the Cocoa sheet
   // controller.
   scoped_ptr<WebContentsModalDialogHostCocoa> dialogHost_;
@@ -57,6 +61,13 @@
 // Hides a sheet over the active view.
 - (void)hideSheet;
 
+// Hides and unhides the sheet at the beginning and end of fullscreen
+// transition. |hideSheetForFullscreenTransition| gets called at the beginning
+// of the transition and |unhideSheetForFullscreenTransition| gets called at
+// the end.
+- (void)hideSheetForFullscreenTransition;
+- (void)unhideSheetForFullscreenTransition;
+
 // Calculates the position of the sheet for the given window size.
 - (NSPoint)originForSheet:(id<ConstrainedWindowSheet>)sheet
            withWindowSize:(NSSize)size;
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.mm
index 0c66e6f..db2d4951 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.mm
@@ -198,6 +198,22 @@
   activeView_.reset();
 }
 
+- (void)hideSheetForFullscreenTransition {
+  if (ConstrainedWindowSheetInfo* sheetInfo =
+          [self findSheetInfoForParentView:activeView_]) {
+    [sheetInfo hideSheet];
+    isSheetHiddenForFullscreen_ = YES;
+  }
+}
+
+- (void)unhideSheetForFullscreenTransition {
+  isSheetHiddenForFullscreen_ = NO;
+  if (ConstrainedWindowSheetInfo* sheetInfo =
+          [self findSheetInfoForParentView:activeView_]) {
+    [self showSheet:[sheetInfo sheet] forParentView:activeView_];
+  }
+}
+
 - (NSPoint)originForSheet:(id<ConstrainedWindowSheet>)sheet
            withWindowSize:(NSSize)size {
   ConstrainedWindowSheetInfo* info = [self findSheetInfoForSheet:sheet];
@@ -267,6 +283,9 @@
 }
 
 - (void)onParentWindowSizeDidChange:(NSNotification*)note {
+  if (isSheetHiddenForFullscreen_)
+    return;
+
   [self updateSheetPosition:activeView_];
 }
 
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
index c0a10e9f..0ddd6aa 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
@@ -940,7 +940,7 @@
 
 - (void)updateChevronPositionInFrame:(NSRect)frame {
   CGFloat xPos = NSWidth(frame) - kChevronWidth -
-      toolbarActionsBar_->platform_settings().right_padding;
+      toolbarActionsBar_->platform_settings().item_spacing;
   NSRect buttonFrame = NSMakeRect(xPos,
                                   0,
                                   kChevronWidth,
diff --git a/chrome/browser/ui/cocoa/infobars/after_translate_infobar_controller.mm b/chrome/browser/ui/cocoa/infobars/after_translate_infobar_controller.mm
index 6c18f58..ff2f503 100644
--- a/chrome/browser/ui/cocoa/infobars/after_translate_infobar_controller.mm
+++ b/chrome/browser/ui/cocoa/infobars/after_translate_infobar_controller.mm
@@ -6,6 +6,7 @@
 
 #include "base/strings/sys_string_conversions.h"
 #import "chrome/browser/ui/cocoa/infobars/infobar_utilities.h"
+#include "components/translate/core/common/translate_constants.h"
 
 using InfoBarUtilities::MoveControl;
 using InfoBarUtilities::VerifyControlOrderAndSpacing;
@@ -13,9 +14,8 @@
 @implementation AfterTranslateInfobarController
 
 - (void)loadLabelText {
-  autodeterminedSourceLanguage_ =
-      ([self delegate]->original_language_index() ==
-       translate::TranslateInfoBarDelegate::kNoIndex);
+  autodeterminedSourceLanguage_ = ([self delegate]->original_language_code() ==
+                                   translate::kUnknownLanguageCode);
   std::vector<base::string16> strings;
   translate::TranslateInfoBarDelegate::GetAfterTranslateStrings(
       &strings, &swappedLanugageButtons_, autodeterminedSourceLanguage_);
diff --git a/chrome/browser/ui/cocoa/infobars/before_translate_infobar_controller.mm b/chrome/browser/ui/cocoa/infobars/before_translate_infobar_controller.mm
index 361c498..11317bc 100644
--- a/chrome/browser/ui/cocoa/infobars/before_translate_infobar_controller.mm
+++ b/chrome/browser/ui/cocoa/infobars/before_translate_infobar_controller.mm
@@ -46,8 +46,7 @@
 
 - (void)initializeExtraControls {
   translate::TranslateInfoBarDelegate* delegate = [self delegate];
-  const base::string16& language =
-      delegate->language_name_at(delegate->original_language_index());
+  const base::string16& language = delegate->original_language_name();
   neverTranslateButton_.reset(
       CreateNSButtonWithResourceIDAndParameter(
           IDS_TRANSLATE_INFOBAR_NEVER_TRANSLATE, language));
diff --git a/chrome/browser/ui/cocoa/infobars/infobar_utilities.h b/chrome/browser/ui/cocoa/infobars/infobar_utilities.h
index 7f95774..2d6c820 100644
--- a/chrome/browser/ui/cocoa/infobars/infobar_utilities.h
+++ b/chrome/browser/ui/cocoa/infobars/infobar_utilities.h
@@ -27,8 +27,14 @@
 NSTextField* CreateLabel(NSRect bounds);
 
 // Adds an item with the specified properties to |menu|.
-void AddMenuItem(NSMenu *menu, id target, SEL selector, NSString* title,
-    int tag, bool enabled, bool checked);
+void AddMenuItem(NSMenu* menu,
+                 id target,
+                 SEL selector,
+                 NSString* title,
+                 int tag,
+                 bool enabled,
+                 bool checked,
+                 NSString* representedObj);
 
 }  // namespace InfoBarUtilities
 
diff --git a/chrome/browser/ui/cocoa/infobars/infobar_utilities.mm b/chrome/browser/ui/cocoa/infobars/infobar_utilities.mm
index 29831ff..fbc47579 100644
--- a/chrome/browser/ui/cocoa/infobars/infobar_utilities.mm
+++ b/chrome/browser/ui/cocoa/infobars/infobar_utilities.mm
@@ -84,8 +84,14 @@
 }
 
 // Adds an item with the specified properties to |menu|.
-void AddMenuItem(NSMenu *menu, id target, SEL selector, NSString* title,
-    int tag, bool enabled, bool checked) {
+void AddMenuItem(NSMenu* menu,
+                 id target,
+                 SEL selector,
+                 NSString* title,
+                 int tag,
+                 bool enabled,
+                 bool checked,
+                 NSString* representedObject) {
   if (tag == -1) {
     [menu addItem:[NSMenuItem separatorItem]];
   } else {
@@ -96,6 +102,9 @@
     [item setTag:tag];
     [menu addItem:item];
     [item setTarget:target];
+    if (representedObject != nil) {
+      [item setRepresentedObject:representedObject];
+    }
     if (checked)
       [item setState:NSOnState];
     if (!enabled)
diff --git a/chrome/browser/ui/cocoa/infobars/translate_infobar_base.h b/chrome/browser/ui/cocoa/infobars/translate_infobar_base.h
index ff0de35..992aedb7 100644
--- a/chrome/browser/ui/cocoa/infobars/translate_infobar_base.h
+++ b/chrome/browser/ui/cocoa/infobars/translate_infobar_base.h
@@ -87,10 +87,13 @@
 - (void)removeOkCancelButtons;
 
 // Called when the source or target language selection changes in a menu.
+// |newLanguageCode| is the ISO language of the newly selected item.
 // |newLanguageIdx| is the index of the newly selected item in the appropriate
 // menu.
-- (void)sourceLanguageModified:(NSInteger)newLanguageIdx;
-- (void)targetLanguageModified:(NSInteger)newLanguageIdx;
+- (void)sourceLanguageModified:(NSString*)newLanguageCode
+             withLanguageIndex:(NSInteger)newLanguageIdx;
+- (void)targetLanguageModified:(NSString*)newLanguageCode
+             withLanguageIndex:(NSInteger)newLanguageIdx;
 
 // Called when an item in one of the toolbar's language or options
 // menus is selected.
diff --git a/chrome/browser/ui/cocoa/infobars/translate_infobar_base.mm b/chrome/browser/ui/cocoa/infobars/translate_infobar_base.mm
index 209e5d5..bcf6d72c 100644
--- a/chrome/browser/ui/cocoa/infobars/translate_infobar_base.mm
+++ b/chrome/browser/ui/cocoa/infobars/translate_infobar_base.mm
@@ -84,10 +84,13 @@
 - (void)updateState;
 
 // Called when the source or target language selection changes in a menu.
+// |newLanguageCode| is the ISO language of the newly selected item.
 // |newLanguageIdx| is the index of the newly selected item in the appropriate
 // menu.
-- (void)sourceLanguageModified:(NSInteger)newLanguageIdx;
-- (void)targetLanguageModified:(NSInteger)newLanguageIdx;
+- (void)sourceLanguageModified:(NSString*)newLanguageCode
+             withLanguageIndex:(NSInteger)newLanguageIdx;
+- (void)targetLanguageModified:(NSString*)newLanguageCode
+             withLanguageIndex:(NSInteger)newLanguageIdx;
 
 // Completely rebuild "from" and "to" language menus from the data model.
 - (void)populateLanguageMenus;
@@ -122,12 +125,12 @@
   translateMessageButton_.reset([[NSButton alloc] init]);
 }
 
-- (void)sourceLanguageModified:(NSInteger)newLanguageIdx {
-  size_t newLanguageIdxSizeT = static_cast<size_t>(newLanguageIdx);
-  DCHECK_NE(translate::TranslateInfoBarDelegate::kNoIndex, newLanguageIdxSizeT);
-  if (newLanguageIdxSizeT == [self delegate]->original_language_index())
+- (void)sourceLanguageModified:(NSString*)newLanguageCode
+             withLanguageIndex:(NSInteger)newLanguageIdx {
+  std::string newLanguageCodeS = base::SysNSStringToUTF8(newLanguageCode);
+  if (newLanguageCodeS.compare([self delegate]->original_language_code()) == 0)
     return;
-  [self delegate]->UpdateOriginalLanguageIndex(newLanguageIdxSizeT);
+  [self delegate]->UpdateOriginalLanguage(newLanguageCodeS);
   if ([self delegate]->translate_step() ==
       translate::TRANSLATE_STEP_AFTER_TRANSLATE)
     [self delegate]->Translate();
@@ -136,12 +139,12 @@
   [fromLanguagePopUp_ selectItemAtIndex:newMenuIdx];
 }
 
-- (void)targetLanguageModified:(NSInteger)newLanguageIdx {
-  size_t newLanguageIdxSizeT = static_cast<size_t>(newLanguageIdx);
-  DCHECK_NE(translate::TranslateInfoBarDelegate::kNoIndex, newLanguageIdxSizeT);
-  if (newLanguageIdxSizeT == [self delegate]->target_language_index())
+- (void)targetLanguageModified:(NSString*)newLanguageCode
+             withLanguageIndex:(NSInteger)newLanguageIdx {
+  std::string newLanguageCodeS = base::SysNSStringToUTF8(newLanguageCode);
+  if (newLanguageCodeS.compare([self delegate]->target_language_code()) == 0)
     return;
-  [self delegate]->UpdateTargetLanguageIndex(newLanguageIdxSizeT);
+  [self delegate]->UpdateTargetLanguage(newLanguageCodeS);
   if ([self delegate]->translate_step() ==
       translate::TRANSLATE_STEP_AFTER_TRANSLATE)
     [self delegate]->Translate();
@@ -233,13 +236,11 @@
   NSMenu* optionsMenu = [optionsPopUp_ menu];
   [optionsMenu setAutoenablesItems:NO];
   for (int i = 0; i < optionsMenuModel_->GetItemCount(); ++i) {
-    AddMenuItem(optionsMenu,
-                self,
-                @selector(optionsMenuChanged:),
+    AddMenuItem(optionsMenu, self, @selector(optionsMenuChanged:),
                 base::SysUTF16ToNSString(optionsMenuModel_->GetLabelAt(i)),
                 optionsMenuModel_->GetCommandIdAt(i),
                 optionsMenuModel_->IsEnabledAt(i),
-                optionsMenuModel_->IsItemCheckedAt(i));
+                optionsMenuModel_->IsItemCheckedAt(i), nil);
   }
 }
 
@@ -252,31 +253,33 @@
   [originalLanguageMenu setAutoenablesItems:NO];
   NSMenu* targetLanguageMenu = [toLanguagePopUp_ menu];
   [targetLanguageMenu setAutoenablesItems:NO];
+  size_t source_index = translate::TranslateInfoBarDelegate::kNoIndex;
+  size_t target_index = translate::TranslateInfoBarDelegate::kNoIndex;
   for (size_t i = 0; i < [self delegate]->num_languages(); ++i) {
     NSString* title =
         base::SysUTF16ToNSString([self delegate]->language_name_at(i));
-    AddMenuItem(originalLanguageMenu,
-                self,
-                @selector(languageMenuChanged:),
-                title,
-                IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE + i,
-                i != [self delegate]->target_language_index(),
-                i == [self delegate]->original_language_index());
-    AddMenuItem(targetLanguageMenu,
-                self,
-                @selector(languageMenuChanged:),
-                title,
-                IDC_TRANSLATE_TARGET_LANGUAGE_BASE + i,
-                i != [self delegate]->original_language_index(),
-                i == [self delegate]->target_language_index());
+    std::string language_code = [self delegate]->language_code_at(i);
+    if (language_code == [self delegate]->original_language_code()) {
+      source_index = i;
+    }
+    if (language_code == [self delegate]->target_language_code()) {
+      target_index = i;
+    }
+    AddMenuItem(originalLanguageMenu, self, @selector(languageMenuChanged:),
+                title, IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE + i,
+                language_code != [self delegate]->target_language_code(),
+                language_code == [self delegate]->original_language_code(),
+                base::SysUTF8ToNSString(language_code));
+    AddMenuItem(targetLanguageMenu, self, @selector(languageMenuChanged:),
+                title, IDC_TRANSLATE_TARGET_LANGUAGE_BASE + i,
+                language_code != [self delegate]->original_language_code(),
+                language_code == [self delegate]->target_language_code(),
+                base::SysUTF8ToNSString(language_code));
   }
-  if ([self delegate]->original_language_index() !=
-      translate::TranslateInfoBarDelegate::kNoIndex) {
-    [fromLanguagePopUp_
-        selectItemAtIndex:([self delegate]->original_language_index())];
+  if (source_index != translate::TranslateInfoBarDelegate::kNoIndex) {
+    [fromLanguagePopUp_ selectItemAtIndex:(source_index)];
   }
-  [toLanguagePopUp_
-      selectItemAtIndex:([self delegate]->target_language_index())];
+  [toLanguagePopUp_ selectItemAtIndex:(target_index)];
 }
 
 - (void)addAdditionalControls {
@@ -436,13 +439,14 @@
     return;
   if ([item respondsToSelector:@selector(tag)]) {
     int cmd = [item tag];
+    NSString* language_code = [item representedObject];
     if (cmd >= IDC_TRANSLATE_TARGET_LANGUAGE_BASE) {
       cmd -= IDC_TRANSLATE_TARGET_LANGUAGE_BASE;
-      [self targetLanguageModified:cmd];
+      [self targetLanguageModified:language_code withLanguageIndex:cmd];
       return;
     } else if (cmd >= IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE) {
       cmd -= IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE;
-      [self sourceLanguageModified:cmd];
+      [self sourceLanguageModified:language_code withLanguageIndex:cmd];
       return;
     }
   }
diff --git a/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm b/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm
index d16e8067..3d78553c 100644
--- a/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm
+++ b/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm
@@ -222,7 +222,9 @@
     .Times(0);
 
   int arbitrary_index = 2;
-  [infobar_controller_ sourceLanguageModified:arbitrary_index];
+  NSString* arbitrary_language = @"es";
+  [infobar_controller_ sourceLanguageModified:arbitrary_language
+                            withLanguageIndex:arbitrary_index];
   EXPECT_CALL(*infobar_delegate(), Translate())
     .Times(0);
 }
diff --git a/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm b/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm
index 470e4df..194bed6 100644
--- a/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm
@@ -175,13 +175,14 @@
 bool ContentSettingDecoration::UpdateFromWebContents(
     WebContents* web_contents) {
   bool was_visible = IsVisible();
-  int old_icon = content_setting_image_model_->icon_id();
+  int old_icon = content_setting_image_model_->raster_icon_id();
   content_setting_image_model_->UpdateFromWebContents(web_contents);
   SetVisible(content_setting_image_model_->is_visible());
-  bool decoration_changed = was_visible != IsVisible() ||
-      old_icon != content_setting_image_model_->icon_id();
+  bool decoration_changed =
+      was_visible != IsVisible() ||
+      old_icon != content_setting_image_model_->raster_icon_id();
   if (IsVisible()) {
-    SetImage(content_setting_image_model_->icon().ToNSImage());
+    SetImage(content_setting_image_model_->raster_icon().ToNSImage());
     SetToolTip(
         base::SysUTF16ToNSString(content_setting_image_model_->get_tooltip()));
 
diff --git a/chrome/browser/ui/cocoa/passwords/passwords_bubble_browsertest.mm b/chrome/browser/ui/cocoa/passwords/passwords_bubble_browsertest.mm
index 7f63089..f9a02b5 100644
--- a/chrome/browser/ui/cocoa/passwords/passwords_bubble_browsertest.mm
+++ b/chrome/browser/ui/cocoa/passwords/passwords_bubble_browsertest.mm
@@ -12,7 +12,7 @@
 #include "chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration.h"
 #include "chrome/browser/ui/cocoa/passwords/passwords_bubble_cocoa.h"
 #include "chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.h"
-#include "chrome/browser/ui/cocoa/passwords/pending_password_view_controller.h"
+#include "chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.h"
 #include "chrome/browser/ui/passwords/manage_passwords_test.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "content/public/test/test_utils.h"
@@ -76,7 +76,7 @@
   EXPECT_FALSE(ManagePasswordsBubbleCocoa::instance());
   DoWithSwizzledNSWindow(^{ SetupPendingPassword(); });
   EXPECT_TRUE(ManagePasswordsBubbleCocoa::instance());
-  EXPECT_EQ([ManagePasswordsBubblePendingViewController class],
+  EXPECT_EQ([SavePendingPasswordViewController class],
             [controller().currentController class]);
   EXPECT_TRUE(view()->active());
 }
diff --git a/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.mm b/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.mm
index d24a5bae..efc37c9e 100644
--- a/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.mm
@@ -14,6 +14,7 @@
 #import "chrome/browser/ui/cocoa/passwords/auto_signin_view_controller.h"
 #import "chrome/browser/ui/cocoa/passwords/confirmation_password_saved_view_controller.h"
 #import "chrome/browser/ui/cocoa/passwords/manage_passwords_view_controller.h"
+#import "chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.h"
 #include "ui/base/cocoa/window_size_constants.h"
 
 @interface ManagePasswordsBubbleController ()
@@ -58,10 +59,9 @@
   // Find the next view controller.
   currentController_.reset();
   if (model_->state() == password_manager::ui::PENDING_PASSWORD_STATE) {
-    currentController_.reset(
-        [[ManagePasswordsBubblePendingViewController alloc]
-            initWithModel:model_
-                 delegate:self]);
+    currentController_.reset([[SavePendingPasswordViewController alloc]
+        initWithModel:model_
+             delegate:self]);
   } else if (model_->state() == password_manager::ui::CONFIRMATION_STATE) {
     currentController_.reset(
         [[ManagePasswordsBubbleConfirmationViewController alloc]
diff --git a/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller_unittest.mm
index 510da060..91b5f41 100644
--- a/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller_unittest.mm
@@ -14,7 +14,7 @@
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
 #include "chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.h"
 #import "chrome/browser/ui/cocoa/passwords/manage_passwords_view_controller.h"
-#import "chrome/browser/ui/cocoa/passwords/pending_password_view_controller.h"
+#import "chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.h"
 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -49,7 +49,7 @@
 
 TEST_F(ManagePasswordsBubbleControllerTest, PendingStateShouldHavePendingView) {
   SetUpPendingState();
-  EXPECT_EQ([ManagePasswordsBubblePendingViewController class],
+  EXPECT_EQ([SavePendingPasswordViewController class],
             [[controller() currentController] class]);
 }
 
diff --git a/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.h b/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.h
index c411cb9a..a5c0cd8 100644
--- a/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.h
+++ b/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.h
@@ -13,23 +13,29 @@
 class ManagePasswordsBubbleModel;
 @class PasswordsListViewController;
 
-// Manages the view that offers to save the user's password.
-@interface ManagePasswordsBubblePendingViewController
+// Base class for the views that offer to save/update the user's password.
+@interface PendingPasswordViewController
     : ManagePasswordsBubbleContentViewController<NSTextViewDelegate> {
  @private
   ManagePasswordsBubbleModel* model_;  // weak
-  base::scoped_nsobject<NSButton> saveButton_;
-  base::scoped_nsobject<NSButton> neverButton_;
   base::scoped_nsobject<NSButton> closeButton_;
-  base::scoped_nsobject<PasswordsListViewController> passwordItem_;
 }
 - (id)initWithModel:(ManagePasswordsBubbleModel*)model
            delegate:(id<ManagePasswordsBubbleContentViewDelegate>)delegate;
+
+// Creates a controller for showing username/password and returns its view.
+- (NSView*)createPasswordView;
+
+// Returns whether GoogleSmartLock warm welcome should be shown.
+- (BOOL)shouldShowGoogleSmartLockWelcome;
+
+// Creates buttons that should be shown in the bubble and returns them.
+- (NSArray*)createButtonsAndAddThemToView:(NSView*)view;
+
+@property(readonly) ManagePasswordsBubbleModel* model;
 @end
 
-@interface ManagePasswordsBubblePendingViewController (Testing)
-@property(readonly) NSButton* saveButton;
-@property(readonly) NSButton* neverButton;
+@interface PendingPasswordViewController (Testing)
 @property(readonly) NSButton* closeButton;
 @end
 
diff --git a/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.mm b/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.mm
index 88ea5577..04c459e 100644
--- a/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.mm
+++ b/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.mm
@@ -6,11 +6,11 @@
 
 #import "chrome/browser/ui/cocoa/passwords/pending_password_view_controller.h"
 
+#include "base/mac/foundation_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/browser/ui/chrome_style.h"
 #import "chrome/browser/ui/cocoa/hover_close_button.h"
 #import "chrome/browser/ui/cocoa/passwords/passwords_bubble_utils.h"
-#import "chrome/browser/ui/cocoa/passwords/passwords_list_view_controller.h"
 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
 #include "chrome/grit/generated_resources.h"
 #include "skia/ext/skia_utils_mac.h"
@@ -20,12 +20,7 @@
 
 const SkColor kWarmWelcomeColor = SkColorSetRGB(0x64, 0x64, 0x64);
 
-@interface ManagePasswordsBubblePendingViewController ()
-- (void)onSaveClicked:(id)sender;
-- (void)onNeverForThisSiteClicked:(id)sender;
-@end
-
-@implementation ManagePasswordsBubblePendingViewController
+@implementation PendingPasswordViewController
 
 - (id)initWithModel:(ManagePasswordsBubbleModel*)model
            delegate:(id<ManagePasswordsBubbleContentViewDelegate>)delegate {
@@ -35,20 +30,6 @@
   return self;
 }
 
-- (NSButton*)defaultButton {
-  return saveButton_;
-}
-
-- (void)onSaveClicked:(id)sender {
-  model_->OnSaveClicked();
-  [delegate_ viewShouldDismiss];
-}
-
-- (void)onNeverForThisSiteClicked:(id)sender {
-  model_->OnNeverForThisSiteClicked();
-  [delegate_ viewShouldDismiss];
-}
-
 - (BOOL)textView:(NSTextView*)textView
     clickedOnLink:(id)link
           atIndex:(NSUInteger)charIndex {
@@ -67,6 +48,22 @@
   return button;
 }
 
+- (NSView*)createPasswordView {
+  // Empty implementation, it should be implemented in child class.
+  NOTREACHED();
+  return nil;
+}
+
+- (BOOL)shouldShowGoogleSmartLockWelcome {
+  return NO;
+}
+
+- (NSArray*)createButtonsAndAddThemToView:(NSView*)view {
+  // Empty implementation, it should be implemented in child class.
+  NOTREACHED();
+  return nil;
+}
+
 - (void)loadView {
   base::scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:NSZeroRect]);
 
@@ -74,7 +71,7 @@
   // |  Title                        x |
   // |  username   password            |
   // |  Smart Lock  welcome (optional) |
-  // |                [Never]  [Save]  |
+  // |            [Button1] [Button2]  |
   // -----------------------------------
 
   // The title text depends on whether the user is signed in and therefore syncs
@@ -136,16 +133,11 @@
 
   // Password item.
   // It should be at least as wide as the box without the padding.
-  std::vector<const autofill::PasswordForm*> password_forms;
-  password_forms.push_back(&model_->pending_password());
-  passwordItem_.reset([[PasswordsListViewController alloc]
-      initWithModel:model_
-              forms:password_forms]);
-  NSView* password = [passwordItem_ view];
+  NSView* password = [self createPasswordView];
   [view addSubview:password];
 
   base::scoped_nsobject<NSTextField> warm_welcome;
-  if (model_->ShouldShowGoogleSmartLockWelcome()) {
+  if ([self shouldShowGoogleSmartLockWelcome]) {
     NSString* label_text =
         l10n_util::GetNSString(IDS_PASSWORD_MANAGER_SMART_LOCK_WELCOME);
     warm_welcome.reset([[self addLabel:label_text
@@ -157,21 +149,7 @@
     [warm_welcome setTextColor:color];
   }
 
-  // Save button.
-  saveButton_.reset(
-      [[self addButton:l10n_util::GetNSString(IDS_PASSWORD_MANAGER_SAVE_BUTTON)
-                toView:view
-                target:self
-                action:@selector(onSaveClicked:)] retain]);
-
-  // Never button.
-  NSString* neverButtonText =
-      l10n_util::GetNSString(IDS_PASSWORD_MANAGER_BUBBLE_BLACKLIST_BUTTON);
-  neverButton_.reset(
-      [[self addButton:neverButtonText
-                toView:view
-                target:self
-                action:@selector(onNeverForThisSiteClicked:)] retain]);
+  NSArray* buttons = [self createButtonsAndAddThemToView:view];
 
   // Compute the bubble width using the password item.
   const CGFloat contentWidth =
@@ -182,16 +160,16 @@
 
   // Buttons go on the bottom row and are right-aligned.
   // Start with [Save].
-  CGFloat curX = width - kFramePadding - NSWidth([saveButton_ frame]);
+  CGFloat curX = width - kFramePadding + kRelatedControlHorizontalPadding;
   CGFloat curY = kFramePadding;
-  [saveButton_ setFrameOrigin:NSMakePoint(curX, curY)];
 
-  // [Never] goes to the left of [Save].
-  curX -= kRelatedControlHorizontalPadding + NSWidth([neverButton_ frame]);
-  [neverButton_ setFrameOrigin:NSMakePoint(curX, curY)];
+  for (NSButton* button in buttons) {
+    curX -= kRelatedControlHorizontalPadding + NSWidth([button frame]);
+    [button setFrameOrigin:NSMakePoint(curX, curY)];
+  }
 
   curX = kFramePadding;
-  curY = NSMaxY([saveButton_ frame]) + kUnrelatedControlVerticalPadding;
+  curY = NSMaxY([buttons.firstObject frame]) + kUnrelatedControlVerticalPadding;
   // The Smart Lock warm welcome is placed above after some padding.
   if (warm_welcome) {
     [warm_welcome setFrameOrigin:NSMakePoint(curX, curY)];
@@ -220,17 +198,13 @@
   [self setView:view];
 }
 
+- (ManagePasswordsBubbleModel*)model {
+  return model_;
+}
+
 @end
 
-@implementation ManagePasswordsBubblePendingViewController (Testing)
-
-- (NSButton*)saveButton {
-  return saveButton_.get();
-}
-
-- (NSButton*)neverButton {
-  return neverButton_.get();
-}
+@implementation PendingPasswordViewController (Testing)
 
 - (NSButton*)closeButton {
   return closeButton_.get();
diff --git a/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.h b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.h
new file mode 100644
index 0000000..a100858
--- /dev/null
+++ b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.h
@@ -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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_PASSWORDS_PENDING_SAVE_PASSWORD_VIEW_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_PASSWORDS_PENDING_SAVE_PASSWORD_VIEW_CONTROLLER_H_
+
+#import "chrome/browser/ui/cocoa/passwords/pending_password_view_controller.h"
+
+class ManagePasswordsBubbleModel;
+@class PasswordsListViewController;
+
+// Manages the view that offers to save the user's password.
+@interface SavePendingPasswordViewController
+    : PendingPasswordViewController<NSTextViewDelegate> {
+ @private
+  base::scoped_nsobject<NSButton> saveButton_;
+  base::scoped_nsobject<NSButton> neverButton_;
+  base::scoped_nsobject<PasswordsListViewController> passwordItem_;
+}
+- (SavePendingPasswordViewController*)
+initWithModel:(ManagePasswordsBubbleModel*)model
+     delegate:(id<ManagePasswordsBubbleContentViewDelegate>)delegate;
+- (NSView*)createPasswordView;
+- (NSArray*)createButtonsAndAddThemToView:(NSView*)view;
+@end
+
+@interface SavePendingPasswordViewController (Testing)
+@property(readonly) NSButton* saveButton;
+@property(readonly) NSButton* neverButton;
+@end
+
+#endif  // CHROME_BROWSER_UI_COCOA_PASSWORDS_PENDING_SAVE_PASSWORD_VIEW_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.mm b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.mm
new file mode 100644
index 0000000..6113068
--- /dev/null
+++ b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.mm
@@ -0,0 +1,85 @@
+// 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 "chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.h"
+
+#import "chrome/browser/ui/cocoa/passwords/passwords_list_view_controller.h"
+#include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
+#include "chrome/grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+@interface SavePendingPasswordViewController ()
+- (void)onSaveClicked:(id)sender;
+- (void)onNeverForThisSiteClicked:(id)sender;
+@end
+
+@implementation SavePendingPasswordViewController
+
+- (SavePendingPasswordViewController*)
+initWithModel:(ManagePasswordsBubbleModel*)model
+     delegate:(id<ManagePasswordsBubbleContentViewDelegate>)delegate {
+  self = [super initWithModel:model
+                     delegate:delegate];
+  return self;
+}
+
+- (NSButton*)defaultButton {
+  return saveButton_;
+}
+
+- (void)onSaveClicked:(id)sender {
+  self.model->OnSaveClicked();
+  [delegate_ viewShouldDismiss];
+}
+
+- (void)onNeverForThisSiteClicked:(id)sender {
+  self.model->OnNeverForThisSiteClicked();
+  [delegate_ viewShouldDismiss];
+}
+
+- (NSView*)createPasswordView {
+  std::vector<const autofill::PasswordForm*> password_forms;
+  password_forms.push_back(&self.model->pending_password());
+  passwordItem_.reset([[PasswordsListViewController alloc]
+      initWithModel:self.model
+              forms:password_forms]);
+  return [passwordItem_ view];
+}
+
+- (BOOL)shouldShowGoogleSmartLockWelcome {
+  return self.model->ShouldShowGoogleSmartLockWelcome();
+}
+
+- (NSArray*)createButtonsAndAddThemToView:(NSView*)view {
+  // Save button.
+  saveButton_.reset(
+      [[self addButton:l10n_util::GetNSString(IDS_PASSWORD_MANAGER_SAVE_BUTTON)
+                toView:view
+                target:self
+                action:@selector(onSaveClicked:)] retain]);
+
+  // Never button.
+  NSString* neverButtonText =
+      l10n_util::GetNSString(IDS_PASSWORD_MANAGER_BUBBLE_BLACKLIST_BUTTON);
+  neverButton_.reset(
+      [[self addButton:neverButtonText
+                toView:view
+                target:self
+                action:@selector(onNeverForThisSiteClicked:)] retain]);
+  return @[ saveButton_, neverButton_ ];
+}
+
+@end
+
+@implementation SavePendingPasswordViewController (Testing)
+
+- (NSButton*)saveButton {
+  return saveButton_.get();
+}
+
+- (NSButton*)neverButton {
+  return neverButton_.get();
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/passwords/pending_password_view_controller_unittest.mm b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller_unittest.mm
similarity index 77%
rename from chrome/browser/ui/cocoa/passwords/pending_password_view_controller_unittest.mm
rename to chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller_unittest.mm
index dd204b7..ace1e94 100644
--- a/chrome/browser/ui/cocoa/passwords/pending_password_view_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller_unittest.mm
@@ -10,7 +10,7 @@
 #import "chrome/browser/ui/cocoa/bubble_combobox.h"
 #include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.h"
-#import "chrome/browser/ui/cocoa/passwords/pending_password_view_controller.h"
+#import "chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.h"
 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -18,10 +18,10 @@
 
 namespace {
 
-class ManagePasswordsBubblePendingViewControllerTest
+class SavePendingPasswordViewControllerTest
     : public ManagePasswordsControllerTest {
  public:
-  ManagePasswordsBubblePendingViewControllerTest() {}
+  SavePendingPasswordViewControllerTest() {}
 
   void SetUp() override {
     ManagePasswordsControllerTest::SetUp();
@@ -31,9 +31,9 @@
 
   ContentViewDelegateMock* delegate() { return delegate_.get(); }
 
-  ManagePasswordsBubblePendingViewController* controller() {
+  SavePendingPasswordViewController* controller() {
     if (!controller_) {
-      controller_.reset([[ManagePasswordsBubblePendingViewController alloc]
+      controller_.reset([[SavePendingPasswordViewController alloc]
           initWithModel:GetModelAndCreateIfNull()
                delegate:delegate()]);
       [controller_ loadView];
@@ -42,11 +42,11 @@
   }
 
  private:
-  base::scoped_nsobject<ManagePasswordsBubblePendingViewController> controller_;
+  base::scoped_nsobject<SavePendingPasswordViewController> controller_;
   base::scoped_nsobject<ContentViewDelegateMock> delegate_;
 };
 
-TEST_F(ManagePasswordsBubblePendingViewControllerTest,
+TEST_F(SavePendingPasswordViewControllerTest,
        ShouldSavePasswordAndDismissWhenSaveClicked) {
   EXPECT_CALL(*ui_controller(), SavePassword());
   EXPECT_CALL(*ui_controller(), NeverSavePassword()).Times(0);
@@ -55,7 +55,7 @@
   EXPECT_TRUE([delegate() dismissed]);
 }
 
-TEST_F(ManagePasswordsBubblePendingViewControllerTest,
+TEST_F(SavePendingPasswordViewControllerTest,
        ShouldNeverAndDismissWhenNeverClicked) {
   EXPECT_CALL(*ui_controller(), SavePassword()).Times(0);
   EXPECT_CALL(*ui_controller(), NeverSavePassword());
@@ -64,8 +64,7 @@
   EXPECT_TRUE([delegate() dismissed]);
 }
 
-TEST_F(ManagePasswordsBubblePendingViewControllerTest,
-       ShouldDismissWhenCrossClicked) {
+TEST_F(SavePendingPasswordViewControllerTest, ShouldDismissWhenCrossClicked) {
   EXPECT_CALL(*ui_controller(), SavePassword()).Times(0);
   EXPECT_CALL(*ui_controller(), NeverSavePassword()).Times(0);
   [controller().closeButton performClick:nil];
diff --git a/chrome/browser/ui/content_settings/content_setting_image_model.cc b/chrome/browser/ui/content_settings/content_setting_image_model.cc
index 93493b8..56d5221 100644
--- a/chrome/browser/ui/content_settings/content_setting_image_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_image_model.cc
@@ -15,13 +15,10 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/vector_icons_public.h"
-
-#if !defined(OS_MACOSX)
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/paint_vector_icon.h"
-#endif
+#include "ui/gfx/vector_icons_public.h"
 
 using content::WebContents;
 
@@ -311,7 +308,6 @@
   if (!UseVectorGraphics()) {
     DCHECK(icon_id);
     SetIconByResourceId(icon_id);
-#if !defined(OS_MACOSX)
   } else {
     gfx::VectorIconId badge_id = gfx::VectorIconId::VECTOR_ICON_NONE;
     if (type == CONTENT_SETTINGS_TYPE_PPAPI_BROKER)
@@ -320,7 +316,6 @@
       badge_id = gfx::VectorIconId::BLOCKED_BADGE;
 
     set_icon_by_vector_id(image_details->vector_icon_id, badge_id);
-#endif
   }
   set_explanatory_string_id(explanation_id);
   DCHECK(tooltip_id);
@@ -356,12 +351,10 @@
       !!(state_flags & ContentSettingsUsagesState::TABSTATE_HAS_ANY_ALLOWED);
   if (!UseVectorGraphics()) {
     SetIconByResourceId(allowed ? IDR_ALLOWED_LOCATION : IDR_BLOCKED_LOCATION);
-#if !defined(OS_MACOSX)
   } else {
     set_icon_by_vector_id(gfx::VectorIconId::MY_LOCATION,
                           allowed ? gfx::VectorIconId::VECTOR_ICON_NONE
                                   : gfx::VectorIconId::BLOCKED_BADGE);
-#endif
   }
   set_tooltip(l10n_util::GetStringUTF16(allowed
                                             ? IDS_GEOLOCATION_ALLOWED_TOOLTIP
@@ -402,22 +395,18 @@
                TabSpecificContentSettings::CAMERA_BLOCKED)) {
     if (!UseVectorGraphics()) {
       SetIconByResourceId(IDR_BLOCKED_CAMERA);
-#if !defined(OS_MACOSX)
     } else {
       set_icon_by_vector_id(gfx::VectorIconId::VIDEOCAM,
                             gfx::VectorIconId::BLOCKED_BADGE);
-#endif
     }
     if (is_mic)
       id = is_cam ? IDS_MICROPHONE_CAMERA_BLOCKED : IDS_MICROPHONE_BLOCKED;
   } else {
     if (!UseVectorGraphics()) {
       SetIconByResourceId(IDR_ALLOWED_CAMERA);
-#if !defined(OS_MACOSX)
     } else {
       set_icon_by_vector_id(gfx::VectorIconId::VIDEOCAM,
                             gfx::VectorIconId::VECTOR_ICON_NONE);
-#endif
     }
     id = IDS_CAMERA_ACCESSED;
     if (is_mic)
@@ -474,11 +463,9 @@
     : ContentSettingSimpleImageModel(CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS) {
   if (!UseVectorGraphics()) {
     SetIconByResourceId(IDR_REGISTER_PROTOCOL_HANDLER);
-#if !defined(OS_MACOSX)
   } else {
     set_icon_by_vector_id(gfx::VectorIconId::PROTOCOL_HANDLER,
                           gfx::VectorIconId::VECTOR_ICON_NONE);
-#endif
   }
   set_tooltip(l10n_util::GetStringUTF16(IDS_REGISTER_PROTOCOL_HANDLER_TOOLTIP));
 }
@@ -529,12 +516,10 @@
   if (!UseVectorGraphics()) {
     SetIconByResourceId(allowed ? IDR_ALLOWED_MIDI_SYSEX
                                 : IDR_BLOCKED_MIDI_SYSEX);
-#if !defined(OS_MACOSX)
   } else {
     set_icon_by_vector_id(gfx::VectorIconId::MIDI,
                           allowed ? gfx::VectorIconId::VECTOR_ICON_NONE
                                   : gfx::VectorIconId::BLOCKED_BADGE);
-#endif
   }
   set_tooltip(l10n_util::GetStringUTF16(allowed
                                             ? IDS_MIDI_SYSEX_ALLOWED_TOOLTIP
@@ -543,20 +528,18 @@
 
 // Base class ------------------------------------------------------------------
 
-#if !defined(OS_MACOSX)
 gfx::Image ContentSettingImageModel::GetIcon(SkColor nearby_text_color) const {
   return UseVectorGraphics()
              ? gfx::Image(gfx::CreateVectorIconWithBadge(
                    vector_icon_id_, 16,
                    color_utils::DeriveDefaultIconColor(nearby_text_color),
                    vector_icon_badge_id_))
-             : icon_;
+             : raster_icon_;
 }
-#endif
 
 ContentSettingImageModel::ContentSettingImageModel()
     : is_visible_(false),
-      icon_id_(0),
+      raster_icon_id_(0),
       vector_icon_id_(gfx::VectorIconId::VECTOR_ICON_NONE),
       vector_icon_badge_id_(gfx::VectorIconId::VECTOR_ICON_NONE),
       explanatory_string_id_(0) {}
@@ -594,6 +577,7 @@
 }
 
 void ContentSettingImageModel::SetIconByResourceId(int id) {
-  icon_id_ = id;
-  icon_ = ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(id);
+  raster_icon_id_ = id;
+  raster_icon_ =
+      ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(id);
 }
diff --git a/chrome/browser/ui/content_settings/content_setting_image_model.h b/chrome/browser/ui/content_settings/content_setting_image_model.h
index d121b0e..2fe8523 100644
--- a/chrome/browser/ui/content_settings/content_setting_image_model.h
+++ b/chrome/browser/ui/content_settings/content_setting_image_model.h
@@ -49,12 +49,14 @@
   virtual void SetAnimationHasRun(content::WebContents* web_contents) = 0;
 
   bool is_visible() const { return is_visible_; }
+
 #if defined(OS_MACOSX)
-  const gfx::Image& icon() const { return icon_; }
-  int icon_id() const { return icon_id_; }
-#else
-  gfx::Image GetIcon(SkColor nearby_text_color) const;
+  const gfx::Image& raster_icon() const { return raster_icon_; }
+  int raster_icon_id() const { return raster_icon_id_; }
 #endif
+
+  gfx::Image GetIcon(SkColor nearby_text_color) const;
+
   // Returns the resource ID of a string to show when the icon appears, or 0 if
   // we don't wish to show anything.
   int explanatory_string_id() const { return explanatory_string_id_; }
@@ -63,14 +65,13 @@
  protected:
   ContentSettingImageModel();
   void SetIconByResourceId(int id);
-#if !defined(OS_MACOSX)
+
   void set_icon_by_vector_id(gfx::VectorIconId id, gfx::VectorIconId badge_id) {
     vector_icon_id_ = id;
     vector_icon_badge_id_ = badge_id;
   }
-#endif
+
   void set_visible(bool visible) { is_visible_ = visible; }
-  void set_icon(const gfx::Image& image) { icon_ = image; }
   void set_explanatory_string_id(int text_id) {
     explanatory_string_id_ = text_id;
   }
@@ -78,9 +79,11 @@
 
  private:
   bool is_visible_;
-  // |icon_id_| and |icon_| are only used for pre-MD.
-  int icon_id_;
-  gfx::Image icon_;
+
+  // |raster_icon_id_| and |raster_icon_| are only used for pre-MD.
+  int raster_icon_id_;
+  gfx::Image raster_icon_;
+
   // Vector icons are used for MD.
   gfx::VectorIconId vector_icon_id_;
   gfx::VectorIconId vector_icon_badge_id_;
diff --git a/chrome/browser/ui/content_settings/content_setting_image_model_unittest.cc b/chrome/browser/ui/content_settings/content_setting_image_model_unittest.cc
index 8ff6be80..ac38fec 100644
--- a/chrome/browser/ui/content_settings/content_setting_image_model_unittest.cc
+++ b/chrome/browser/ui/content_settings/content_setting_image_model_unittest.cc
@@ -23,11 +23,7 @@
 namespace {
 
 bool HasIcon(const ContentSettingImageModel& model) {
-#if defined(OS_MACOSX)
-  return !model.icon().IsEmpty();
-#else
   return !model.GetIcon(gfx::kPlaceholderColor).IsEmpty();
-#endif
 }
 
 // Forward all NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED to the specified
diff --git a/chrome/browser/ui/extensions/extension_installed_bubble.cc b/chrome/browser/ui/extensions/extension_installed_bubble.cc
index 0f8accb2..e9ba2b98 100644
--- a/chrome/browser/ui/extensions/extension_installed_bubble.cc
+++ b/chrome/browser/ui/extensions/extension_installed_bubble.cc
@@ -56,6 +56,8 @@
                    content::Source<Browser>(bubble_->browser()));
   }
 
+  void Run() { OnExtensionLoaded(nullptr, bubble_->extension()); }
+
  private:
   ~ExtensionInstalledBubbleObserver() override {}
 
@@ -169,8 +171,13 @@
     const SkBitmap& icon) {
   // The ExtensionInstalledBubbleObserver will delete itself when the
   // ExtensionInstalledBubble is shown or when it can't be shown anymore.
-  new ExtensionInstalledBubbleObserver(
+  auto x = new ExtensionInstalledBubbleObserver(
       make_scoped_ptr(new ExtensionInstalledBubble(extension, browser, icon)));
+  extensions::ExtensionRegistry* reg =
+      extensions::ExtensionRegistry::Get(browser->profile());
+  if (reg->enabled_extensions().GetByID(extension->id())) {
+    x->Run();
+  }
 }
 
 ExtensionInstalledBubble::ExtensionInstalledBubble(const Extension* extension,
diff --git a/chrome/browser/ui/views/layout_constants.cc b/chrome/browser/ui/layout_constants.cc
similarity index 86%
rename from chrome/browser/ui/views/layout_constants.cc
rename to chrome/browser/ui/layout_constants.cc
index 0c55c03..3a4a34a 100644
--- a/chrome/browser/ui/views/layout_constants.cc
+++ b/chrome/browser/ui/layout_constants.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 "chrome/browser/ui/views/layout_constants.h"
+#include "chrome/browser/ui/layout_constants.h"
 
 #include "base/logging.h"
 #include "ui/base/resource/material_design/material_design_controller.h"
@@ -17,23 +17,23 @@
   const int kLocationBarHeight[] = {27, 28, 32};
   const int kLocationBarHorizontalPadding[] = {3, 6, 6};
   const int kLocationBarVerticalPadding[] = {2, 2, 2};
-  const int kNewTabButtonWidth[] = {34, 34, 34};
+  const int kNewTabButtonWidth[] = {34, 36, 36};
   const int kOmniboxDropdownBorderInterior[] = {6, 0, 0};
   const int kOmniboxFontPixelSize[] = {16, 14, 14};
-  const int kTabCloseButtonTrailingPaddingOverlap[] = {2, 2, 2};
-  const int kTabFaviconTitleSpacing[] = {4, 4, 4};
-  const int kTabMaximumTitleWidth[] = {175, 175, 175};
-  const int kTabPinnedContentWidth[] = {25, 25, 25};
+  const int kTabCloseButtonTrailingPaddingOverlap[] = {2, 0, 0};
+  const int kTabFaviconTitleSpacing[] = {4, 6, 6};
+  const int kTabMaximumTitleWidth[] = {175, 171, 171};
+  const int kTabPinnedContentWidth[] = {25, 23, 23};
 #if defined(OS_MACOSX)
   const int kTabTopExclusionHeight[] = {0, 0, 0};
-  const int kTabstripNewTabButtonOverlap[] = {8, 8, 8};
-  const int kTabstripTabOverlap[] = {19, 19, 19};
+  const int kTabstripNewTabButtonOverlap[] = {8, 5, 5};
+  const int kTabstripTabOverlap[] = {19, 16, 16};
 #else
-  const int kTabTopExclusionHeight[] = {2, 2, 2};
-  const int kTabstripNewTabButtonOverlap[] = {11, 11, 11};
-  const int kTabstripTabOverlap[] = {26, 26, 26};
+  const int kTabTopExclusionHeight[] = {2, 0, 0};
+  const int kTabstripNewTabButtonOverlap[] = {11, 5, 5};
+  const int kTabstripTabOverlap[] = {26, 16, 16};
 #endif
-  const int kTabstripToolbarOverlap[] = {3, 3, 3};
+  const int kTabstripToolbarOverlap[] = {3, 0, 0};
   const int kToolbarContentShadowHeight[] = {0, 0, 0};
   const int kToolbarContentShadowHeightAsh[] = {2, 0, 0};
   const int kToolbarElementPadding[] = {0, 0, 8};
@@ -104,10 +104,10 @@
   const int kOmniboxDropdownIconPadding[] = {2, 4, 8};
   const int kOmniboxDropdownPadding[] = {3, 4, 4};
   const int kOmniboxDropdownTextPadding[] = {3, 3, 3};
-  const int kTabBottomPadding[] = {2, 2, 2};
-  const int kTabLeftPadding[] = {20, 20, 20};
-  const int kTabRightPadding[] = {20, 20, 20};
-  const int kTabTopPadding[] = {4, 4, 4};
+  const int kTabBottomPadding[] = {2, 1, 1};
+  const int kTabLeftPadding[] = {20, 16, 16};
+  const int kTabRightPadding[] = {20, 16, 16};
+  const int kTabTopPadding[] = {4, 1, 1};
   const int kToolbarBottomPadding[] = {5, 5, 5};
   const int kToolbarButtonPadding[] = {2, 6, 6};
   const int kToolbarLeftPadding[] = {3, 4, 8};
diff --git a/chrome/browser/ui/views/layout_constants.h b/chrome/browser/ui/layout_constants.h
similarity index 93%
rename from chrome/browser/ui/views/layout_constants.h
rename to chrome/browser/ui/layout_constants.h
index 352a1e0d..603f094b 100644
--- a/chrome/browser/ui/views/layout_constants.h
+++ b/chrome/browser/ui/layout_constants.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_VIEWS_LAYOUT_CONSTANTS_H_
-#define CHROME_BROWSER_UI_VIEWS_LAYOUT_CONSTANTS_H_
+#ifndef CHROME_BROWSER_UI_LAYOUT_CONSTANTS_H_
+#define CHROME_BROWSER_UI_LAYOUT_CONSTANTS_H_
 
 #include "ui/gfx/geometry/insets.h"
 
@@ -88,7 +88,8 @@
   // Additional horizontal padding between the elements in the toolbar.
   TOOLBAR_ELEMENT_PADDING,
 
-  // Padding between the right-edge of the location bar and browser actions.
+  // Padding between the right edge of the location bar and the left edge of the
+  // app menu icon when the browser actions container is not present.
   TOOLBAR_LOCATION_BAR_RIGHT_PADDING,
 
   // The horizontal space between most items in the toolbar.
@@ -126,4 +127,4 @@
 int GetLayoutConstant(LayoutConstant constant);
 gfx::Insets GetLayoutInsets(LayoutInset inset);
 
-#endif  // CHROME_BROWSER_UI_VIEWS_LAYOUT_CONSTANTS_H_
+#endif  // CHROME_BROWSER_UI_LAYOUT_CONSTANTS_H_
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.cc b/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.cc
index 39ddb25..ff00223 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.cc
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.cc
@@ -6,6 +6,7 @@
 
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/command_updater.h"
+#include "components/toolbar/toolbar_model.h"
 
 ChromeOmniboxEditController::ChromeOmniboxEditController(
     CommandUpdater* command_updater)
@@ -22,3 +23,8 @@
   if (command_updater_)
     command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
 }
+
+void ChromeOmniboxEditController::OnInputInProgress(bool in_progress) {
+  GetToolbarModel()->set_input_in_progress(in_progress);
+  UpdateWithoutTabRestore();
+}
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h b/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h
index 386b5e9..f6f5ab9 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h
@@ -19,6 +19,10 @@
   // Returns the WebContents of the currently active tab.
   virtual content::WebContents* GetWebContents() = 0;
 
+  // Called when the the controller should update itself without restoring any
+  // tab state.
+  virtual void UpdateWithoutTabRestore() = 0;
+
   CommandUpdater* command_updater() { return command_updater_; }
   const CommandUpdater* command_updater() const { return command_updater_; }
 
@@ -31,6 +35,7 @@
   void OnAutocompleteAccept(const GURL& destination_url,
                             WindowOpenDisposition disposition,
                             ui::PageTransition transition) override;
+  void OnInputInProgress(bool in_progress) override;
 
   CommandUpdater* command_updater_;
 
diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc
index 6af21fd..e832fb5 100644
--- a/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <vector>
+
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_samples.h"
 #include "base/prefs/pref_service.h"
@@ -11,6 +13,7 @@
 #include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/browser/sync/profile_sync_test_util.h"
 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h"
 #include "chrome/test/base/testing_profile.h"
@@ -44,7 +47,8 @@
 class TestSyncService : public ProfileSyncServiceMock {
  public:
   explicit TestSyncService(Profile* profile)
-      : ProfileSyncServiceMock(profile), smartlock_enabled_(false) {}
+      : ProfileSyncServiceMock(CreateProfileSyncServiceParamsForTest(profile)),
+        smartlock_enabled_(false) {}
   ~TestSyncService() override {}
 
   // FakeSyncService:
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
index a333c5a6..83ce991 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/location_bar/location_bar.h"
-#include "chrome/browser/ui/passwords/manage_passwords_icon_view.h"
 #include "chrome/browser/ui/tab_dialogs.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
@@ -28,6 +27,12 @@
 #include "content/public/browser/navigation_details.h"
 #include "ui/base/l10n/l10n_util.h"
 
+#if BUILDFLAG(ANDROID_JAVA_UI)
+#include "chrome/browser/android/chrome_application.h"
+#else
+#include "chrome/browser/ui/passwords/manage_passwords_icon_view.h"
+#endif
+
 using autofill::PasswordFormMap;
 using password_manager::PasswordFormManager;
 
@@ -144,6 +149,7 @@
     UpdateBubbleAndIconVisibility();
 }
 
+#if !BUILDFLAG(ANDROID_JAVA_UI)
 void ManagePasswordsUIController::UpdateIconAndBubbleState(
     ManagePasswordsIconView* icon) {
   if (should_pop_up_bubble_) {
@@ -155,6 +161,7 @@
     icon->SetState(GetState());
   }
 }
+#endif
 
 const GURL& ManagePasswordsUIController::GetOrigin() const {
   return passwords_data_.origin();
@@ -264,26 +271,38 @@
 }
 
 void ManagePasswordsUIController::NavigateToExternalPasswordManager() {
+#if BUILDFLAG(ANDROID_JAVA_UI)
+  NOTREACHED();
+#else
   chrome::NavigateParams params(
       chrome::FindBrowserWithWebContents(web_contents()),
       GURL(password_manager::kPasswordManagerAccountDashboardURL),
       ui::PAGE_TRANSITION_LINK);
   params.disposition = NEW_FOREGROUND_TAB;
   chrome::Navigate(&params);
+#endif
 }
 
 void ManagePasswordsUIController::NavigateToSmartLockHelpPage() {
+#if BUILDFLAG(ANDROID_JAVA_UI)
+  NOTREACHED();
+#else
   chrome::NavigateParams params(
       chrome::FindBrowserWithWebContents(web_contents()),
       GURL(chrome::kSmartLockHelpPage), ui::PAGE_TRANSITION_LINK);
   params.disposition = NEW_FOREGROUND_TAB;
   chrome::Navigate(&params);
+#endif
 }
 
 void ManagePasswordsUIController::NavigateToPasswordManagerSettingsPage() {
+#if BUILDFLAG(ANDROID_JAVA_UI)
+  chrome::android::ChromeApplication::ShowPasswordSettings();
+#else
   chrome::ShowSettingsSubPage(
       chrome::FindBrowserWithWebContents(web_contents()),
       chrome::kPasswordManagerSubPage);
+#endif
 }
 
 void ManagePasswordsUIController::SavePasswordInternal() {
@@ -321,12 +340,14 @@
     passwords_data_.OnInactive();
   }
 
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
   if (!browser)
     return;
   LocationBar* location_bar = browser->window()->GetLocationBar();
   DCHECK(location_bar);
   location_bar->UpdateManagePasswordsIconAndBubble();
+#endif
 }
 
 base::TimeDelta ManagePasswordsUIController::Elapsed() const {
@@ -354,17 +375,21 @@
 }
 
 void ManagePasswordsUIController::WasHidden() {
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   TabDialogs::FromWebContents(web_contents())->HideManagePasswordsBubble();
+#endif
 }
 
 void ManagePasswordsUIController::ShowBubbleWithoutUserInteraction() {
   DCHECK(should_pop_up_bubble_);
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
   if (!browser || browser->toolbar_model()->input_in_progress())
     return;
 
   CommandUpdater* updater = browser->command_controller()->command_updater();
   updater->ExecuteCommand(IDC_MANAGE_PASSWORDS_FOR_PAGE);
+#endif
 }
 
 void ManagePasswordsUIController::WebContentsDestroyed() {
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.h b/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
index bd7ba77f..dd745998 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
@@ -58,9 +58,11 @@
   void OnLoginsChanged(
       const password_manager::PasswordStoreChangeList& changes) override;
 
+#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);
+#endif
 
   bool IsAutomaticallyOpeningBubble() const { return should_pop_up_bubble_; }
 
diff --git a/chrome/browser/ui/passwords/manage_passwords_view_utils_desktop_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_view_utils_desktop_unittest.cc
index caf103a..cb63bbd 100644
--- a/chrome/browser/ui/passwords/manage_passwords_view_utils_desktop_unittest.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_view_utils_desktop_unittest.cc
@@ -8,7 +8,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/mock_entropy_provider.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/browser/sync/profile_sync_test_util.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/browser_sync/browser/profile_sync_service.h"
@@ -49,7 +49,7 @@
 
   void SetUp() override {
     ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-        &profile_, &ProfileSyncServiceMock::BuildMockProfileSyncService);
+        &profile_, &BuildMockProfileSyncService);
   };
 
   Profile* profile() { return &profile_; }
diff --git a/chrome/browser/ui/prefs/prefs_tab_helper.cc b/chrome/browser/ui/prefs/prefs_tab_helper.cc
index 1eb12687..50fc060 100644
--- a/chrome/browser/ui/prefs/prefs_tab_helper.cc
+++ b/chrome/browser/ui/prefs/prefs_tab_helper.cc
@@ -7,7 +7,9 @@
 #include <set>
 #include <string>
 
+#include "base/command_line.h"
 #include "base/memory/singleton.h"
+#include "base/metrics/field_trial.h"
 #include "base/prefs/overlay_user_pref_store.h"
 #include "base/prefs/pref_change_registrar.h"
 #include "base/prefs/pref_service.h"
@@ -318,6 +320,14 @@
   registry->RegisterIntegerPref(path, val);
 }
 
+bool IsAutodetectEncodingEnabledByDefault() {
+  const std::string group_name = base::FieldTrialList::FindFullName(
+      "AutodetectEncoding");
+  return base::StartsWith(group_name,
+                          "Enabled",
+                          base::CompareCase::INSENSITIVE_ASCII);
+}
+
 }  // namespace
 
 // Watching all these settings per tab is slow when a user has a lot of tabs and
@@ -581,9 +591,11 @@
                             IDS_MINIMUM_FONT_SIZE);
   RegisterLocalizedFontPref(registry, prefs::kWebKitMinimumLogicalFontSize,
                             IDS_MINIMUM_LOGICAL_FONT_SIZE);
+  bool uses_universal_detector = IsAutodetectEncodingEnabledByDefault() ||
+      l10n_util::GetStringUTF8(IDS_USES_UNIVERSAL_DETECTOR) == "true";
   registry->RegisterBooleanPref(
       prefs::kWebKitUsesUniversalDetector,
-      l10n_util::GetStringUTF8(IDS_USES_UNIVERSAL_DETECTOR) == "true",
+      uses_universal_detector,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterStringPref(
       prefs::kStaticEncodings,
diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc
index e071a4e2..e20bcfe 100644
--- a/chrome/browser/ui/search/search_tab_helper.cc
+++ b/chrome/browser/ui/search/search_tab_helper.cc
@@ -388,6 +388,24 @@
   // our metrics get inconsistent. So we'd rather emit stats now.
   InstantTab::EmitNtpStatistics(web_contents_);
   ipc_router_.SendMostVisitedItems(items);
+  LogMostVisitedItemsSource(items);
+}
+
+void SearchTabHelper::LogMostVisitedItemsSource(
+    const std::vector<InstantMostVisitedItem>& items) {
+  for (auto item : items) {
+    NTPLoggingEventType event;
+    if (item.is_server_side_suggestion) {
+      event = NTP_SERVER_SIDE_SUGGESTION;
+    } else {
+      event = NTP_CLIENT_SIDE_SUGGESTION;
+    }
+    // The metrics are emitted for each suggestion as the design requirement
+    // even the ntp_user_data_logger.cc now only supports the scenario:
+    // all suggestions are provided by server OR
+    // all suggestions are provided by client.
+    this->OnLogEvent(event, base::TimeDelta());
+  }
 }
 
 void SearchTabHelper::OmniboxStartMarginChanged(int omnibox_start_margin) {
diff --git a/chrome/browser/ui/search/search_tab_helper.h b/chrome/browser/ui/search/search_tab_helper.h
index 6c5bea9..1471c7b2 100644
--- a/chrome/browser/ui/search/search_tab_helper.h
+++ b/chrome/browser/ui/search/search_tab_helper.h
@@ -125,6 +125,10 @@
                            OnHistorySyncCheckSyncing);
   FRIEND_TEST_ALL_PREFIXES(SearchTabHelperTest,
                            OnHistorySyncCheckNotSyncing);
+  FRIEND_TEST_ALL_PREFIXES(SearchTabHelperTest,
+                           OnMostVisitedItemsChangedFromServer);
+  FRIEND_TEST_ALL_PREFIXES(SearchTabHelperTest,
+                           OnMostVisitedItemsChangedFromClient);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest,
                            IgnoreMessageIfThePageIsNotActive);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest,
@@ -201,6 +205,10 @@
   // Returns the OmniboxView for |web_contents_| or NULL if not available.
   OmniboxView* GetOmniboxView() const;
 
+  // Record whether each suggestion comes from server or client.
+  void LogMostVisitedItemsSource(
+      const std::vector<InstantMostVisitedItem>& items);
+
   typedef bool (*OmniboxHasFocusFn)(OmniboxView*);
 
   void set_omnibox_has_focus_fn(OmniboxHasFocusFn fn) {
diff --git a/chrome/browser/ui/search/search_tab_helper_unittest.cc b/chrome/browser/ui/search/search_tab_helper_unittest.cc
index ecfc8c0..83a613e9 100644
--- a/chrome/browser/ui/search/search_tab_helper_unittest.cc
+++ b/chrome/browser/ui/search/search_tab_helper_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/search/search_tab_helper.h"
 
+#include <string>
+
 #include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/field_trial.h"
@@ -17,9 +19,10 @@
 #include "chrome/browser/signin/fake_signin_manager_builder.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/browser/sync/profile_sync_test_util.h"
 #include "chrome/browser/ui/search/search_ipc_router.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/ntp_logging_events.h"
 #include "chrome/common/render_messages.h"
@@ -83,9 +86,8 @@
     TestingProfile::Builder builder;
     builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
                               BuildFakeSigninManagerBase);
-    builder.AddTestingFactory(
-        ProfileSyncServiceFactory::GetInstance(),
-        ProfileSyncServiceMock::BuildMockProfileSyncService);
+    builder.AddTestingFactory(ProfileSyncServiceFactory::GetInstance(),
+                              BuildMockProfileSyncService);
     return builder.Build().release();
   }
 
@@ -315,6 +317,46 @@
   ASSERT_FALSE(base::get<0>(params));
 }
 
+TEST_F(SearchTabHelperTest, OnMostVisitedItemsChangedFromServer) {
+  InstantMostVisitedItem item;
+  item.is_server_side_suggestion = true;
+  std::vector<InstantMostVisitedItem> items;
+  items.push_back(item);
+
+  SearchTabHelper* search_tab_helper =
+      SearchTabHelper::FromWebContents(web_contents());
+  ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
+
+  auto logger = NTPUserDataLogger::GetOrCreateFromWebContents(web_contents());
+  ASSERT_FALSE(logger->has_server_side_suggestions_);
+  ASSERT_FALSE(logger->has_client_side_suggestions_);
+
+  search_tab_helper->MostVisitedItemsChanged(items);
+
+  ASSERT_TRUE(logger->has_server_side_suggestions_);
+  ASSERT_FALSE(logger->has_client_side_suggestions_);
+}
+
+TEST_F(SearchTabHelperTest, OnMostVisitedItemsChangedFromClient) {
+  InstantMostVisitedItem item;
+  item.is_server_side_suggestion = false;
+  std::vector<InstantMostVisitedItem> items;
+  items.push_back(item);
+
+  SearchTabHelper* search_tab_helper =
+      SearchTabHelper::FromWebContents(web_contents());
+  ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
+
+  auto logger = NTPUserDataLogger::GetOrCreateFromWebContents(web_contents());
+  ASSERT_FALSE(logger->has_server_side_suggestions_);
+  ASSERT_FALSE(logger->has_client_side_suggestions_);
+
+  search_tab_helper->MostVisitedItemsChanged(items);
+
+  ASSERT_FALSE(logger->has_server_side_suggestions_);
+  ASSERT_TRUE(logger->has_client_side_suggestions_);
+}
+
 class TabTitleObserver : public content::WebContentsObserver {
  public:
   explicit TabTitleObserver(content::WebContents* contents)
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 98cb2c4..f5ab94c 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -681,10 +681,6 @@
     // specified on the command line. Filter out any urls that are to be
     // restored by virtue of having been previously pinned.
     AddUniqueURLs(pref.urls, &tabs);
-  } else if (pref.type == SessionStartupPref::HOMEPAGE) {
-    // If 'homepage' selected, either by the user or by a policy, we should
-    // have migrated them to another value.
-    NOTREACHED() << "SessionStartupPref has deprecated type HOMEPAGE";
   }
 
   if (tabs.empty())
diff --git a/chrome/browser/ui/sync/bubble_sync_promo_delegate.h b/chrome/browser/ui/sync/bubble_sync_promo_delegate.h
new file mode 100644
index 0000000..0bc1c21
--- /dev/null
+++ b/chrome/browser/ui/sync/bubble_sync_promo_delegate.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 CHROME_BROWSER_UI_SYNC_BUBBLE_SYNC_PROMO_DELEGATE_H_
+#define CHROME_BROWSER_UI_SYNC_BUBBLE_SYNC_PROMO_DELEGATE_H_
+
+class BubbleSyncPromoDelegate {
+ public:
+  virtual ~BubbleSyncPromoDelegate() {}
+  virtual void OnSignInLinkClicked() = 0;
+};
+
+#endif  // CHROME_BROWSER_UI_SYNC_BUBBLE_SYNC_PROMO_DELEGATE_H_
diff --git a/chrome/browser/ui/sync/inline_login_dialog.cc b/chrome/browser/ui/sync/inline_login_dialog.cc
deleted file mode 100644
index dfd056d..0000000
--- a/chrome/browser/ui/sync/inline_login_dialog.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/sync/inline_login_dialog.h"
-
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser_dialogs.h"
-#include "chrome/common/url_constants.h"
-#include "ui/gfx/geometry/size.h"
-#include "url/gurl.h"
-
-// static
-void InlineLoginDialog::Show(Profile* profile) {
-  chrome::ShowWebDialog(NULL, profile, new InlineLoginDialog());
-}
-
-InlineLoginDialog::InlineLoginDialog() {
-}
-
-ui::ModalType InlineLoginDialog::GetDialogModalType() const {
-  return ui::MODAL_TYPE_SYSTEM;
-}
-
-base::string16 InlineLoginDialog::GetDialogTitle() const {
-  return base::string16();
-}
-
-GURL InlineLoginDialog::GetDialogContentURL() const {
-  return GURL(chrome::kChromeUIChromeSigninURL);
-}
-
-void InlineLoginDialog::GetWebUIMessageHandlers(
-    std::vector<content::WebUIMessageHandler*>* handlers) const {
-}
-
-void InlineLoginDialog::GetDialogSize(gfx::Size* size) const {
-  size->SetSize(380, 290);
-}
-
-std::string InlineLoginDialog::GetDialogArgs() const {
-  return "[]";
-}
-
-void InlineLoginDialog::OnDialogClosed(const std::string& json_retval) {
-  delete this;
-}
-
-void InlineLoginDialog::OnCloseContents(
-    content::WebContents* source, bool* out_close_dialog) {
-  *out_close_dialog = true;
-}
-
-bool InlineLoginDialog::ShouldShowDialogTitle() const {
-  return false;
-}
-
-bool InlineLoginDialog::HandleContextMenu(
-    const content::ContextMenuParams& params) {
-  return true;
-}
diff --git a/chrome/browser/ui/sync/inline_login_dialog.h b/chrome/browser/ui/sync/inline_login_dialog.h
deleted file mode 100644
index 71c42fb..0000000
--- a/chrome/browser/ui/sync/inline_login_dialog.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_SYNC_INLINE_LOGIN_DIALOG_H_
-#define CHROME_BROWSER_UI_SYNC_INLINE_LOGIN_DIALOG_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "ui/web_dialogs/web_dialog_delegate.h"
-
-class Profile;
-
-// A dialog to host the inline sign-in WebUI. Currently, it loads
-// chrome:://chrome-signin and dismisses itself when the sign-in is finished
-// successfully.
-class InlineLoginDialog : public ui::WebDialogDelegate {
- public:
-  static void Show(Profile* profile);
-
- private:
-  InlineLoginDialog();
-
-  // ui::WebDialogDelegate overrides:
-  ui::ModalType GetDialogModalType() const override;
-  base::string16 GetDialogTitle() const override;
-  GURL GetDialogContentURL() const override;
-  void GetWebUIMessageHandlers(
-      std::vector<content::WebUIMessageHandler*>* handlers) const override;
-  void GetDialogSize(gfx::Size* size) const override;
-  std::string GetDialogArgs() const override;
-  void OnDialogClosed(const std::string& json_retval) override;
-  void OnCloseContents(content::WebContents* source,
-                       bool* out_close_dialog) override;
-  bool ShouldShowDialogTitle() const override;
-  bool HandleContextMenu(const content::ContextMenuParams& params) override;
-
-  DISALLOW_COPY_AND_ASSIGN(InlineLoginDialog);
-};
-
-#endif  // CHROME_BROWSER_UI_SYNC_INLINE_LOGIN_DIALOG_H_
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
index 6a0c0e1..e25a56b 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -40,6 +40,7 @@
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/signin/core/browser/signin_metrics.h"
 #include "components/sync_driver/sync_prefs.h"
+#include "net/base/url_util.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -534,15 +535,17 @@
     bool use_same_tab = false;
     if (web_contents()) {
       GURL current_url = web_contents()->GetLastCommittedURL();
+      std::string constrained_key;
+      net::GetValueForKeyInQuery(current_url, "constrained", &constrained_key);
+      bool is_constrained = (constrained_key == "1");
       bool is_chrome_signin_url =
           current_url.GetOrigin().spec() == chrome::kChromeUIChromeSigninURL;
       bool is_same_profile =
           Profile::FromBrowserContext(web_contents()->GetBrowserContext()) ==
           profile_;
-      use_same_tab =
-          is_chrome_signin_url &&
-          !signin::IsAutoCloseEnabledInURL(current_url) &&
-          is_same_profile;
+      use_same_tab = !is_constrained && is_chrome_signin_url &&
+                     !signin::IsAutoCloseEnabledInURL(current_url) &&
+                     is_same_profile;
     }
     if (profile_sync_service) {
       // Need to navigate to the settings page and display the sync UI.
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index 0ffef21..5bfbf050 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -163,6 +163,7 @@
                             web_contents->GetBrowserContext())).get());
   HistoryTabHelper::CreateForWebContents(web_contents);
   InfoBarService::CreateForWebContents(web_contents);
+  ManagePasswordsUIController::CreateForWebContents(web_contents);
   NavigationCorrectionTabObserver::CreateForWebContents(web_contents);
   NavigationMetricsRecorder::CreateForWebContents(web_contents);
   chrome::InitializePageLoadMetricsForWebContents(web_contents);
@@ -191,7 +192,6 @@
       web_contents);
   extensions::WebNavigationTabObserver::CreateForWebContents(web_contents);
   HungPluginTabHelper::CreateForWebContents(web_contents);
-  ManagePasswordsUIController::CreateForWebContents(web_contents);
   pdf::PDFWebContentsHelper::CreateForWebContentsWithClient(
       web_contents,
       scoped_ptr<pdf::PDFWebContentsHelperClient>(
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
index 9f75b67..c1415fd 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/sessions/session_service_factory.h"
 #include "chrome/browser/sessions/tab_restore_service_factory.h"
 #include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/browser/sync/profile_sync_test_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/sync/browser_synced_window_delegates_getter.h"
@@ -118,14 +119,14 @@
     : public BrowserWithTestWindowTest {
  public:
   RecentTabsSubMenuModelTest()
-      : sync_service_(&testing_profile_),
+      : sync_service_(CreateProfileSyncServiceParamsForTest(&testing_profile_)),
         local_device_(new sync_driver::LocalDeviceInfoProviderMock(
-                      "RecentTabsSubMenuModelTest",
-                      "Test Machine",
-                      "Chromium 10k",
-                      "Chrome 10k",
-                      sync_pb::SyncEnums_DeviceType_TYPE_LINUX,
-                      "device_id")) {
+            "RecentTabsSubMenuModelTest",
+            "Test Machine",
+            "Chromium 10k",
+            "Chrome 10k",
+            sync_pb::SyncEnums_DeviceType_TYPE_LINUX,
+            "device_id")) {
     sync_prefs_.reset(new sync_driver::SyncPrefs(testing_profile_.GetPrefs()));
     manager_.reset(new browser_sync::SessionsSyncManager(
         sync_service_.GetSyncClient()->GetSyncSessionsClient(),
@@ -163,7 +164,7 @@
 
  private:
   TestingProfile testing_profile_;
-  testing::NiceMock<ProfileSyncServiceMock> sync_service_;
+  ProfileSyncServiceMock sync_service_;
   scoped_ptr<sync_driver::SyncPrefs> sync_prefs_;
   scoped_ptr<browser_sync::SessionsSyncManager> manager_;
   scoped_ptr<sync_driver::LocalDeviceInfoProviderMock> local_device_;
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
index 442119b..acef91b 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/extensions/extension_action_view_controller.h"
 #include "chrome/browser/ui/extensions/extension_message_bubble_factory.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/toolbar/component_toolbar_actions_factory.h"
 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
@@ -38,13 +39,6 @@
 
 using WeakToolbarActions = std::vector<ToolbarActionViewController*>;
 
-// Matches ToolbarView::kStandardSpacing;
-const int kLeftPadding = 3;
-const int kRightPadding = kLeftPadding;
-const int kItemSpacing = kLeftPadding;
-const int kOverflowLeftPadding = kItemSpacing;
-const int kOverflowRightPadding = kItemSpacing;
-
 enum DimensionType { WIDTH, HEIGHT };
 
 // Returns the width or height of the toolbar action icon size.
@@ -106,10 +100,8 @@
 // static
 bool ToolbarActionsBar::disable_animations_for_testing_ = false;
 
-ToolbarActionsBar::PlatformSettings::PlatformSettings(bool in_overflow_mode)
-    : left_padding(in_overflow_mode ? kOverflowLeftPadding : kLeftPadding),
-      right_padding(in_overflow_mode ? kOverflowRightPadding : kRightPadding),
-      item_spacing(kItemSpacing),
+ToolbarActionsBar::PlatformSettings::PlatformSettings()
+    : item_spacing(GetLayoutConstant(TOOLBAR_STANDARD_SPACING)),
       icons_per_overflow_menu_row(1),
       chevron_enabled(!extensions::FeatureSwitch::extension_action_redesign()->
                           IsEnabled()) {
@@ -122,7 +114,7 @@
       browser_(browser),
       model_(ToolbarActionsModel::Get(browser_->profile())),
       main_bar_(main_bar),
-      platform_settings_(main_bar != nullptr),
+      platform_settings_(),
       popup_owner_(nullptr),
       model_observer_(this),
       suppress_layout_(false),
@@ -146,7 +138,8 @@
 
 // static
 int ToolbarActionsBar::IconWidth(bool include_padding) {
-  return GetIconDimension(WIDTH) + (include_padding ? kItemSpacing : 0);
+  return GetIconDimension(WIDTH) +
+         (include_padding ? GetLayoutConstant(TOOLBAR_STANDARD_SPACING) : 0);
 }
 
 // static
@@ -189,8 +182,8 @@
 
 int ToolbarActionsBar::GetMinimumWidth() const {
   if (!platform_settings_.chevron_enabled || toolbar_actions_.empty())
-    return kLeftPadding;
-  return kLeftPadding + delegate_->GetChevronWidth() + kRightPadding;
+    return platform_settings_.item_spacing;
+  return 2 * platform_settings_.item_spacing + delegate_->GetChevronWidth();
 }
 
 int ToolbarActionsBar::GetMaximumWidth() const {
@@ -200,17 +193,18 @@
 int ToolbarActionsBar::IconCountToWidth(int icons) const {
   if (icons < 0)
     icons = toolbar_actions_.size();
-  bool display_chevron =
+  const bool display_chevron =
       platform_settings_.chevron_enabled &&
       static_cast<size_t>(icons) < toolbar_actions_.size();
   if (icons == 0 && !display_chevron)
-    return platform_settings_.left_padding;
-  int icons_size = (icons == 0) ? 0 :
+    return platform_settings_.item_spacing;
+
+  const int icons_size = (icons == 0) ? 0 :
       (icons * IconWidth(true)) - platform_settings_.item_spacing;
-  int chevron_size = display_chevron ? delegate_->GetChevronWidth() : 0;
-  int padding = platform_settings_.left_padding +
-                platform_settings_.right_padding;
-  return icons_size + chevron_size + padding;
+  const int chevron_size = display_chevron ? delegate_->GetChevronWidth() : 0;
+  const int side_padding = platform_settings_.item_spacing * 2;
+
+  return icons_size + chevron_size + side_padding;
 }
 
 size_t ToolbarActionsBar::WidthToIconCount(int pixels) const {
@@ -218,10 +212,9 @@
   if (pixels >= IconCountToWidth(-1))
     return toolbar_actions_.size();
 
-  // We reserve space for the padding on either side of the toolbar...
-  int available_space = pixels -
-      (platform_settings_.left_padding + platform_settings_.right_padding);
-  // ... and, if the chevron is enabled, the chevron.
+  // We reserve space for the padding on either side of the toolbar and,
+  // if enabled, for the chevron.
+  int available_space = pixels - (platform_settings_.item_spacing * 2);
   if (platform_settings_.chevron_enabled)
     available_space -= delegate_->GetChevronWidth();
 
@@ -311,7 +304,7 @@
   size_t index_in_row = in_overflow_mode() ?
       relative_index % icons_per_overflow_row : relative_index;
 
-  return gfx::Rect(platform_settings().left_padding +
+  return gfx::Rect(platform_settings().item_spacing +
                        index_in_row * IconWidth(true),
                    row_index * IconHeight(),
                    IconWidth(false),
@@ -436,7 +429,7 @@
 void ToolbarActionsBar::SetOverflowRowWidth(int width) {
   DCHECK(in_overflow_mode());
   platform_settings_.icons_per_overflow_menu_row =
-      std::max((width - kItemSpacing) / IconWidth(true), 1);
+      std::max((width - platform_settings_.item_spacing) / IconWidth(true), 1);
 }
 
 void ToolbarActionsBar::OnResizeComplete(int width) {
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.h b/chrome/browser/ui/toolbar/toolbar_actions_bar.h
index 6d3bf93..7fed96a 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar.h
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.h
@@ -48,13 +48,11 @@
  public:
   // A struct to contain the platform settings.
   struct PlatformSettings {
-    explicit PlatformSettings(bool in_overflow_mode);
+    PlatformSettings();
 
-    // The padding that comes before the first icon in the container.
-    int left_padding;
-    // The padding following the final icon in the container.
-    int right_padding;
-    // The spacing between each of the icons.
+    // The spacing between each of the icons, between the start of the
+    // container and the first item, and between the last item and end of
+    // the container.
     int item_spacing;
     // The number of icons per row in the overflow menu.
     int icons_per_overflow_menu_row;
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
index b0ce77b..350baa3 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
@@ -204,18 +204,18 @@
 
   // By default, all three actions should be visible.
   EXPECT_EQ(3u, toolbar_actions_bar()->GetIconCount());
-  // Check the widths.
-  int expected_width = 3 * ToolbarActionsBar::IconWidth(true) -
-                       platform_settings.item_spacing +
-                       platform_settings.left_padding +
-                       platform_settings.right_padding;
+  // Check the widths. IconWidth(true) includes the spacing to the left of
+  // each icon and |item_spacing| accounts for the spacing to the right
+  // of the rightmost icon.
+  int expected_width =
+      3 * ToolbarActionsBar::IconWidth(true) + platform_settings.item_spacing;
   EXPECT_EQ(expected_width, toolbar_actions_bar()->GetPreferredSize().width());
   // Since all icons are showing, the current width should be the max width.
   int maximum_width = expected_width;
   EXPECT_EQ(maximum_width, toolbar_actions_bar()->GetMaximumWidth());
-  // The minimum width should be just enough for the chevron to be displayed.
-  int minimum_width = platform_settings.left_padding +
-                      platform_settings.right_padding +
+  // The minimum width should be just enough for the chevron to be displayed
+  // along with left and right padding.
+  int minimum_width = 2 * platform_settings.item_spacing +
                       toolbar_actions_bar()->delegate_for_test()->
                           GetChevronWidth();
   EXPECT_EQ(minimum_width, toolbar_actions_bar()->GetMinimumWidth());
@@ -226,10 +226,11 @@
   EXPECT_EQ(2u, toolbar_actions_bar()->GetIconCount());
 
   // The current width should now be enough for two icons, and the chevron.
-  expected_width = 2 * ToolbarActionsBar::IconWidth(true) -
+  // IconWidth(true) includes the spacing to the left of each icon and
+  // |item_spacing| accounts for the spacing to the right of the rightmost
+  // icon.
+  expected_width = 2 * ToolbarActionsBar::IconWidth(true) +
                    platform_settings.item_spacing +
-                   platform_settings.left_padding +
-                   platform_settings.right_padding +
                    toolbar_actions_bar()->delegate_for_test()->
                        GetChevronWidth();
   EXPECT_EQ(expected_width, toolbar_actions_bar()->GetPreferredSize().width());
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_permissions_panel_unittest.cc b/chrome/browser/ui/views/apps/app_info_dialog/app_info_permissions_panel_unittest.cc
index cbf5b820..439ce7d 100644
--- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_permissions_panel_unittest.cc
+++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_permissions_panel_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/views/apps/app_info_dialog/app_info_permissions_panel.h"
 
+#include <utility>
+
 #include "apps/saved_files_service.h"
 #include "base/callback.h"
 #include "base/memory/scoped_ptr.h"
@@ -46,8 +48,8 @@
              extensions::DictionaryBuilder().Set(
                  "background",
                  extensions::DictionaryBuilder().Set(
-                     "scripts",
-                     extensions::ListBuilder().Append("background.js"))))
+                     "scripts", std::move(extensions::ListBuilder().Append(
+                                    "background.js")))))
         .Build();
   }
 
@@ -77,14 +79,15 @@
           .SetManifest(ValidAppManifest())
           .MergeManifest(extensions::DictionaryBuilder().Set(
               "permissions",
-              extensions::ListBuilder()
-                  .Append("desktopCapture")  // A valid permission with a
-                                             // message
-                  .Append("bad_perm")        // An invalid permission
-                  .Append("notifications")   // An valid permission with
-                                             // no message
-                  .Append("serial")))        // Another valid permission with
-                                             // a message
+              std::move(
+                  extensions::ListBuilder()
+                      .Append("desktopCapture")  // A valid permission with a
+                                                 // message
+                      .Append("bad_perm")        // An invalid permission
+                      .Append("notifications")   // An valid permission with
+                                                 // no message
+                      .Append("serial"))))  // Another valid permission with
+                                            // a message
           .SetID(kTestExtensionId)
           .Build();
   AppInfoPermissionsPanel panel(&profile_, app.get());
@@ -104,14 +107,15 @@
           .SetManifest(ValidAppManifest())
           .MergeManifest(extensions::DictionaryBuilder().Set(
               "optional_permissions",
-              extensions::ListBuilder()
-                  .Append("clipboardRead")  // A valid permission with a
-                                            // message
-                  .Append("bad_perm")       // An invalid permission
-                  .Append("idle")           // A valid permission with
-                                            // no message
-                  .Append("serial")))       // Another valid permission with
-                                            // a message
+              std::move(
+                  extensions::ListBuilder()
+                      .Append("clipboardRead")  // A valid permission with a
+                                                // message
+                      .Append("bad_perm")       // An invalid permission
+                      .Append("idle")           // A valid permission with
+                                                // no message
+                      .Append("serial"))))      // Another valid permission with
+                                                // a message
           .SetID(kTestExtensionId)
           .Build();
   AppInfoPermissionsPanel panel(&profile_, app.get());
@@ -131,10 +135,10 @@
           .SetManifest(ValidAppManifest())
           .MergeManifest(extensions::DictionaryBuilder().Set(
               "permissions",
-              extensions::ListBuilder().Append(
+              std::move(extensions::ListBuilder().Append(
                   extensions::DictionaryBuilder().Set(
-                      "fileSystem",
-                      extensions::ListBuilder().Append("retainEntries")))))
+                      "fileSystem", std::move(extensions::ListBuilder().Append(
+                                        "retainEntries")))))))
           .SetID(kTestExtensionId)
           .Build();
   AppInfoPermissionsPanel panel(&profile_, app.get());
diff --git a/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc b/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc
index eff7ee5..7f4d45e 100644
--- a/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc
+++ b/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc
@@ -26,6 +26,7 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/compositor/compositing_recorder.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/color_palette.h"
 #include "ui/gfx/geometry/safe_integer_conversions.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/vector_icons_public.h"
@@ -456,9 +457,8 @@
 
   error_icon_ = new views::ImageView();
   error_icon_->SetVisible(false);
-  // TODO(estade): revisit this color.
   error_icon_->SetImage(gfx::CreateVectorIcon(gfx::VectorIconId::WARNING, 16,
-                                              SkColorSetRGB(0xDB, 0x44, 0x37)));
+                                              gfx::kGoogleRed700));
   temporary_error->AddChildView(error_icon_);
 
   // Reserve vertical space for the error label, assuming it's one line.
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_sign_in_delegate_browsertest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_sign_in_delegate_browsertest.cc
index 255e7e2..7654e8b 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_sign_in_delegate_browsertest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_sign_in_delegate_browsertest.cc
@@ -10,11 +10,11 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/test_extension_service.h"
 #include "chrome/browser/extensions/test_extension_system.h"
-#include "chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/browser/ui/singleton_tabs.h"
+#include "chrome/browser/ui/sync/bubble_sync_promo_delegate.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/profiles/profile_chooser_view.h"
 #include "chrome/common/chrome_switches.h"
@@ -58,7 +58,7 @@
   ReplaceBlank(browser());
   int starting_tab_count = browser()->tab_strip_model()->count();
 
-  scoped_ptr<BookmarkBubbleDelegate> delegate;
+  scoped_ptr<BubbleSyncPromoDelegate> delegate;
   delegate.reset(new BookmarkBubbleSignInDelegate(browser()));
 
   delegate->OnSignInLinkClicked();
@@ -75,7 +75,7 @@
                        OnSignInLinkClickedReusesBlank) {
   int starting_tab_count = browser()->tab_strip_model()->count();
 
-  scoped_ptr<BookmarkBubbleDelegate> delegate;
+  scoped_ptr<BubbleSyncPromoDelegate> delegate;
   delegate.reset(new BookmarkBubbleSignInDelegate(browser()));
 
   delegate->OnSignInLinkClicked();
@@ -97,7 +97,7 @@
   int starting_tab_count_incognito =
       incognito_browser->tab_strip_model()->count();
 
-  scoped_ptr<BookmarkBubbleDelegate> delegate;
+  scoped_ptr<BubbleSyncPromoDelegate> delegate;
   delegate.reset(new BookmarkBubbleSignInDelegate(incognito_browser));
 
   delegate->OnSignInLinkClicked();
@@ -125,7 +125,7 @@
 
   int starting_tab_count = extra_browser->tab_strip_model()->count();
 
-  scoped_ptr<BookmarkBubbleDelegate> delegate;
+  scoped_ptr<BubbleSyncPromoDelegate> delegate;
   delegate.reset(new BookmarkBubbleSignInDelegate(browser()));
 
   BrowserList::SetLastActive(extra_browser);
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
index 8314f733..389b745 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
@@ -15,7 +15,8 @@
 #include "chrome/browser/ui/bookmarks/bookmark_editor.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/sync/sync_promo_ui.h"
-#include "chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view.h"
+#include "chrome/browser/ui/views/sync/bubble_sync_promo_view.h"
+#include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_utils.h"
@@ -64,14 +65,15 @@
 BookmarkBubbleView* BookmarkBubbleView::bookmark_bubble_ = NULL;
 
 // static
-void BookmarkBubbleView::ShowBubble(views::View* anchor_view,
-                                    const gfx::Rect& anchor_rect,
-                                    gfx::NativeView parent_window,
-                                    bookmarks::BookmarkBubbleObserver* observer,
-                                    scoped_ptr<BookmarkBubbleDelegate> delegate,
-                                    Profile* profile,
-                                    const GURL& url,
-                                    bool already_bookmarked) {
+void BookmarkBubbleView::ShowBubble(
+    views::View* anchor_view,
+    const gfx::Rect& anchor_rect,
+    gfx::NativeView parent_window,
+    bookmarks::BookmarkBubbleObserver* observer,
+    scoped_ptr<BubbleSyncPromoDelegate> delegate,
+    Profile* profile,
+    const GURL& url,
+    bool already_bookmarked) {
   if (bookmark_bubble_)
     return;
 
@@ -255,7 +257,9 @@
                   0);
     layout->StartRow(0, SYNC_PROMO_COLUMN_SET_ID);
 
-    sync_promo_view_ = new BookmarkSyncPromoView(delegate_.get());
+    sync_promo_view_ =
+        new BubbleSyncPromoView(delegate_.get(), IDS_BOOKMARK_SYNC_PROMO_LINK,
+                                IDS_BOOKMARK_SYNC_PROMO_MESSAGE);
     layout->AddView(sync_promo_view_);
   }
 
@@ -275,7 +279,7 @@
 BookmarkBubbleView::BookmarkBubbleView(
     views::View* anchor_view,
     bookmarks::BookmarkBubbleObserver* observer,
-    scoped_ptr<BookmarkBubbleDelegate> delegate,
+    scoped_ptr<BubbleSyncPromoDelegate> delegate,
     Profile* profile,
     const GURL& url,
     bool newly_bookmarked)
@@ -285,10 +289,9 @@
       profile_(profile),
       url_(url),
       newly_bookmarked_(newly_bookmarked),
-      parent_model_(
-          BookmarkModelFactory::GetForProfile(profile_),
-          BookmarkModelFactory::GetForProfile(profile_)->
-              GetMostRecentlyAddedUserNodeForURL(url)),
+      parent_model_(BookmarkModelFactory::GetForProfile(profile_),
+                    BookmarkModelFactory::GetForProfile(profile_)
+                        ->GetMostRecentlyAddedUserNodeForURL(url)),
       remove_button_(NULL),
       edit_button_(NULL),
       close_button_(NULL),
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h
index 0eea1cfa..775eae4 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h
@@ -10,8 +10,8 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
-#include "chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h"
 #include "chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h"
+#include "chrome/browser/ui/sync/bubble_sync_promo_delegate.h"
 #include "ui/views/bubble/bubble_delegate.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/combobox/combobox_listener.h"
@@ -42,7 +42,7 @@
                          const gfx::Rect& anchor_rect,
                          gfx::NativeView parent_window,
                          bookmarks::BookmarkBubbleObserver* observer,
-                         scoped_ptr<BookmarkBubbleDelegate> delegate,
+                         scoped_ptr<BubbleSyncPromoDelegate> delegate,
                          Profile* profile,
                          const GURL& url,
                          bool already_bookmarked);
@@ -73,7 +73,7 @@
   // Creates a BookmarkBubbleView.
   BookmarkBubbleView(views::View* anchor_view,
                      bookmarks::BookmarkBubbleObserver* observer,
-                     scoped_ptr<BookmarkBubbleDelegate> delegate,
+                     scoped_ptr<BubbleSyncPromoDelegate> delegate,
                      Profile* profile,
                      const GURL& url,
                      bool newly_bookmarked);
@@ -107,7 +107,7 @@
   bookmarks::BookmarkBubbleObserver* observer_;
 
   // Delegate, to handle clicks on the sign in link.
-  scoped_ptr<BookmarkBubbleDelegate> delegate_;
+  scoped_ptr<BubbleSyncPromoDelegate> delegate_;
 
   // The profile.
   Profile* profile_;
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc
index b237cd53..a0a95993 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc
@@ -10,7 +10,7 @@
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/signin/fake_signin_manager_builder.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
-#include "chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h"
+#include "chrome/browser/ui/sync/bubble_sync_promo_delegate.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "components/bookmarks/browser/bookmark_utils.h"
 #include "components/bookmarks/test/bookmark_test_helpers.h"
@@ -57,7 +57,7 @@
  protected:
   // Creates a bookmark bubble view.
   void CreateBubbleView() {
-    scoped_ptr<BookmarkBubbleDelegate> delegate;
+    scoped_ptr<BubbleSyncPromoDelegate> delegate;
     bubble_.reset(new BookmarkBubbleView(NULL,
                                          NULL,
                                          delegate.Pass(),
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view.h b/chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view.h
deleted file mode 100644
index 75bcb56..0000000
--- a/chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_VIEWS_BOOKMARKS_BOOKMARK_SYNC_PROMO_VIEW_H_
-#define CHROME_BROWSER_UI_VIEWS_BOOKMARKS_BOOKMARK_SYNC_PROMO_VIEW_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "ui/views/controls/styled_label_listener.h"
-#include "ui/views/view.h"
-
-class BookmarkBubbleDelegate;
-
-// Bookmark sync promo displayed at the bottom of the bookmark bubble.
-class BookmarkSyncPromoView : public views::StyledLabelListener,
-                              public views::View {
- public:
-  // |delegate| is not owned by BookmarkSyncPromoView.
-  explicit BookmarkSyncPromoView(BookmarkBubbleDelegate* delegate);
-
- private:
-  // views::StyledLabelListener:
-  void StyledLabelLinkClicked(views::StyledLabel* label,
-                              const gfx::Range& range,
-                              int event_flags) override;
-
-  // views::View:
-  const char* GetClassName() const override;
-
-  // Delegate, to handle clicks on the sign in link.
-  BookmarkBubbleDelegate* delegate_;
-
-  DISALLOW_COPY_AND_ASSIGN(BookmarkSyncPromoView);
-};
-
-#endif  // CHROME_BROWSER_UI_VIEWS_BOOKMARKS_BOOKMARK_SYNC_PROMO_VIEW_H_
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view_unittest.cc b/chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view_unittest.cc
deleted file mode 100644
index f7f21615..0000000
--- a/chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view_unittest.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view.h"
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/event_constants.h"
-#include "ui/gfx/range/range.h"
-#include "ui/views/controls/styled_label.h"
-
-class BookmarkSyncPromoViewTest : public BookmarkBubbleDelegate,
-                                  public testing::Test {
- public:
-  BookmarkSyncPromoViewTest() : sign_in_clicked_count_(0) {}
-
- protected:
-  // BookmarkBubbleDelegate:
-  void OnSignInLinkClicked() override { ++sign_in_clicked_count_; }
-
-  // Number of times that OnSignInLinkClicked has been called.
-  int sign_in_clicked_count_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(BookmarkSyncPromoViewTest);
-};
-
-TEST_F(BookmarkSyncPromoViewTest, SignInLink) {
-  scoped_ptr<BookmarkSyncPromoView> sync_promo;
-  sync_promo.reset(new BookmarkSyncPromoView(this));
-
-  // Simulate clicking the "Sign in" link.
-  views::StyledLabel styled_label(base::ASCIIToUTF16("test"), nullptr);
-  views::StyledLabelListener* listener = sync_promo.get();
-  listener->StyledLabelLinkClicked(&styled_label, gfx::Range(), ui::EF_NONE);
-
-  EXPECT_EQ(1, sign_in_clicked_count_);
-}
diff --git a/chrome/browser/ui/views/browser_dialogs_views_mac.cc b/chrome/browser/ui/views/browser_dialogs_views_mac.cc
index 1a8e754..0f4d6656 100644
--- a/chrome/browser/ui/views/browser_dialogs_views_mac.cc
+++ b/chrome/browser/ui/views/browser_dialogs_views_mac.cc
@@ -35,7 +35,7 @@
                                     const GURL& url,
                                     bool already_bookmarked) {
   // The Views dialog may prompt for sign in.
-  scoped_ptr<BookmarkBubbleDelegate> delegate(
+  scoped_ptr<BubbleSyncPromoDelegate> delegate(
       new BookmarkBubbleSignInDelegate(browser));
 
   BookmarkBubbleView::ShowBubble(nullptr, gfx::Rect(anchor_point, gfx::Size()),
diff --git a/chrome/browser/ui/views/content_setting_bubble_contents.cc b/chrome/browser/ui/views/content_setting_bubble_contents.cc
index 54e273a..7cdc6b0 100644
--- a/chrome/browser/ui/views/content_setting_bubble_contents.cc
+++ b/chrome/browser/ui/views/content_setting_bubble_contents.cc
@@ -337,7 +337,7 @@
     }
   }
 
-  UpdateMenuButtonSizes(GetNativeTheme());
+  UpdateMenuButtonSizes();
 
   const gfx::FontList& domain_font =
       ui::ResourceBundle::GetSharedInstance().GetFontList(
@@ -409,12 +409,6 @@
   GetWidget()->Close();
 }
 
-void ContentSettingBubbleContents::OnNativeThemeChanged(
-    const ui::NativeTheme* theme) {
-  views::BubbleDelegateView::OnNativeThemeChanged(theme);
-  UpdateMenuButtonSizes(theme);
-}
-
 void ContentSettingBubbleContents::ButtonPressed(views::Button* sender,
                                                  const ui::Event& event) {
   RadioGroup::const_iterator i(
@@ -472,9 +466,8 @@
                                 ui::MENU_SOURCE_NONE));
 }
 
-void ContentSettingBubbleContents::UpdateMenuButtonSizes(
-    const ui::NativeTheme* theme) {
-  const views::MenuConfig config = views::MenuConfig(theme);
+void ContentSettingBubbleContents::UpdateMenuButtonSizes() {
+  const views::MenuConfig& config = views::MenuConfig::instance();
   const int margins = config.item_left_margin + config.check_width +
                       config.label_to_arrow_padding + config.arrow_width +
                       config.arrow_to_edge_padding;
diff --git a/chrome/browser/ui/views/content_setting_bubble_contents.h b/chrome/browser/ui/views/content_setting_bubble_contents.h
index 62968a4..c6bc636 100644
--- a/chrome/browser/ui/views/content_setting_bubble_contents.h
+++ b/chrome/browser/ui/views/content_setting_bubble_contents.h
@@ -76,9 +76,6 @@
       const content::LoadCommittedDetails& details,
       const content::FrameNavigateParams& params) override;
 
-  // views::View:
-  void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
-
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
@@ -90,7 +87,7 @@
                            const gfx::Point& point) override;
 
   // Helper to get the preferred width of the media menu.
-  void UpdateMenuButtonSizes(const ui::NativeTheme* theme);
+  void UpdateMenuButtonSizes();
 
   // Provides data for this bubble.
   scoped_ptr<ContentSettingBubbleModel> content_setting_bubble_model_;
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
index eb2f69df..ff1ac90f 100644
--- a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/views/extensions/extension_install_dialog_view.h"
 
+#include <algorithm>
+#include <string>
 #include <vector>
 
 #include "base/basictypes.h"
@@ -107,8 +109,16 @@
                                      show_params->GetParentWebContents(),
                                      delegate,
                                      prompt);
-  constrained_window::CreateBrowserModalDialogViews(
-      dialog, show_params->GetParentWindow())->Show();
+  if (prompt->ShouldUseTabModalDialog()) {
+    content::WebContents* parent_web_contents =
+        show_params->GetParentWebContents();
+    if (parent_web_contents)
+      constrained_window::ShowWebModalDialogViews(dialog, parent_web_contents);
+  } else {
+    constrained_window::CreateBrowserModalDialogViews(
+        dialog, show_params->GetParentWindow())
+        ->Show();
+  }
 }
 
 // A custom scrollable view implementation for the dialog.
@@ -412,7 +422,7 @@
     scroll_layout->AddView(issue_advice_view);
   }
 
-  DCHECK(prompt_->type() >= 0);
+  DCHECK_GE(prompt_->type(), 0);
   UMA_HISTOGRAM_ENUMERATION("Extensions.InstallPrompt.Type",
                             prompt_->type(),
                             ExtensionInstallPrompt::NUM_PROMPT_TYPES);
@@ -598,7 +608,8 @@
 }
 
 ui::ModalType ExtensionInstallDialogView::GetModalType() const {
-  return ui::MODAL_TYPE_WINDOW;
+  return prompt_->ShouldUseTabModalDialog() ? ui::MODAL_TYPE_CHILD
+                                            : ui::MODAL_TYPE_WINDOW;
 }
 
 void ExtensionInstallDialogView::LinkClicked(views::Link* source,
diff --git a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
index 46e291e..b732e2a 100644
--- a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/location_bar/page_action_with_badge_view.h"
+#include "chrome/browser/ui/views/sync/bubble_sync_promo_view.h"
 #include "chrome/browser/ui/views/toolbar/app_menu_button.h"
 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
@@ -33,12 +34,15 @@
 #include "ui/gfx/render_text.h"
 #include "ui/gfx/text_elider.h"
 #include "ui/resources/grit/ui_resources.h"
+#include "ui/views/bubble/bubble_frame_view.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/link.h"
 #include "ui/views/controls/link_listener.h"
+#include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/fill_layout.h"
+#include "ui/views/layout/grid_layout.h"
 #include "ui/views/layout/layout_constants.h"
 
 using extensions::Extension;
@@ -49,19 +53,13 @@
 
 const int kRightColumnWidth = 285;
 
-// The Bubble uses a BubbleBorder which adds about 6 pixels of whitespace
-// around the content view. We compensate by reducing our outer borders by this
-// amount + 4px.
-const int kOuterMarginInset = 10;
-const int kHorizOuterMargin = views::kPanelHorizMargin - kOuterMarginInset;
-const int kVertOuterMargin = views::kPanelVertMargin - kOuterMarginInset;
-
-// Interior vertical margin is 8px smaller than standard
-const int kVertInnerMargin = views::kPanelVertMargin - 8;
-
-// We want to shift the right column (which contains the header and text) up
-// 4px to align with icon.
-const int kRightcolumnVerticalShift = -4;
+views::Label* CreateLabel(const base::string16& text,
+                          const gfx::FontList& font) {
+  views::Label* label = new views::Label(text, font);
+  label->SetMultiLine(true);
+  label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  return label;
+}
 
 }  // namespace
 
@@ -71,7 +69,11 @@
     : bubble_reference_(bubble_reference),
       extension_(bubble->extension()),
       browser_(bubble->browser()),
-      type_(bubble->type()) {}
+      type_(bubble->type()),
+      options_(NONE),
+      sync_promo_(nullptr),
+      close_(nullptr),
+      manage_shortcut_(nullptr) {}
 
 ExtensionInstalledBubbleView::~ExtensionInstalledBubbleView() {}
 
@@ -165,6 +167,188 @@
   return true;
 }
 
+void ExtensionInstalledBubbleView::OnSignInLinkClicked() {
+  GetWidget()->Close();
+  chrome::ShowBrowserSignin(
+      browser_,
+      signin_metrics::AccessPoint::ACCESS_POINT_EXTENSION_INSTALL_BUBBLE);
+}
+
+void ExtensionInstalledBubbleView::ButtonPressed(views::Button* sender,
+                                                 const ui::Event& event) {
+  DCHECK_EQ(sender, close_);
+  GetWidget()->Close();
+}
+
+void ExtensionInstalledBubbleView::LinkClicked(views::Link* source,
+                                               int event_flags) {
+  DCHECK_EQ(manage_shortcut_, source);
+  GetWidget()->Close();
+
+  std::string configure_url = chrome::kChromeUIExtensionsURL;
+  configure_url += chrome::kExtensionConfigureCommandsSubPage;
+  chrome::NavigateParams params(
+      chrome::GetSingletonTabNavigateParams(browser_, GURL(configure_url)));
+  chrome::Navigate(&params);
+}
+
+void ExtensionInstalledBubbleView::InitLayout(
+    const ExtensionInstalledBubble& bubble) {
+  // The Extension Installed bubble takes on various forms, depending on the
+  // type of extension installed. In general, though, they are all similar:
+  //
+  // -------------------------
+  // |      | Heading    [X] |
+  // | Icon | Info           |
+  // |      | Extra info     |
+  // -------------------------
+  //
+  // Icon and Heading are always shown (as well as the close button).
+  // Info is shown for browser actions, page actions and Omnibox keyword
+  // extensions and might list keyboard shorcut for the former two types.
+  // Extra info is...
+  // ... for other types, either a description of how to manage the extension
+  //     or a link to configure the keybinding shortcut (if one exists).
+  // Extra info can include a promo for signing into sync.
+
+  set_margins(gfx::Insets(views::kPanelVertMargin, 0, 0, 0));
+
+  if (extensions::sync_helper::IsSyncable(extension_) &&
+      SyncPromoUI::ShouldShowSyncPromo(browser_->profile()))
+    options_ |= SIGN_IN_PROMO;
+
+  // The number of rows in the content section of the bubble.
+  int main_content_row_count = 1;
+  // Determine the bubble option we want, based on the extension type.
+  switch (type_) {
+    case ExtensionInstalledBubble::BROWSER_ACTION:
+    case ExtensionInstalledBubble::PAGE_ACTION:
+      options_ |= HOW_TO_USE;
+      if (bubble.has_command_keybinding()) {
+        options_ |= SHOW_KEYBINDING;
+      } else {
+        // The How-To-Use text makes the bubble seem a little crowded when the
+        // extension has a keybinding, so the How-To-Manage text is not shown
+        // in those cases.
+        options_ |= HOW_TO_MANAGE;
+      }
+      main_content_row_count += 2;
+      break;
+    case ExtensionInstalledBubble::OMNIBOX_KEYWORD:
+      options_ |= HOW_TO_USE | HOW_TO_MANAGE;
+      main_content_row_count += 2;
+      break;
+    case ExtensionInstalledBubble::GENERIC:
+      break;
+    default:
+      // When adding a new bubble type, the option needs to be set.
+      static_assert(ExtensionInstalledBubble::GENERIC == 3,
+                    "kBubbleType enum has changed, this switch statement must "
+                    "be updateed");
+      break;
+  }
+
+  views::GridLayout* layout = new views::GridLayout(this);
+  SetLayoutManager(layout);
+
+  enum ColumnSetId {
+    MAIN_COLUMN_SET = 0,
+    SYNC_PROMO_COLUMN_SET,
+  };
+
+  views::ColumnSet* main_cs = layout->AddColumnSet(MAIN_COLUMN_SET);
+  // Note: the left padding column is set to kUnrelatedControlHorizontalSpacing
+  // so that the distance between the left edge and the icon matches the
+  // distance between the icon and the content.
+  main_cs->AddPaddingColumn(0 /* not resizable */,
+                            views::kUnrelatedControlHorizontalSpacing);
+  // Icon column.
+  main_cs->AddColumn(views::GridLayout::CENTER, views::GridLayout::LEADING, 0,
+                     views::GridLayout::USE_PREF, 0, 0);
+  main_cs->AddPaddingColumn(0, views::kUnrelatedControlHorizontalSpacing);
+  // Heading column:
+  main_cs->AddColumn(views::GridLayout::LEADING, views::GridLayout::LEADING, 0,
+                     views::GridLayout::FIXED, kRightColumnWidth, 0);
+  main_cs->AddPaddingColumn(0 /* not resizable */,
+                            views::kUnrelatedControlHorizontalSpacing);
+
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+  const gfx::FontList& font_list = rb.GetFontList(ui::ResourceBundle::BaseFont);
+
+  const SkBitmap& bitmap = bubble.icon();
+  // Add the icon (for all options).
+  // Scale down to 43x43, but allow smaller icons (don't scale up).
+  gfx::Size size(bitmap.width(), bitmap.height());
+  if (size.width() > kIconSize || size.height() > kIconSize)
+    size = gfx::Size(kIconSize, kIconSize);
+  views::ImageView* icon = new views::ImageView();
+  icon->SetImageSize(size);
+  icon->SetImage(gfx::ImageSkia::CreateFrom1xBitmap(bitmap));
+
+  layout->StartRow(0, MAIN_COLUMN_SET);
+  layout->AddView(icon, 1, main_content_row_count);
+
+  // Add the heading (for all options).
+  base::string16 extension_name = base::UTF8ToUTF16(extension_->name());
+  base::i18n::AdjustStringForLocaleDirection(&extension_name);
+  views::Label* heading =
+      CreateLabel(l10n_util::GetStringFUTF16(IDS_EXTENSION_INSTALLED_HEADING,
+                                             extension_name),
+                  rb.GetFontList(ui::ResourceBundle::MediumFont));
+
+  close_ = views::BubbleFrameView::CreateCloseButton(this);
+
+  views::View* heading_and_close = new views::View();
+  views::BoxLayout* heading_and_close_layout =
+      new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0,
+                           views::kUnrelatedControlHorizontalSpacing);
+  heading_and_close_layout->set_cross_axis_alignment(
+      views::BoxLayout::CROSS_AXIS_ALIGNMENT_START);
+  heading_and_close->SetLayoutManager(heading_and_close_layout);
+  heading_and_close->AddChildView(heading);
+  heading_and_close->AddChildView(close_);
+
+  layout->AddView(heading_and_close);
+  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
+
+  auto add_content_view = [&layout](views::View* view) {
+    layout->StartRow(0, MAIN_COLUMN_SET);
+    // Skip the icon column.
+    layout->SkipColumns(1);
+    layout->AddView(view);
+    layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
+  };
+
+  if (options_ & HOW_TO_USE) {
+    add_content_view(CreateLabel(bubble.GetHowToUseDescription(), font_list));
+  }
+
+  if (options_ & SHOW_KEYBINDING) {
+    manage_shortcut_ = new views::Link(
+        l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_MANAGE_SHORTCUTS));
+    manage_shortcut_->set_listener(this);
+    manage_shortcut_->SetUnderline(false);
+    add_content_view(manage_shortcut_);
+  }
+
+  if (options_ & HOW_TO_MANAGE) {
+    add_content_view(CreateLabel(
+        l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_MANAGE_INFO),
+        font_list));
+  }
+
+  if (options_ & SIGN_IN_PROMO) {
+    views::ColumnSet* sync_cs = layout->AddColumnSet(SYNC_PROMO_COLUMN_SET);
+    sync_cs->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
+                       views::GridLayout::USE_PREF, 0, 0);
+    layout->StartRow(0, SYNC_PROMO_COLUMN_SET);
+    sync_promo_ = new BubbleSyncPromoView(
+        this, IDS_EXTENSION_INSTALLED_SYNC_PROMO_LINK_NEW,
+        IDS_EXTENSION_INSTALLED_SYNC_PROMO_NEW);
+    layout->AddView(sync_promo_);
+  }
+}
+
 // Views specific implementation.
 bool ExtensionInstalledBubble::ShouldShow() {
   if (type() == BROWSER_ACTION ||
@@ -200,396 +384,6 @@
   return make_scoped_ptr(new ExtensionInstalledBubbleUi(this));
 }
 
-// InstalledBubbleContent is the content view which is placed in the
-// ExtensionInstalledBubbleView. It displays the install icon and explanatory
-// text about the installed extension.
-class InstalledBubbleContent : public views::View,
-                               public views::ButtonListener,
-                               public views::LinkListener {
- public:
-  InstalledBubbleContent(const ExtensionInstalledBubble& bubble,
-                         const BubbleReference& bubble_reference,
-                         Browser* browser);
-
-  // Overridden from views::ButtonListener.
-  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
-
-  // Overriden from views::LinkListener.
-  void LinkClicked(views::Link* source, int event_flags) override;
-
- private:
-  enum Flavors {
-    NONE            = 0,
-    HOW_TO_USE      = 1 << 0,
-    HOW_TO_MANAGE   = 1 << 1,
-    SHOW_KEYBINDING = 1 << 2,
-    SIGN_IN_PROMO   = 1 << 3,
-  };
-
-  // Layout the signin promo at coordinates |offset_x| and |offset_y|. Returns
-  // the height (in pixels) of the promo UI.
-  int LayoutSigninPromo(int offset_x, int offset_y);
-
-  // Overriden from views::View.
-  gfx::Size GetPreferredSize() const override;
-  void Layout() override;
-  void OnPaint(gfx::Canvas* canvas) override;
-
-  // The browser we're associated with.
-  Browser* browser_;
-
-  // A reference to the bubble to send close events to.
-  BubbleReference bubble_reference_;
-
-  // The string that contains the link text at the beginning of the sign-in
-  // promo text.
-  base::string16 signin_promo_link_text_;
-  // The remaining text of the sign-in promo text.
-  base::string16 signin_promo_text_;
-
-  // A vector of RenderText objects representing the full sign-in promo
-  // paragraph as layed out within the bubble, but has the text of the link
-  // whited out so the link can be drawn in its place.
-  ScopedVector<gfx::RenderText> sign_in_promo_lines_;
-
-  // A bitmask containing the various flavors of bubble sections to show.
-  int flavors_;
-
-  // The height, in pixels, of the sign-in promo.
-  size_t height_of_signin_promo_;
-
-  views::ImageView* icon_;
-  views::Label* heading_;
-  views::Label* how_to_use_;
-  views::Link* sign_in_link_;
-  views::Label* manage_;
-  views::Link* manage_shortcut_;
-  views::ImageButton* close_button_;
-
-  DISALLOW_COPY_AND_ASSIGN(InstalledBubbleContent);
-};
-
-InstalledBubbleContent::InstalledBubbleContent(
-    const ExtensionInstalledBubble& bubble,
-    const BubbleReference& bubble_reference,
-    Browser* browser)
-    : browser_(browser),
-      bubble_reference_(bubble_reference),
-      flavors_(NONE),
-      height_of_signin_promo_(0u),
-      how_to_use_(nullptr),
-      sign_in_link_(nullptr),
-      manage_(nullptr),
-      manage_shortcut_(nullptr) {
-  // The Extension Installed bubble takes on various forms, depending on the
-  // type of extension installed. In general, though, they are all similar:
-  //
-  // -------------------------
-  // |      | Heading    [X] |
-  // | Icon | Info           |
-  // |      | Extra info     |
-  // -------------------------
-  //
-  // Icon and Heading are always shown (as well as the close button).
-  // Info is shown for browser actions, page actions and Omnibox keyword
-  // extensions and might list keyboard shorcut for the former two types.
-  // Extra info is...
-  // ... for other types, either a description of how to manage the extension
-  //     or a link to configure the keybinding shortcut (if one exists).
-  // Extra info can include a promo for signing into sync.
-
-  const Extension* extension = bubble.extension();
-  if (extensions::sync_helper::IsSyncable(extension) &&
-      SyncPromoUI::ShouldShowSyncPromo(browser->profile()))
-    flavors_ |= SIGN_IN_PROMO;
-
-  // Determine the bubble flavor we want, based on the extension type.
-  switch (bubble.type()) {
-    case ExtensionInstalledBubble::BROWSER_ACTION:
-    case ExtensionInstalledBubble::PAGE_ACTION:
-      flavors_ |= HOW_TO_USE;
-      if (bubble.has_command_keybinding()) {
-        flavors_ |= SHOW_KEYBINDING;
-      } else {
-        // The How-To-Use text makes the bubble seem a little crowded when the
-        // extension has a keybinding, so the How-To-Manage text is not shown
-        // in those cases.
-        flavors_ |= HOW_TO_MANAGE;
-      }
-      break;
-    case ExtensionInstalledBubble::OMNIBOX_KEYWORD:
-      flavors_ |= HOW_TO_USE | HOW_TO_MANAGE;
-      break;
-    case ExtensionInstalledBubble::GENERIC:
-      break;
-    default:
-      // When adding a new bubble type, the flavor needs to be set.
-      static_assert(ExtensionInstalledBubble::GENERIC == 3,
-          "kBubbleType enum has changed, this switch statement must "
-          "be updateed");
-      break;
-  }
-
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  const gfx::FontList& font_list =
-      rb.GetFontList(ui::ResourceBundle::BaseFont);
-
-  const SkBitmap& icon = bubble.icon();
-  // Add the icon (for all flavors).
-  // Scale down to 43x43, but allow smaller icons (don't scale up).
-  gfx::Size size(icon.width(), icon.height());
-  if (size.width() > kIconSize || size.height() > kIconSize)
-    size = gfx::Size(kIconSize, kIconSize);
-  icon_ = new views::ImageView();
-  icon_->SetImageSize(size);
-  icon_->SetImage(gfx::ImageSkia::CreateFrom1xBitmap(icon));
-  AddChildView(icon_);
-
-  // Add the heading (for all flavors).
-  base::string16 extension_name = base::UTF8ToUTF16(extension->name());
-  base::i18n::AdjustStringForLocaleDirection(&extension_name);
-  heading_ = new views::Label(l10n_util::GetStringFUTF16(
-      IDS_EXTENSION_INSTALLED_HEADING, extension_name));
-  heading_->SetFontList(rb.GetFontList(ui::ResourceBundle::MediumFont));
-  heading_->SetMultiLine(true);
-  heading_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  AddChildView(heading_);
-
-  if (flavors_ & HOW_TO_USE) {
-    how_to_use_ = new views::Label(bubble.GetHowToUseDescription());
-    how_to_use_->SetFontList(font_list);
-    how_to_use_->SetMultiLine(true);
-    how_to_use_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-    AddChildView(how_to_use_);
-  }
-
-  if (flavors_ & SHOW_KEYBINDING) {
-    manage_shortcut_ = new views::Link(
-        l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_MANAGE_SHORTCUTS));
-    manage_shortcut_->set_listener(this);
-    AddChildView(manage_shortcut_);
-  }
-
-  if (flavors_ & HOW_TO_MANAGE) {
-    manage_ = new views::Label(l10n_util::GetStringUTF16(
-        IDS_EXTENSION_INSTALLED_MANAGE_INFO));
-    manage_->SetFontList(font_list);
-    manage_->SetMultiLine(true);
-    manage_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-    AddChildView(manage_);
-  }
-
-  if (flavors_ & SIGN_IN_PROMO) {
-    signin_promo_text_ =
-        l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_SIGNIN_PROMO);
-
-    signin_promo_link_text_ =
-        l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_SIGNIN_PROMO_LINK);
-    sign_in_link_ = new views::Link(signin_promo_link_text_);
-    sign_in_link_->SetFontList(font_list);
-    sign_in_link_->set_listener(this);
-    AddChildView(sign_in_link_);
-  }
-
-  // Add the Close button (for all flavors).
-  close_button_ = new views::ImageButton(this);
-  close_button_->SetImage(views::CustomButton::STATE_NORMAL,
-      rb.GetImageSkiaNamed(IDR_CLOSE_2));
-  close_button_->SetImage(views::CustomButton::STATE_HOVERED,
-      rb.GetImageSkiaNamed(IDR_CLOSE_2_H));
-  close_button_->SetImage(views::CustomButton::STATE_PRESSED,
-      rb.GetImageSkiaNamed(IDR_CLOSE_2_P));
-  AddChildView(close_button_);
-}
-
-void InstalledBubbleContent::ButtonPressed(views::Button* sender,
-                                           const ui::Event& event) {
-  DCHECK_EQ(sender, close_button_);
-  DCHECK(bubble_reference_);
-  bool did_close = bubble_reference_->CloseBubble(BUBBLE_CLOSE_USER_DISMISSED);
-  DCHECK(did_close);
-}
-
-void InstalledBubbleContent::LinkClicked(views::Link* source, int event_flags) {
-  DCHECK(bubble_reference_);
-  bool did_close = bubble_reference_->CloseBubble(BUBBLE_CLOSE_ACCEPTED);
-  DCHECK(did_close);
-
-  if (source == sign_in_link_) {
-#if defined(OS_ANDROID)
-    // TODO(bshe): Figure out what to do on Android platform. See
-    // crbug.com/559340.
-    NOTIMPLEMENTED();
-#else
-    chrome::ShowBrowserSignin(
-        browser_,
-        signin_metrics::AccessPoint::ACCESS_POINT_EXTENSION_INSTALL_BUBBLE);
-#endif
-    return;
-  }
-
-  DCHECK_EQ(manage_shortcut_, source);
-
-  std::string configure_url = chrome::kChromeUIExtensionsURL;
-  configure_url += chrome::kExtensionConfigureCommandsSubPage;
-  chrome::NavigateParams params(chrome::GetSingletonTabNavigateParams(
-      browser_, GURL(configure_url)));
-  chrome::Navigate(&params);
-}
-
-int InstalledBubbleContent::LayoutSigninPromo(int offset_x, int offset_y) {
-  sign_in_promo_lines_.clear();
-  int height = 0;
-  gfx::Rect contents_area = GetContentsBounds();
-  if (contents_area.IsEmpty())
-    return height;
-  contents_area.set_width(kRightColumnWidth);
-
-  base::string16 full_text = signin_promo_link_text_ + signin_promo_text_;
-
-  // The link is the first item in the text.
-  const gfx::Size link_size = sign_in_link_->GetPreferredSize();
-  sign_in_link_->SetBounds(
-      offset_x, offset_y, link_size.width(), link_size.height());
-
-  // Word-wrap the full label text.
-  const gfx::FontList font_list;
-  std::vector<base::string16> lines;
-  gfx::ElideRectangleText(full_text, font_list, contents_area.width(),
-                          contents_area.height(), gfx::ELIDE_LONG_WORDS,
-                          &lines);
-
-  gfx::Point position = gfx::Point(
-      contents_area.origin().x() + offset_x,
-      contents_area.origin().y() + offset_y + 1);
-  if (base::i18n::IsRTL()) {
-    position -= gfx::Vector2d(
-        2 * views::kPanelHorizMargin + kHorizOuterMargin, 0);
-  }
-
-  // Loop through the lines, creating a renderer for each.
-  for (std::vector<base::string16>::const_iterator it = lines.begin();
-       it != lines.end(); ++it) {
-    gfx::RenderText* line = gfx::RenderText::CreateInstance();
-    line->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_UI);
-    line->SetText(*it);
-    const gfx::Size size(contents_area.width(),
-                         line->GetStringSize().height());
-    line->SetDisplayRect(gfx::Rect(position, size));
-    position.set_y(position.y() + size.height());
-    sign_in_promo_lines_.push_back(line);
-    height += size.height();
-  }
-
-  // The link is drawn separately; make it transparent here to only draw once.
-  // The link always leads other text and is assumed to fit on the first line.
-  sign_in_promo_lines_.front()->ApplyColor(SK_ColorTRANSPARENT,
-      gfx::Range(0, signin_promo_link_text_.size()));
-
-  return height;
-}
-
-gfx::Size InstalledBubbleContent::GetPreferredSize() const {
-  int width = kHorizOuterMargin;
-  width += kIconSize;
-  width += views::kPanelHorizMargin;
-  width += kRightColumnWidth;
-  width += 2 * views::kPanelHorizMargin;
-  width += kHorizOuterMargin;
-
-  int height = kVertOuterMargin;
-  height += heading_->GetHeightForWidth(kRightColumnWidth);
-  height += kVertInnerMargin;
-
-  if (flavors_ & HOW_TO_USE) {
-    height += how_to_use_->GetHeightForWidth(kRightColumnWidth);
-    height += kVertInnerMargin;
-  }
-
-  if (flavors_ & HOW_TO_MANAGE) {
-    height += manage_->GetHeightForWidth(kRightColumnWidth);
-    height += kVertInnerMargin;
-  }
-
-  if (flavors_ & SIGN_IN_PROMO && height_of_signin_promo_ > 0u) {
-    height += height_of_signin_promo_;
-    height += kVertInnerMargin;
-  }
-
-  if (flavors_ & SHOW_KEYBINDING) {
-    height += manage_shortcut_->GetHeightForWidth(kRightColumnWidth);
-    height += kVertInnerMargin;
-  }
-
-  return gfx::Size(width, std::max(height, kIconSize + 2 * kVertOuterMargin));
-}
-
-void InstalledBubbleContent::Layout() {
-  int x = kHorizOuterMargin;
-  int y = kVertOuterMargin;
-
-  icon_->SetBounds(x, y, kIconSize, kIconSize);
-  x += kIconSize;
-  x += views::kPanelHorizMargin;
-
-  y += kRightcolumnVerticalShift;
-  heading_->SizeToFit(kRightColumnWidth);
-  heading_->SetX(x);
-  heading_->SetY(y);
-  y += heading_->height();
-  y += kVertInnerMargin;
-
-  if (flavors_ & HOW_TO_USE) {
-    how_to_use_->SizeToFit(kRightColumnWidth);
-    how_to_use_->SetX(x);
-    how_to_use_->SetY(y);
-    y += how_to_use_->height();
-    y += kVertInnerMargin;
-  }
-
-  if (flavors_ & HOW_TO_MANAGE) {
-    manage_->SizeToFit(kRightColumnWidth);
-    manage_->SetX(x);
-    manage_->SetY(y);
-    y += manage_->height();
-    y += kVertInnerMargin;
-  }
-
-  if (flavors_ & SIGN_IN_PROMO) {
-    height_of_signin_promo_ = LayoutSigninPromo(x, y);
-    y += height_of_signin_promo_;
-    y += kVertInnerMargin;
-  }
-
-  if (flavors_ & SHOW_KEYBINDING) {
-    gfx::Size sz = manage_shortcut_->GetPreferredSize();
-    manage_shortcut_->SetBounds(width() - 2 * kHorizOuterMargin - sz.width(),
-                                y,
-                                sz.width(),
-                                sz.height());
-    y += manage_shortcut_->height();
-    y += kVertInnerMargin;
-  }
-
-  gfx::Size sz;
-  x += kRightColumnWidth + 2 * views::kPanelHorizMargin + kHorizOuterMargin -
-      close_button_->GetPreferredSize().width();
-  y = kVertOuterMargin;
-  sz = close_button_->GetPreferredSize();
-  // x-1 & y-1 is just slop to get the close button visually aligned with the
-  // title text and bubble arrow.
-  close_button_->SetBounds(x - 1, y - 1, sz.width(), sz.height());
-}
-
-void InstalledBubbleContent::OnPaint(gfx::Canvas* canvas) {
-  for (ScopedVector<gfx::RenderText>::const_iterator it =
-           sign_in_promo_lines_.begin();
-       it != sign_in_promo_lines_.end(); ++it)
-    (*it)->Draw(canvas);
-
-  views::View::OnPaint(canvas);
-}
-
 ExtensionInstalledBubbleUi::ExtensionInstalledBubbleUi(
     ExtensionInstalledBubble* bubble)
     : bubble_(bubble), delegate_view_(nullptr) {
@@ -606,9 +400,8 @@
   delegate_view_->set_arrow(bubble_->type() == bubble_->OMNIBOX_KEYWORD
                                 ? views::BubbleBorder::TOP_LEFT
                                 : views::BubbleBorder::TOP_RIGHT);
-  delegate_view_->SetLayoutManager(new views::FillLayout());
-  delegate_view_->AddChildView(new InstalledBubbleContent(
-      *bubble_, bubble_reference, bubble_->browser()));
+
+  delegate_view_->InitLayout(*bubble_);
 
   views::BubbleDelegateView::CreateBubble(delegate_view_)->Show();
 }
diff --git a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.h b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.h
index b4beaf2..0d6d1cd6 100644
--- a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.h
+++ b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.h
@@ -7,15 +7,24 @@
 
 #include "base/macros.h"
 #include "chrome/browser/ui/extensions/extension_installed_bubble.h"
+#include "chrome/browser/ui/sync/bubble_sync_promo_delegate.h"
 #include "components/bubble/bubble_reference.h"
 #include "ui/views/bubble/bubble_delegate.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/link_listener.h"
 
 class Browser;
+class BubbleSyncPromoView;
 
 namespace extensions {
 class Extension;
 }
 
+namespace views {
+class LabelButton;
+class Link;
+}
+
 // Provides feedback to the user upon successful installation of an
 // extension. Depending on the type of extension, the Bubble will
 // point to:
@@ -25,7 +34,10 @@
 //                      bar which is shown while the Bubble is shown.
 //    GENERIC        -> The app menu. This case includes pageActions that don't
 //                      specify a default icon.
-class ExtensionInstalledBubbleView : public views::BubbleDelegateView {
+class ExtensionInstalledBubbleView : public BubbleSyncPromoDelegate,
+                                     public views::BubbleDelegateView,
+                                     public views::ButtonListener,
+                                     public views::LinkListener {
  public:
   ExtensionInstalledBubbleView(ExtensionInstalledBubble* bubble,
                                BubbleReference bubble_reference);
@@ -34,6 +46,18 @@
   // Recalculate the anchor position for this bubble.
   void UpdateAnchorView();
 
+  void InitLayout(const ExtensionInstalledBubble& bubble);
+
+ private:
+  // The different options to show in the installed bubble.
+  enum Options {
+    NONE = 0,
+    HOW_TO_USE = 1 << 0,
+    HOW_TO_MANAGE = 1 << 1,
+    SHOW_KEYBINDING = 1 << 2,
+    SIGN_IN_PROMO = 1 << 3,
+  };
+
   // views::BubbleDelegateView:
   void WindowClosing() override;
   gfx::Rect GetAnchorRect() const override;
@@ -41,12 +65,32 @@
   void OnWidgetActivationChanged(views::Widget* widget, bool active) override;
   bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
 
- private:
+  // BubbleSyncPromoDelegate:
+  void OnSignInLinkClicked() override;
+
+  // views::LinkListener:
+  void LinkClicked(views::Link* source, int event_flags) override;
+
+  // views::ButtonListener:
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
   BubbleReference bubble_reference_;
   const extensions::Extension* extension_;
   Browser* browser_;
   ExtensionInstalledBubble::BubbleType type_;
 
+  // A bitmask containing the various options of bubble sections to show.
+  int options_;
+
+  // The sync promo section of the bubble.
+  BubbleSyncPromoView* sync_promo_;
+
+  // The button to close the bubble.
+  views::LabelButton* close_;
+
+  // The shortcut to open the manage shortcuts page.
+  views::Link* manage_shortcut_;
+
   DISALLOW_COPY_AND_ASSIGN(ExtensionInstalledBubbleView);
 };
 
diff --git a/chrome/browser/ui/views/frame/browser_header_painter_ash.cc b/chrome/browser/ui/views/frame/browser_header_painter_ash.cc
index e6022e93..710951ba 100644
--- a/chrome/browser/ui/views/frame/browser_header_painter_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_header_painter_ash.cc
@@ -15,6 +15,7 @@
 #include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkPaint.h"
 #include "third_party/skia/include/core/SkPath.h"
+#include "ui/base/resource/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/theme_provider.h"
 #include "ui/gfx/animation/slide_animation.h"
@@ -218,8 +219,12 @@
         ash::HeaderPainterUtil::GetThemeBackgroundXInset());
   }
 
-  if (!frame_->IsMaximized() && !frame_->IsFullscreen())
+  if (!ui::MaterialDesignController::IsModeMaterial() &&
+      !frame_->IsMaximized() &&
+      !frame_->IsFullscreen()) {
     PaintHighlightForRestoredWindow(canvas);
+  }
+
   if (frame_->widget_delegate() &&
       frame_->widget_delegate()->ShouldShowWindowTitle()) {
     PaintTitleBar(canvas);
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
index 411089e..4155826 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -18,12 +18,12 @@
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/views/frame/browser_frame.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"
 #include "chrome/browser/ui/views/frame/web_app_left_header_view_ash.h"
-#include "chrome/browser/ui/views/layout_constants.h"
 #include "chrome/browser/ui/views/profiles/avatar_menu_button.h"
 #include "chrome/browser/ui/views/tab_icon_view.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc
similarity index 95%
rename from chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_ash.cc
rename to chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc
index 7ee9c48e..918be4f 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc
@@ -44,10 +44,15 @@
   }
 #endif
 
+#if defined(USE_ASH)
   BrowserNonClientFrameViewAsh* frame_view =
       new BrowserNonClientFrameViewAsh(frame, browser_view);
   frame_view->Init();
   return frame_view;
+#else
+  NOTREACHED();
+  return nullptr;
+#endif
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
index d8bff00..aef61f8 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
@@ -5,10 +5,10 @@
 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.h"
 
 #include "chrome/browser/themes/theme_properties.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/views/frame/browser_frame.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/browser_view_layout.h"
-#include "chrome/browser/ui/views/layout_constants.h"
 #include "grit/theme_resources.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/theme_provider.h"
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 d030b6c1..0acd143 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
@@ -13,13 +13,13 @@
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/layout_constants.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"
 #include "chrome/browser/ui/views/frame/web_app_left_header_view_ash.h"
-#include "chrome/browser/ui/views/layout_constants.h"
 #include "chrome/browser/ui/views/profiles/avatar_menu_button.h"
 #include "chrome/browser/ui/views/tab_icon_view.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index cbd2b2c..2f1616fd 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -42,7 +42,6 @@
 #include "chrome/browser/translate/chrome_translate_client.h"
 #include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/browser/ui/bookmarks/bookmark_bar_constants.h"
-#include "chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h"
 #include "chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_command_controller.h"
@@ -54,6 +53,7 @@
 #include "chrome/browser/ui/search/search_delegate.h"
 #include "chrome/browser/ui/search/search_model.h"
 #include "chrome/browser/ui/search/search_ui.h"
+#include "chrome/browser/ui/sync/bubble_sync_promo_delegate.h"
 #include "chrome/browser/ui/tabs/tab_menu_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/view_ids.h"
@@ -1298,7 +1298,7 @@
 }
 
 void BrowserView::ShowBookmarkBubble(const GURL& url, bool already_bookmarked) {
-  scoped_ptr<BookmarkBubbleDelegate> delegate;
+  scoped_ptr<BubbleSyncPromoDelegate> delegate;
   delegate.reset(new BookmarkBubbleSignInDelegate(browser_.get()));
 
   BookmarkBubbleView::ShowBubble(GetToolbarView()->GetBookmarkBubbleAnchor(),
@@ -1821,9 +1821,7 @@
     ui::WindowShowState* show_state) const {
   chrome::GetSavedWindowBoundsAndShowState(browser_.get(), bounds, show_state);
 
-  if (browser_->is_type_popup() &&
-      !browser_->is_app() &&
-      !browser_->is_trusted_source()) {
+  if (chrome::SavedBoundsAreContentBounds(browser_.get())) {
     // This is normal non-app popup window. The value passed in |bounds|
     // represents two pieces of information:
     // - the position of the window, in screen coordinates (outer position).
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.cc b/chrome/browser/ui/views/frame/browser_view_layout.cc
index af512ca..5c5e792 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout.cc
+++ b/chrome/browser/ui/views/frame/browser_view_layout.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/find_bar/find_bar.h"
 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/search/search_model.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
 #include "chrome/browser/ui/views/download/download_shelf_view.h"
@@ -20,7 +21,6 @@
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
 #include "chrome/browser/ui/views/frame/top_container_view.h"
 #include "chrome/browser/ui/views/infobars/infobar_container_view.h"
-#include "chrome/browser/ui/views/layout_constants.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "components/web_modal/web_contents_modal_dialog_host.h"
 #include "ui/base/hit_test.h"
diff --git a/chrome/browser/ui/views/frame/browser_view_unittest.cc b/chrome/browser/ui/views/frame/browser_view_unittest.cc
index 1d31c65a..ab66a8e 100644
--- a/chrome/browser/ui/views/frame/browser_view_unittest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_unittest.cc
@@ -6,12 +6,12 @@
 
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
 #include "chrome/browser/ui/views/frame/browser_view_layout.h"
 #include "chrome/browser/ui/views/frame/test_with_browser_view.h"
 #include "chrome/browser/ui/views/frame/top_container_view.h"
 #include "chrome/browser/ui/views/infobars/infobar_container_view.h"
-#include "chrome/browser/ui/views/layout_constants.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/common/url_constants.h"
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
index 801c90a..71f69fab 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
@@ -11,8 +11,8 @@
 #include "chrome/app/chrome_dll_resource.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/theme_properties.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views/layout_constants.h"
 #include "chrome/browser/ui/views/profiles/avatar_menu_button.h"
 #include "chrome/browser/ui/views/profiles/new_avatar_button.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
@@ -28,6 +28,7 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/icon_util.h"
 #include "ui/gfx/image/image.h"
+#include "ui/gfx/scoped_canvas.h"
 #include "ui/gfx/win/dpi.h"
 #include "ui/resources/grit/ui_resources.h"
 #include "ui/views/controls/label.h"
@@ -366,47 +367,76 @@
         GetTopInset(false) + Tab::GetYInsetForActiveTabBackground();
     int w = toolbar_bounds.width();
 
-    // Background.  The top stroke is drawn using the IDR_CONTENT_TOP_XXX
-    // images, which overlay the toolbar.  The top 2 px of these images is the
-    // actual top stroke + shadow, and is partly transparent, so the toolbar
-    // background shouldn't be drawn over it.
-    const int split_point = std::min(kContentEdgeShadowThickness, h);
-    if (h > split_point) {
-      const int split_y = y + split_point;
-      canvas->TileImageInt(*bg, x + GetThemeBackgroundXInset(), split_y - bg_y,
-                           x, split_y, w, h - split_point);
+    if (md) {
+      // Background.  The top stroke is drawn above the toolbar bounds, so
+      // unlike in the non-Material Design code below, we don't need to exclude
+      // any region from having the background image drawn over it.
+      if (tp->HasCustomImage(IDR_THEME_TOOLBAR)) {
+        canvas->TileImageInt(*bg, x + GetThemeBackgroundXInset(), y - bg_y, x,
+                             y, w, h);
+      } else {
+        canvas->FillRect(toolbar_bounds,
+                         tp->GetColor(ThemeProperties::COLOR_TOOLBAR));
+      }
+
+      // Material Design has no corners to mask out.
+
+      // Top stroke.  For Material Design, the toolbar has no side strokes.
+      gfx::Rect separator_rect(x, y, w, 0);
+      gfx::ScopedCanvas scoped_canvas(canvas);
+      gfx::Rect tabstrip_bounds(
+          GetBoundsForTabStrip(browser_view()->tabstrip()));
+      tabstrip_bounds.set_x(GetMirroredXForRect(tabstrip_bounds));
+      canvas->sk_canvas()->clipRect(gfx::RectToSkRect(tabstrip_bounds),
+                                    SkRegion::kDifference_Op);
+      separator_rect.set_y(tabstrip_bounds.bottom());
+      BrowserView::Paint1pxHorizontalLine(
+          canvas, SkColorSetA(SK_ColorBLACK, 0x40), separator_rect, true);
+    } else {
+      // Background.  The top stroke is drawn using the IDR_CONTENT_TOP_XXX
+      // images, which overlay the toolbar.  The top 2 px of these images is the
+      // actual top stroke + shadow, and is partly transparent, so the toolbar
+      // background shouldn't be drawn over it.
+      const int split_point = std::min(kContentEdgeShadowThickness, h);
+      if (h > split_point) {
+        const int split_y = y + split_point;
+        canvas->TileImageInt(*bg, x + GetThemeBackgroundXInset(),
+                             split_y - bg_y, x, split_y, w, h - split_point);
+      }
+
+      // On Windows 10+ where we don't draw our own window border but rather go
+      // right to the system border, the toolbar has no corners or side strokes.
+      if (base::win::GetVersion() < base::win::VERSION_WIN10) {
+        // Mask out the corners.
+        gfx::ImageSkia* left =
+            tp->GetImageSkiaNamed(IDR_CONTENT_TOP_LEFT_CORNER);
+        const int img_w = left->width();
+        x -= kContentEdgeShadowThickness;
+        SkPaint paint;
+        paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
+        canvas->DrawImageInt(
+            *tp->GetImageSkiaNamed(IDR_CONTENT_TOP_LEFT_CORNER_MASK), 0, 0,
+            img_w, h, x, y, img_w, h, false, paint);
+        const int right_x =
+            toolbar_bounds.right() + kContentEdgeShadowThickness - img_w;
+        canvas->DrawImageInt(
+            *tp->GetImageSkiaNamed(IDR_CONTENT_TOP_RIGHT_CORNER_MASK), 0, 0,
+            img_w, h, right_x, y, img_w, h, false, paint);
+
+        // Corner and side strokes.
+        canvas->DrawImageInt(*left, 0, 0, img_w, h, x, y, img_w, h, false);
+        canvas->DrawImageInt(
+            *tp->GetImageSkiaNamed(IDR_CONTENT_TOP_RIGHT_CORNER), 0, 0, img_w,
+            h, right_x, y, img_w, h, false);
+
+        x += img_w;
+        w = right_x - x;
+      }
+
+      // Top stroke.
+      canvas->TileImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_TOP_CENTER), x, y,
+                           w, split_point);
     }
-
-    // On Windows 10+ where we don't draw our own window border but rather go
-    // right to the system border, the toolbar has no corners or side strokes.
-    if (base::win::GetVersion() < base::win::VERSION_WIN10) {
-      // Mask out the corners.
-      gfx::ImageSkia* left = tp->GetImageSkiaNamed(IDR_CONTENT_TOP_LEFT_CORNER);
-      const int img_w = left->width();
-      x -= kContentEdgeShadowThickness;
-      SkPaint paint;
-      paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
-      canvas->DrawImageInt(
-          *tp->GetImageSkiaNamed(IDR_CONTENT_TOP_LEFT_CORNER_MASK), 0, 0, img_w,
-          h, x, y, img_w, h, false, paint);
-      const int right_x =
-          toolbar_bounds.right() + kContentEdgeShadowThickness - img_w;
-      canvas->DrawImageInt(
-          *tp->GetImageSkiaNamed(IDR_CONTENT_TOP_RIGHT_CORNER_MASK), 0, 0,
-          img_w, h, right_x, y, img_w, h, false, paint);
-
-      // Corner and side strokes.
-      canvas->DrawImageInt(*left, 0, 0, img_w, h, x, y, img_w, h, false);
-      canvas->DrawImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_TOP_RIGHT_CORNER),
-                           0, 0, img_w, h, right_x, y, img_w, h, false);
-
-      x += img_w;
-      w = right_x - x;
-    }
-
-    // Top stroke.
-    canvas->TileImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_TOP_CENTER), x, y,
-                         w, split_point);
   }
 
   // Toolbar/content separator.
@@ -448,8 +478,11 @@
     return;
 
   const int x = client_bounds.x();
-  y += toolbar_bounds.bottom();  // The side edges start below the toolbar.
-  const int img_y = y;
+  // Pre-Material Design, the client edge images start below the toolbar.  In MD
+  // the client edge images start at the top of the toolbar.
+  y += toolbar_bounds.bottom();
+  const int img_y = ui::MaterialDesignController::IsModeMaterial() ?
+      (y - toolbar_bounds.height()) : y;
   const int w = client_bounds.width();
   const int right = client_bounds.right();
   const int bottom = std::max(y, height() - NonClientBorderThickness(false));
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_factory_ash.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_factory_views.cc
similarity index 91%
rename from chrome/browser/ui/views/frame/immersive_mode_controller_factory_ash.cc
rename to chrome/browser/ui/views/frame/immersive_mode_controller_factory_views.cc
index 1d8848ae..99549a4 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_factory_ash.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_factory_views.cc
@@ -3,15 +3,20 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ui/host_desktop.h"
-#include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
 #include "chrome/browser/ui/views/frame/immersive_mode_controller_stub.h"
 
+#if defined(USE_ASH)
+#include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
+#endif
+
 namespace chrome {
 
 ImmersiveModeController* CreateImmersiveModeController(
     chrome::HostDesktopType host_desktop_type) {
+#if defined(USE_ASH)
   if (host_desktop_type == chrome::HOST_DESKTOP_TYPE_ASH)
     return new ImmersiveModeControllerAsh();
+#endif
 
   return new ImmersiveModeControllerStub();
 }
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index 597fd14..1ced4ca8 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -39,6 +39,7 @@
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/path.h"
+#include "ui/gfx/scoped_canvas.h"
 #include "ui/resources/grit/ui_resources.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/image_view.h"
@@ -649,49 +650,76 @@
         GetTopInset(false) + Tab::GetYInsetForActiveTabBackground();
     const int w = toolbar_bounds.width();
 
-    // Background.  We need to create a separate layer so we can mask off the
-    // corners before compositing onto the frame.
-    canvas->sk_canvas()->saveLayer(
-        gfx::RectToSkRect(gfx::Rect(x - kContentEdgeShadowThickness, y,
-                                    w + kContentEdgeShadowThickness * 2, h)),
-        nullptr);
+    if (md) {
+      // Background.  The top stroke is drawn above the toolbar bounds, so
+      // unlike in the non-Material Design code below, we don't need to exclude
+      // any region from having the background image drawn over it.
+      if (tp->HasCustomImage(IDR_THEME_TOOLBAR)) {
+        canvas->TileImageInt(*bg, x + GetThemeBackgroundXInset(), y - bg_y, x,
+                             y, w, h);
+      } else {
+        canvas->FillRect(toolbar_bounds,
+                         tp->GetColor(ThemeProperties::COLOR_TOOLBAR));
+      }
 
-    // The top stroke is drawn using the IDR_CONTENT_TOP_XXX images, which
-    // overlay the toolbar.  The top 2 px of these images is the actual top
-    // stroke + shadow, and is partly transparent, so the toolbar background
-    // shouldn't be drawn over it.
-    const int split_point = std::min(kContentEdgeShadowThickness, h);
-    if (h > split_point) {
-      const int split_y = y + split_point;
-      canvas->TileImageInt(*bg, x + GetThemeBackgroundXInset(), split_y - bg_y,
-                           x, split_y, w, h - split_point);
+      // Material Design has no corners to mask out.
+
+      // Top stroke.  For Material Design, the toolbar has no side strokes.
+      gfx::Rect separator_rect(x, y, w, 0);
+      gfx::ScopedCanvas scoped_canvas(canvas);
+      gfx::Rect tabstrip_bounds(
+          GetBoundsForTabStrip(browser_view()->tabstrip()));
+      tabstrip_bounds.set_x(GetMirroredXForRect(tabstrip_bounds));
+      canvas->sk_canvas()->clipRect(gfx::RectToSkRect(tabstrip_bounds),
+                                    SkRegion::kDifference_Op);
+      separator_rect.set_y(tabstrip_bounds.bottom());
+      BrowserView::Paint1pxHorizontalLine(
+          canvas, SkColorSetA(SK_ColorBLACK, 0x40), separator_rect, true);
+    } else {
+      // Background.  We need to create a separate layer so we can mask off the
+      // corners before compositing onto the frame.
+      canvas->sk_canvas()->saveLayer(
+          gfx::RectToSkRect(gfx::Rect(x - kContentEdgeShadowThickness, y,
+                                      w + kContentEdgeShadowThickness * 2, h)),
+          nullptr);
+
+      // The top stroke is drawn using the IDR_CONTENT_TOP_XXX images, which
+      // overlay the toolbar.  The top 2 px of these images is the actual top
+      // stroke + shadow, and is partly transparent, so the toolbar background
+      // shouldn't be drawn over it.
+      const int split_point = std::min(kContentEdgeShadowThickness, h);
+      if (h > split_point) {
+        const int split_y = y + split_point;
+        canvas->TileImageInt(*bg, x + GetThemeBackgroundXInset(),
+                             split_y - bg_y, x, split_y, w, h - split_point);
+      }
+
+      // Mask out the corners.
+      gfx::ImageSkia* left = tp->GetImageSkiaNamed(IDR_CONTENT_TOP_LEFT_CORNER);
+      const int img_w = left->width();
+      x -= kContentEdgeShadowThickness;
+      SkPaint paint;
+      paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
+      canvas->DrawImageInt(
+          *tp->GetImageSkiaNamed(IDR_CONTENT_TOP_LEFT_CORNER_MASK), 0, 0, img_w,
+          h, x, y, img_w, h, false, paint);
+      const int right_x =
+          toolbar_bounds.right() + kContentEdgeShadowThickness - img_w;
+      canvas->DrawImageInt(
+          *tp->GetImageSkiaNamed(IDR_CONTENT_TOP_RIGHT_CORNER_MASK), 0, 0,
+          img_w, h, right_x, y, img_w, h, false, paint);
+      canvas->Restore();
+
+      // Corner and side strokes.
+      canvas->DrawImageInt(*left, 0, 0, img_w, h, x, y, img_w, h, false);
+      canvas->DrawImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_TOP_RIGHT_CORNER),
+                           0, 0, img_w, h, right_x, y, img_w, h, false);
+
+      // Top stroke.
+      x += img_w;
+      canvas->TileImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_TOP_CENTER), x, y,
+                           right_x - x, split_point);
     }
-
-    // Mask out the corners.
-    gfx::ImageSkia* left = tp->GetImageSkiaNamed(IDR_CONTENT_TOP_LEFT_CORNER);
-    const int img_w = left->width();
-    x -= kContentEdgeShadowThickness;
-    SkPaint paint;
-    paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
-    canvas->DrawImageInt(
-        *tp->GetImageSkiaNamed(IDR_CONTENT_TOP_LEFT_CORNER_MASK), 0, 0, img_w,
-        h, x, y, img_w, h, false, paint);
-    const int right_x =
-        toolbar_bounds.right() + kContentEdgeShadowThickness - img_w;
-    canvas->DrawImageInt(
-        *tp->GetImageSkiaNamed(IDR_CONTENT_TOP_RIGHT_CORNER_MASK), 0, 0, img_w,
-        h, right_x, y, img_w, h, false, paint);
-    canvas->Restore();
-
-    // Corner and side strokes.
-    canvas->DrawImageInt(*left, 0, 0, img_w, h, x, y, img_w, h, false);
-    canvas->DrawImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_TOP_RIGHT_CORNER),
-                         0, 0, img_w, h, right_x, y, img_w, h, false);
-
-    // Top stroke.
-    x += img_w;
-    canvas->TileImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_TOP_CENTER), x, y,
-                         right_x - x, split_point);
   }
 
   // Toolbar/content separator.
@@ -713,6 +741,7 @@
   const int w = client_bounds.width();
   const int right = client_bounds.right();
   const bool normal_mode = browser_view()->IsTabStripVisible();
+  const bool md = ui::MaterialDesignController::IsModeMaterial();
   const ui::ThemeProvider* tp = GetThemeProvider();
   const SkColor toolbar_color = normal_mode ?
       tp->GetColor(ThemeProperties::COLOR_TOOLBAR) :
@@ -721,8 +750,11 @@
   const gfx::Rect toolbar_bounds(browser_view()->GetToolbarBounds());
   int img_y_offset = 0;
   if (normal_mode) {
-    // The client edge images start below the toolbar.
+    // Pre-Material Design, the client edge images start below the toolbar.  In
+    // MD the client edge images start at the top of the toolbar.
     y += toolbar_bounds.bottom();
+    if (md)
+      img_y_offset = -toolbar_bounds.height();
   } else {
     // The toolbar isn't going to draw a top edge for us, so draw one ourselves.
     if (IsToolbarVisible()) {
@@ -732,21 +764,33 @@
     client_bounds.set_y(y);
     client_bounds.Inset(-kClientEdgeThickness, -kClientEdgeThickness,
                         -kClientEdgeThickness, client_bounds.height());
+    if (md) {
+      img_y_offset = -kClientEdgeThickness;
 
-    // Edge.
-    canvas->FillRect(client_bounds, toolbar_color);
+      // Edge.
+      BrowserView::Paint1pxHorizontalLine(canvas, toolbar_color, client_bounds,
+                                          false);
 
-    // Shadow.
-    gfx::ImageSkia* top_left = tp->GetImageSkiaNamed(IDR_APP_TOP_LEFT);
-    const int img_w = top_left->width();
-    const int height = top_left->height();
-    const int top_y = y - height;
-    canvas->DrawImageInt(*top_left, 0, 0, img_w, height, x - img_w, top_y,
-                         img_w, height, false);
-    canvas->TileImageInt(*tp->GetImageSkiaNamed(IDR_APP_TOP_CENTER), 0, 0, x,
-                         top_y, w, height);
-    canvas->DrawImageInt(*tp->GetImageSkiaNamed(IDR_APP_TOP_RIGHT), 0, 0, img_w,
-                         height, right, top_y, img_w, height, false);
+      // Shadow.
+      client_bounds.Offset(0, img_y_offset);
+      BrowserView::Paint1pxHorizontalLine(
+          canvas, SkColorSetA(SK_ColorBLACK, 0x40), client_bounds, true);
+    } else {
+      // Edge.
+      canvas->FillRect(client_bounds, toolbar_color);
+
+      // Shadow.
+      gfx::ImageSkia* top_left = tp->GetImageSkiaNamed(IDR_APP_TOP_LEFT);
+      const int img_w = top_left->width();
+      const int height = top_left->height();
+      const int top_y = y - height;
+      canvas->DrawImageInt(*top_left, 0, 0, img_w, height, x - img_w, top_y,
+                           img_w, height, false);
+      canvas->TileImageInt(*tp->GetImageSkiaNamed(IDR_APP_TOP_CENTER), 0, 0, x,
+                           top_y, w, height);
+      canvas->DrawImageInt(*tp->GetImageSkiaNamed(IDR_APP_TOP_RIGHT), 0, 0,
+                           img_w, height, right, top_y, img_w, height, false);
+    }
   }
 
   // In maximized mode, the only edge to draw is the top one, so we're done.
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
index 7739c7ac..b26381a 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
@@ -6,7 +6,7 @@
 
 #include "base/command_line.h"
 #include "chrome/browser/profiles/profiles_state.h"
-#include "chrome/browser/ui/views/layout_constants.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/views/profiles/avatar_menu_button.h"
 #include "chrome/common/chrome_switches.h"
 #include "components/signin/core/common/profile_management_switches.h"
diff --git a/chrome/browser/ui/views/location_bar/background_with_1_px_border.cc b/chrome/browser/ui/views/location_bar/background_with_1_px_border.cc
index 3b35843..d62f030 100644
--- a/chrome/browser/ui/views/location_bar/background_with_1_px_border.cc
+++ b/chrome/browser/ui/views/location_bar/background_with_1_px_border.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/views/location_bar/background_with_1_px_border.h"
 
-#include "chrome/browser/ui/views/layout_constants.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "third_party/skia/include/core/SkPaint.h"
 #include "third_party/skia/include/core/SkPath.h"
 #include "third_party/skia/include/pathops/SkPathOps.h"
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
index be10bab..9befb257 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/ui/views/location_bar/icon_label_bubble_view.h"
 
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/ui/views/layout_constants.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/views/location_bar/background_with_1_px_border.h"
 #include "ui/base/resource/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc
index 2fa92b5..38783b0 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc
@@ -31,7 +31,8 @@
 
 void LocationBarBubbleDelegateView::ShowForReason(DisplayReason reason) {
   if (reason == USER_GESTURE) {
-    SetArrowPaintType(views::BubbleBorder::PAINT_TRANSPARENT);
+    // TODO(estade): re-enable this when crbug.com/518941 is fixed.
+    // SetArrowPaintType(views::BubbleBorder::PAINT_TRANSPARENT);
     GetWidget()->Show();
   } else {
     GetWidget()->ShowInactive();
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index b98e28c0..b1e3cda 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -33,11 +33,11 @@
 #include "chrome/browser/ui/browser_instant_controller.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/autofill/save_card_icon_view.h"
 #include "chrome/browser/ui/views/browser_dialogs.h"
-#include "chrome/browser/ui/views/layout_constants.h"
 #include "chrome/browser/ui/views/location_bar/background_with_1_px_border.h"
 #include "chrome/browser/ui/views/location_bar/content_setting_image_view.h"
 #include "chrome/browser/ui/views/location_bar/ev_bubble_view.h"
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 0d1f683a..2b19ade 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
@@ -8,7 +8,7 @@
 
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/themes/theme_properties.h"
-#include "chrome/browser/ui/views/layout_constants.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/omnibox/omnibox_result_view.h"
 #include "components/omnibox/browser/omnibox_view.h"
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index 79c2b69..74e37b25 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -16,7 +16,7 @@
 #include "base/i18n/bidi_line_iterator.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
-#include "chrome/browser/ui/views/layout_constants.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h"
 #include "chrome/grit/generated_resources.h"
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view.cc b/chrome/browser/ui/views/sync/bubble_sync_promo_view.cc
similarity index 66%
rename from chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view.cc
rename to chrome/browser/ui/views/sync/bubble_sync_promo_view.cc
index d0fff27..e74134d4 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view.cc
+++ b/chrome/browser/ui/views/sync/bubble_sync_promo_view.cc
@@ -2,12 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view.h"
+#include "chrome/browser/ui/views/sync/bubble_sync_promo_view.h"
 
 #include "base/strings/string16.h"
-#include "chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h"
-#include "chrome/grit/chromium_strings.h"
-#include "chrome/grit/generated_resources.h"
+#include "chrome/browser/ui/sync/bubble_sync_promo_delegate.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/font.h"
@@ -32,18 +30,17 @@
 
 }  // namespace
 
-BookmarkSyncPromoView::BookmarkSyncPromoView(BookmarkBubbleDelegate* delegate)
+BubbleSyncPromoView::BubbleSyncPromoView(BubbleSyncPromoDelegate* delegate,
+                                         int link_text_resource_id,
+                                         int message_text_resource_id)
     : delegate_(delegate) {
   set_background(views::Background::CreateSolidBackground(kBackgroundColor));
-  SetBorder(views::Border::CreateSolidSidedBorder(
-      kBorderWidth, 0, 0, 0, kBorderColor));
-  size_t offset;
-  base::string16 link_text =
-      l10n_util::GetStringUTF16(IDS_BOOKMARK_SYNC_PROMO_LINK);
-  base::string16 promo_text = l10n_util::GetStringFUTF16(
-      IDS_BOOKMARK_SYNC_PROMO_MESSAGE,
-      link_text,
-      &offset);
+  SetBorder(views::Border::CreateSolidSidedBorder(kBorderWidth, 0, 0, 0,
+                                                  kBorderColor));
+  size_t offset = 0;
+  base::string16 link_text = l10n_util::GetStringUTF16(link_text_resource_id);
+  base::string16 promo_text =
+      l10n_util::GetStringFUTF16(message_text_resource_id, link_text, &offset);
 
   views::StyledLabel* promo_label = new views::StyledLabel(promo_text, this);
   promo_label->SetDisplayedOnBackgroundColor(kBackgroundColor);
@@ -65,18 +62,19 @@
 
   views::BoxLayout* layout = new views::BoxLayout(views::BoxLayout::kVertical,
                                                   views::kButtonHEdgeMarginNew,
-                                                  views::kPanelVertMargin,
-                                                  0);
+                                                  views::kPanelVertMargin, 0);
   SetLayoutManager(layout);
   AddChildView(promo_label);
 }
 
-void BookmarkSyncPromoView::StyledLabelLinkClicked(views::StyledLabel* label,
-                                                   const gfx::Range& range,
-                                                   int event_flags) {
+BubbleSyncPromoView::~BubbleSyncPromoView() {}
+
+void BubbleSyncPromoView::StyledLabelLinkClicked(views::StyledLabel* label,
+                                                 const gfx::Range& range,
+                                                 int event_flags) {
   delegate_->OnSignInLinkClicked();
 }
 
-const char* BookmarkSyncPromoView::GetClassName() const {
-  return "BookmarkSyncPromoView";
+const char* BubbleSyncPromoView::GetClassName() const {
+  return "BubbleSyncPromoView";
 }
diff --git a/chrome/browser/ui/views/sync/bubble_sync_promo_view.h b/chrome/browser/ui/views/sync/bubble_sync_promo_view.h
new file mode 100644
index 0000000..7b80591
--- /dev/null
+++ b/chrome/browser/ui/views/sync/bubble_sync_promo_view.h
@@ -0,0 +1,40 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_SYNC_BUBBLE_SYNC_PROMO_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_SYNC_BUBBLE_SYNC_PROMO_VIEW_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ui/views/controls/styled_label_listener.h"
+#include "ui/views/view.h"
+
+class BubbleSyncPromoDelegate;
+
+// Bookmark sync promo displayed at the bottom of the bookmark bubble.
+class BubbleSyncPromoView : public views::StyledLabelListener,
+                            public views::View {
+ public:
+  // |delegate| is not owned by BubbleSyncPromoView.
+  BubbleSyncPromoView(BubbleSyncPromoDelegate* delegate,
+                      int link_text_resource_id,
+                      int message_text_resource_id);
+  ~BubbleSyncPromoView() override;
+
+ private:
+  // views::StyledLabelListener:
+  void StyledLabelLinkClicked(views::StyledLabel* label,
+                              const gfx::Range& range,
+                              int event_flags) override;
+
+  // views::View:
+  const char* GetClassName() const override;
+
+  // Delegate, to handle clicks on the sign in link.
+  BubbleSyncPromoDelegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(BubbleSyncPromoView);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_SYNC_BUBBLE_SYNC_PROMO_VIEW_H_
diff --git a/chrome/browser/ui/views/sync/bubble_sync_promo_view_unittest.cc b/chrome/browser/ui/views/sync/bubble_sync_promo_view_unittest.cc
new file mode 100644
index 0000000..fe7907d
--- /dev/null
+++ b/chrome/browser/ui/views/sync/bubble_sync_promo_view_unittest.cc
@@ -0,0 +1,46 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/sync/bubble_sync_promo_view.h"
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ui/sync/bubble_sync_promo_delegate.h"
+#include "chrome/grit/chromium_strings.h"
+#include "chrome/grit/generated_resources.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event_constants.h"
+#include "ui/gfx/range/range.h"
+#include "ui/views/controls/styled_label.h"
+
+class BubbleSyncPromoViewTest : public BubbleSyncPromoDelegate,
+                                public testing::Test {
+ public:
+  BubbleSyncPromoViewTest() : sign_in_clicked_count_(0) {}
+
+ protected:
+  // BubbleSyncPromoDelegate:
+  void OnSignInLinkClicked() override { ++sign_in_clicked_count_; }
+
+  // Number of times that OnSignInLinkClicked has been called.
+  int sign_in_clicked_count_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BubbleSyncPromoViewTest);
+};
+
+TEST_F(BubbleSyncPromoViewTest, SignInLink) {
+  scoped_ptr<BubbleSyncPromoView> sync_promo;
+  sync_promo.reset(new BubbleSyncPromoView(this, IDS_BOOKMARK_SYNC_PROMO_LINK,
+                                           IDS_BOOKMARK_SYNC_PROMO_MESSAGE));
+
+  // Simulate clicking the "Sign in" link.
+  views::StyledLabel styled_label(base::ASCIIToUTF16("test"), nullptr);
+  views::StyledLabelListener* listener = sync_promo.get();
+  listener->StyledLabelLinkClicked(&styled_label, gfx::Range(), ui::EF_NONE);
+
+  EXPECT_EQ(1, sign_in_clicked_count_);
+}
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 77a55373..87250a9 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -12,10 +12,10 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
 #include "chrome/browser/ui/view_ids.h"
-#include "chrome/browser/ui/views/layout_constants.h"
 #include "chrome/browser/ui/views/tabs/media_indicator_button.h"
 #include "chrome/browser/ui/views/tabs/tab_controller.h"
 #include "chrome/browser/ui/views/theme_image_mapper.h"
@@ -26,9 +26,11 @@
 #include "grit/components_scaled_resources.h"
 #include "grit/theme_resources.h"
 #include "third_party/skia/include/effects/SkGradientShader.h"
+#include "third_party/skia/include/pathops/SkPathOps.h"
 #include "ui/accessibility/ax_view_state.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/list_selection_model.h"
+#include "ui/base/resource/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/theme_provider.h"
 #include "ui/gfx/animation/animation_container.h"
@@ -41,6 +43,7 @@
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/path.h"
+#include "ui/gfx/scoped_canvas.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/gfx/vector_icons_public.h"
 #include "ui/resources/grit/ui_resources.h"
@@ -81,7 +84,7 @@
 const double kHoverOpacity = 0.33;
 
 // Opacity of the active tab background painted over inactive selected tabs.
-const double kSelectedTabOpacity = 0.45;
+const double kSelectedTabOpacity = 0.3;
 
 // Inactive selected tabs have their throb value scaled by this.
 const double kSelectedTabThrobScale = 0.95 - kSelectedTabOpacity;
@@ -436,6 +439,7 @@
 
 // static
 const char Tab::kViewClassName[] = "Tab";
+const SkColor Tab::kInactiveTabColor = SkColorSetRGB(0xD0, 0xD0, 0xD0);
 Tab::TabImages Tab::active_images_ = {0};
 Tab::TabImages Tab::inactive_images_ = {0};
 Tab::TabImages Tab::mask_images_ = {0};
@@ -648,10 +652,17 @@
 }
 
 gfx::Size Tab::GetMinimumInactiveSize() {
-  // Since we use images, the real minimum height of the image is
-  // defined most accurately by the height of the end cap images.
-  InitTabResources();
-  int height = active_images_.image_l->height();
+  int height;
+  if (ui::MaterialDesignController::IsModeMaterial()) {
+    const int kTabHeight = 29;
+    height = kTabHeight;
+  } else {
+    // Since we use images, the real minimum height of the image is
+    // defined most accurately by the height of the end cap images.
+    InitTabResources();
+    height = active_images_.image_l->height();
+  }
+
   return gfx::Size(GetLayoutInsets(TAB).width(), height);
 }
 
@@ -765,52 +776,59 @@
   const bool extend_to_top =
       widget && (widget->IsMaximized() || widget->IsFullscreen());
 
-  // Hit mask constants.
-  const SkScalar kTabCapWidth = 15;
-  const SkScalar kTabTopCurveWidth = 4;
-  const SkScalar kTabBottomCurveWidth = 3;
+  if (ui::MaterialDesignController::IsModeMaterial()) {
+    SkPath border;
+    const float scale = GetWidget()->GetCompositor()->device_scale_factor();
+    GetBorderPath(scale, extend_to_top, &border);
+    mask->addPath(border, SkMatrix::MakeScale(1 / scale));
+  } else {
+    // Hit mask constants.
+    const SkScalar kTabCapWidth = 15;
+    const SkScalar kTabTopCurveWidth = 4;
+    const SkScalar kTabBottomCurveWidth = 3;
 #if defined(OS_MACOSX)
-  // Mac's Cocoa UI doesn't have shadows.
-  const SkScalar kTabInset = 0;
+    // Mac's Cocoa UI doesn't have shadows.
+    const SkScalar kTabInset = 0;
 #elif defined(TOOLKIT_VIEWS)
-  // The views browser UI has shadows in the left, right and top parts of the
-  // tab.
-  const SkScalar kTabInset = 6;
+    // The views browser UI has shadows in the left, right and top parts of the
+    // tab.
+    const SkScalar kTabInset = 6;
 #endif
 
-  SkScalar left = kTabInset;
-  SkScalar top = GetLayoutConstant(TAB_TOP_EXCLUSION_HEIGHT);
-  SkScalar right = SkIntToScalar(width()) - kTabInset;
-  SkScalar bottom = SkIntToScalar(height());
+    SkScalar left = kTabInset;
+    SkScalar top = GetLayoutConstant(TAB_TOP_EXCLUSION_HEIGHT);
+    SkScalar right = SkIntToScalar(width()) - kTabInset;
+    SkScalar bottom = SkIntToScalar(height());
 
-  // Start in the lower-left corner.
-  mask->moveTo(left, bottom);
+    // Start in the lower-left corner.
+    mask->moveTo(left, bottom);
 
-  // Left end cap.
-  mask->lineTo(left + kTabBottomCurveWidth, bottom - kTabBottomCurveWidth);
-  mask->lineTo(left + kTabCapWidth - kTabTopCurveWidth,
-               top + kTabTopCurveWidth);
-  mask->lineTo(left + kTabCapWidth, top);
+    // Left end cap.
+    mask->lineTo(left + kTabBottomCurveWidth, bottom - kTabBottomCurveWidth);
+    mask->lineTo(left + kTabCapWidth - kTabTopCurveWidth,
+                 top + kTabTopCurveWidth);
+    mask->lineTo(left + kTabCapWidth, top);
 
-  // Extend over the top shadow area if we have one and the caller wants it.
-  if (top > 0 && extend_to_top) {
-    mask->lineTo(left + kTabCapWidth, 0);
-    mask->lineTo(right - kTabCapWidth, 0);
+    // Extend over the top shadow area if we have one and the caller wants it.
+    if (top > 0 && extend_to_top) {
+      mask->lineTo(left + kTabCapWidth, 0);
+      mask->lineTo(right - kTabCapWidth, 0);
+    }
+
+    // Connect to the right cap.
+    mask->lineTo(right - kTabCapWidth, top);
+
+    // Right end cap.
+    mask->lineTo(right - kTabCapWidth + kTabTopCurveWidth,
+                 top + kTabTopCurveWidth);
+    mask->lineTo(right - kTabBottomCurveWidth, bottom - kTabBottomCurveWidth);
+    mask->lineTo(right, bottom);
+
+    // Close out the path.
+    mask->lineTo(left, bottom);
+    mask->close();
   }
 
-  // Connect to the right cap.
-  mask->lineTo(right - kTabCapWidth, top);
-
-  // Right end cap.
-  mask->lineTo(right - kTabCapWidth + kTabTopCurveWidth,
-               top + kTabTopCurveWidth);
-  mask->lineTo(right - kTabBottomCurveWidth, bottom - kTabBottomCurveWidth);
-  mask->lineTo(right, bottom);
-
-  // Close out the path.
-  mask->lineTo(left, bottom);
-  mask->close();
-
   // It is possible for a portion of the tab to be occluded if tabs are
   // stacked, so modify the hit test mask to only include the visible
   // region of the tab.
@@ -1240,15 +1258,26 @@
   }
   SkPoint p;
   p.set(SkDoubleToScalar(x), 0);
-  gfx::Canvas background_canvas(size(), canvas->image_scale(), false);
-  PaintInactiveTabBackground(&background_canvas);
-  gfx::ImageSkia background_image(background_canvas.ExtractImageRep());
-  canvas->DrawImageInt(background_image, 0, 0);
-  gfx::Canvas hover_canvas(size(), canvas->image_scale(), false);
-  DrawHighlight(&hover_canvas, p, SkFloatToScalar(radius), alpha);
-  gfx::ImageSkia hover_image = gfx::ImageSkiaOperations::CreateMaskedImage(
-      gfx::ImageSkia(hover_canvas.ExtractImageRep()), background_image);
-  canvas->DrawImageInt(hover_image, 0, 0);
+  if (ui::MaterialDesignController::IsModeMaterial()) {
+    PaintInactiveTabBackground(canvas);
+    gfx::ScopedCanvas scoped_canvas(canvas);
+    const float scale = canvas->UndoDeviceScaleFactor();
+    SkPath fill;
+    GetFillPath(scale, &fill);
+    canvas->ClipPath(fill, true);
+    p.scale(SkFloatToScalar(scale));
+    DrawHighlight(canvas, p, SkFloatToScalar(radius * scale), alpha);
+  } else {
+    gfx::Canvas background_canvas(size(), canvas->image_scale(), false);
+    PaintInactiveTabBackground(&background_canvas);
+    gfx::ImageSkia background_image(background_canvas.ExtractImageRep());
+    canvas->DrawImageInt(background_image, 0, 0);
+    gfx::Canvas hover_canvas(size(), canvas->image_scale(), false);
+    DrawHighlight(&hover_canvas, p, SkFloatToScalar(radius), alpha);
+    gfx::ImageSkia hover_image = gfx::ImageSkiaOperations::CreateMaskedImage(
+        gfx::ImageSkia(hover_canvas.ExtractImageRep()), background_image);
+    canvas->DrawImageInt(hover_image, 0, 0);
+  }
 }
 
 void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas) {
@@ -1303,31 +1332,75 @@
   SkPoint hover_location(PointToSkPoint(hover_controller_.location()));
   const SkAlpha hover_alpha = hover_controller_.GetAlpha();
 
-  if (draw_hover) {
-    // Draw everything to a temporary canvas so we can extract an image for use
-    // in masking the hover glow.
-    gfx::Canvas background_canvas(size(), canvas->image_scale(), false);
-    PaintTabFill(&background_canvas, fill_image, x_offset, y_offset, is_active);
-    gfx::ImageSkia background_image(background_canvas.ExtractImageRep());
-    canvas->DrawImageInt(background_image, 0, 0);
+  if (ui::MaterialDesignController::IsModeMaterial()) {
+    gfx::ScopedCanvas scoped_canvas(canvas);
+    const float scale = canvas->UndoDeviceScaleFactor();
 
-    gfx::Canvas hover_canvas(size(), canvas->image_scale(), false);
-    DrawHighlight(&hover_canvas, hover_location, radius, hover_alpha);
-    gfx::ImageSkia result = gfx::ImageSkiaOperations::CreateMaskedImage(
-        gfx::ImageSkia(hover_canvas.ExtractImageRep()), background_image);
-    canvas->DrawImageInt(result, 0, 0);
+    // Draw the fill.
+    SkPath fill;
+    GetFillPath(scale, &fill);
+    SkPaint paint;
+    paint.setAntiAlias(true);
+    {
+      gfx::ScopedCanvas clip_scoper(canvas);
+      canvas->ClipPath(fill, true);
+      if (has_custom_image) {
+        gfx::ScopedCanvas scale_scoper(canvas);
+        canvas->sk_canvas()->scale(scale, scale);
+        canvas->TileImageInt(*fill_image, x_offset, y_offset, 0, 0, width(),
+                             height());
+      } else {
+        paint.setColor(
+            is_active ? SkColorSetRGB(0xF2, 0xF2, 0xF2) : kInactiveTabColor);
+        canvas->DrawRect(gfx::ScaleToEnclosingRect(GetLocalBounds(), scale),
+                         paint);
+      }
+      if (draw_hover) {
+        hover_location.scale(SkFloatToScalar(scale));
+        DrawHighlight(canvas, hover_location, radius * scale, hover_alpha);
+      }
+    }
+
+    // Draw the stroke.
+    SkPath stroke;
+    GetBorderPath(scale, false, &stroke);
+    Op(stroke, fill, kDifference_SkPathOp, &stroke);
+    if (!is_active) {
+      // Clip out the bottom line; this will be drawn for us by
+      // TabStrip::PaintChildren().
+      canvas->sk_canvas()->clipRect(
+          SkRect::MakeWH(width() * scale, height() * scale - 1));
+    }
+    paint.setARGB(0x40, 0x00, 0x00, 0x00);
+    canvas->DrawPath(stroke, paint);
   } else {
-    PaintTabFill(canvas, fill_image, x_offset, y_offset, is_active);
-  }
+    if (draw_hover) {
+      // Draw everything to a temporary canvas so we can extract an image for
+      // use in masking the hover glow.
+      gfx::Canvas background_canvas(size(), canvas->image_scale(), false);
+      PaintTabFill(&background_canvas, fill_image, x_offset, y_offset,
+                   is_active);
+      gfx::ImageSkia background_image(background_canvas.ExtractImageRep());
+      canvas->DrawImageInt(background_image, 0, 0);
 
-  // Now draw the stroke, highlights, and shadows around the tab edge.
-  TabImages* stroke_images = is_active ? &active_images_ : &inactive_images_;
-  canvas->DrawImageInt(*stroke_images->image_l, 0, 0);
-  canvas->TileImageInt(
-      *stroke_images->image_c, stroke_images->l_width, 0,
-      width() - stroke_images->l_width - stroke_images->r_width, height());
-  canvas->DrawImageInt(*stroke_images->image_r,
-                       width() - stroke_images->r_width, 0);
+      gfx::Canvas hover_canvas(size(), canvas->image_scale(), false);
+      DrawHighlight(&hover_canvas, hover_location, radius, hover_alpha);
+      gfx::ImageSkia result = gfx::ImageSkiaOperations::CreateMaskedImage(
+          gfx::ImageSkia(hover_canvas.ExtractImageRep()), background_image);
+      canvas->DrawImageInt(result, 0, 0);
+    } else {
+      PaintTabFill(canvas, fill_image, x_offset, y_offset, is_active);
+    }
+
+    // Now draw the stroke, highlights, and shadows around the tab edge.
+    TabImages* stroke_images = is_active ? &active_images_ : &inactive_images_;
+    canvas->DrawImageInt(*stroke_images->image_l, 0, 0);
+    canvas->TileImageInt(
+        *stroke_images->image_c, stroke_images->l_width, 0,
+        width() - stroke_images->l_width - stroke_images->r_width, height());
+    canvas->DrawImageInt(*stroke_images->image_r,
+                         width() - stroke_images->r_width, 0);
+  }
 }
 
 void Tab::PaintTabFill(gfx::Canvas* canvas,
@@ -1543,6 +1616,66 @@
   SchedulePaintInRect(bounds);
 }
 
+void Tab::GetFillPath(float scale, SkPath* fill) const {
+  const float right = width() * scale;
+  const float bottom = height() * scale;
+
+  fill->moveTo(right - 1, bottom);
+  fill->rCubicTo(-0.75 * scale, 0, -1.625 * scale, -0.5 * scale, -2 * scale,
+                 -1.5 * scale);
+  fill->lineTo(right - 1 - 13.5 * scale, 2.5 * scale);
+  // Prevent overdraw in the center near minimum width (only happens if
+  // scale < 2).  We could instead avoid this by increasing the tab inset
+  // values, but that would shift all the content inward as well, unless we
+  // then overlapped the content on the endcaps, by which point we'd have a
+  // huge mess.
+  const float total_endcap_width = 31 * scale + 2;
+  const float overlap = total_endcap_width - right;
+  const float offset = (overlap > 0) ? (overlap / 2) : 0;
+  fill->rCubicTo(-0.375 * scale, -1 * scale, -1.25 * scale + offset,
+                 -1.5 * scale, -2 * scale + offset, -1.5 * scale);
+  if (overlap < 0)
+    fill->lineTo(1 + 15.5 * scale, scale);
+  fill->rCubicTo(-0.75 * scale, 0, -1.625 * scale - offset, 0.5 * scale,
+                 -2 * scale - offset, 1.5 * scale);
+  fill->lineTo(1 + 2 * scale, bottom - 1.5 * scale);
+  fill->rCubicTo(-0.375 * scale, scale, -1.25 * scale, 1.5 * scale, -2 * scale,
+                 1.5 * scale);
+  fill->close();
+}
+
+void Tab::GetBorderPath(float scale, bool extend_to_top, SkPath* path) const {
+  const float top = scale - 1;
+  const float right = width() * scale;
+  const float bottom = height() * scale;
+
+  path->moveTo(0, bottom);
+  path->rLineTo(0, -1);
+  path->rCubicTo(0.75 * scale, 0, 1.625 * scale, -0.5 * scale, 2 * scale,
+                 -1.5 * scale);
+  path->lineTo(13.5 * scale, top + 1.5 * scale);
+  if (extend_to_top) {
+    // Create the vertical extension by extending the side diagonals until they
+    // reach the top of the bounds.
+    const float dy = 2.5 * scale - 1;
+    const float dx = 11.5 / 25 * dy;
+    path->rLineTo(dx, -dy);
+    path->lineTo(right - 13.5 * scale - dx, 0);
+    path->rLineTo(dx, dy);
+  } else {
+    path->rCubicTo(0.375 * scale, -scale, 1.25 * scale, -1.5 * scale, 2 * scale,
+                   -1.5 * scale);
+    path->lineTo(right - 15.5 * scale, top);
+    path->rCubicTo(0.75 * scale, 0, 1.625 * scale, 0.5 * scale, 2 * scale,
+                   1.5 * scale);
+  }
+  path->lineTo(right - 2 * scale, bottom - 1 - 1.5 * scale);
+  path->rCubicTo(0.375 * scale, scale, 1.25 * scale, 1.5 * scale, 2 * scale,
+                 1.5 * scale);
+  path->rLineTo(0, 1);
+  path->close();
+}
+
 gfx::Rect Tab::GetImmersiveBarRect() const {
   // The main bar is as wide as the normal tab's horizontal top line.
   // This top line of the tab extends a few pixels left and right of the
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index 850a864..726ca75 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -51,6 +51,9 @@
   // The Tab's class name.
   static const char kViewClassName[];
 
+  // The color of an inactive tab.
+  static const SkColor kInactiveTabColor;
+
   explicit Tab(TabController* controller);
   ~Tab() override;
 
@@ -298,6 +301,16 @@
   // Schedules repaint task for icon.
   void ScheduleIconPaint();
 
+  // Computes a path corresponding to the tab's content region inside the outer
+  // stroke.
+  void GetFillPath(float scale, SkPath* path) const;
+
+  // Computes a path corresponding to the tab's outer border for a given |scale|
+  // and stores it in |path|.  If |extend_to_top| is true, the path is extended
+  // vertically to the top of the tab bounds.  The caller uses this for Fitts'
+  // Law purposes in maximized/fullscreen mode.
+  void GetBorderPath(float scale, bool extend_to_top, SkPath* path) const;
+
   // Returns the rectangle for the light bar in immersive mode.
   gfx::Rect GetImmersiveBarRect() const;
 
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index cc67bd4..34f422f8 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -16,9 +16,10 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/ui/host_desktop.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/view_ids.h"
-#include "chrome/browser/ui/views/layout_constants.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/tabs/stacked_tab_strip_layout.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
 #include "chrome/browser/ui/views/tabs/tab_drag_controller.h"
@@ -31,11 +32,16 @@
 #include "content/public/browser/user_metrics.h"
 #include "content/public/common/content_switches.h"
 #include "grit/theme_resources.h"
+#include "third_party/skia/include/core/SkColorFilter.h"
+#include "third_party/skia/include/effects/SkBlurMaskFilter.h"
+#include "third_party/skia/include/effects/SkLayerDrawLooper.h"
+#include "third_party/skia/include/pathops/SkPathOps.h"
 #include "ui/accessibility/ax_view_state.h"
 #include "ui/base/default_theme_provider.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/list_selection_model.h"
+#include "ui/base/resource/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/compositor/compositing_recorder.h"
 #include "ui/compositor/paint_recorder.h"
@@ -126,6 +132,28 @@
       GetLayoutConstant(TABSTRIP_NEW_TAB_BUTTON_OVERLAP);
 }
 
+skia::RefPtr<SkDrawLooper> CreateShadowDrawLooper(SkAlpha alpha) {
+  SkLayerDrawLooper::Builder looper_builder;
+  looper_builder.addLayer();
+
+  SkLayerDrawLooper::LayerInfo layer_info;
+  layer_info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit;
+  layer_info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit;
+  layer_info.fColorMode = SkXfermode::kDst_Mode;
+  layer_info.fOffset.set(0, 1);
+  skia::RefPtr<SkMaskFilter> blur_mask =
+      skia::AdoptRef(SkBlurMaskFilter::Create(
+          kNormal_SkBlurStyle, 0.5, SkBlurMaskFilter::kHighQuality_BlurFlag));
+  skia::RefPtr<SkColorFilter> color_filter =
+      skia::AdoptRef(SkColorFilter::CreateModeFilter(
+          SkColorSetA(SK_ColorBLACK, alpha), SkXfermode::kSrcIn_Mode));
+  SkPaint* layer_paint = looper_builder.addLayer(layer_info);
+  layer_paint->setMaskFilter(blur_mask.get());
+  layer_paint->setColorFilter(color_filter.get());
+
+  return skia::AdoptRef(looper_builder.detachLooper());
+}
+
 // Animation delegate used for any automatic tab movement.  Hides the tab if it
 // is not fully visible within the tabstrip area, to prevent overflow clipping.
 class TabAnimationDelegate : public gfx::AnimationDelegate {
@@ -267,11 +295,22 @@
   // views::MaskedTargeterDelegate:
   bool GetHitTestMask(gfx::Path* mask) const override;
 
+  // Computes a path corresponding to the button's outer border for a given
+  // |scale| and stores it in |path|.  |button_y| is used as the y-coordinate
+  // for the top of the button.  If |extend_to_top| is true, the path is
+  // extended vertically to y = 0.  The caller uses this for Fitts' Law purposes
+  // in maximized/fullscreen mode.
+  void GetBorderPath(float button_y,
+                     float scale,
+                     bool extend_to_top,
+                     SkPath* path) const;
+
   // Paints the fill region of the button into |canvas|, according to the
-  // supplied values from GetImage().
+  // supplied values from GetImage() and the given |fill| path.
   void PaintFill(bool pressed,
                  double hover_value,
                  float scale,
+                 const SkPath& fill,
                  gfx::Canvas* canvas) const;
 
   // Tab strip that contains this button.
@@ -339,32 +378,77 @@
     hover_value = hover_animation_->GetCurrentValue();
   const float scale = canvas->image_scale();
 
-  // Fill.
-  gfx::ImageSkia* mask =
-      GetThemeProvider()->GetImageSkiaNamed(IDR_NEWTAB_BUTTON_MASK);
-  // The canvas and mask have to use the same scale factor.
-  const float fill_canvas_scale = mask->HasRepresentation(scale) ?
-      scale : ui::GetScaleForScaleFactor(ui::SCALE_FACTOR_100P);
-  gfx::Canvas fill_canvas(GetNewTabButtonSize(), fill_canvas_scale, false);
-  PaintFill(pressed, hover_value, fill_canvas_scale, &fill_canvas);
-  gfx::ImageSkia image(fill_canvas.ExtractImageRep());
-  canvas->DrawImageInt(
-      gfx::ImageSkiaOperations::CreateMaskedImage(image, *mask), 0, 0);
+  SkPath fill;
+  if (ui::MaterialDesignController::IsModeMaterial()) {
+    // Fill.
+    fill.moveTo(9.75 * scale, 16 * scale);
+    fill.rCubicTo(-0.75 * scale, 0, -1.625 * scale, -0.5 * scale, -2 * scale,
+                  -1.5 * scale);
+    fill.rLineTo(-5.75 * scale, -12.5 * scale);
+    fill.rCubicTo(0, -0.5 * scale, 0.25 * scale, -scale, scale, -scale);
+    fill.rLineTo(23.25 * scale, 0);
+    fill.rCubicTo(0.75 * scale, 0, 1.625 * scale, 0.5 * scale, 2 * scale,
+                  1.5 * scale);
+    fill.rLineTo(5.75 * scale, 12.5 * scale);
+    fill.rCubicTo(0, 0.5 * scale, -0.25 * scale, scale, -scale, scale);
+    fill.close();
+    PaintFill(pressed, hover_value, scale, fill, canvas);
 
-  // Stroke.  Draw the button border with a slight alpha.
-  static const SkAlpha kGlassFrameOverlayAlpha = 178;
-  static const SkAlpha kOpaqueFrameOverlayAlpha = 230;
-  const SkAlpha alpha = GetWidget()->ShouldWindowContentsBeTransparent() ?
-      kGlassFrameOverlayAlpha : kOpaqueFrameOverlayAlpha;
-  const int overlay_id = pressed ? IDR_NEWTAB_BUTTON_P : IDR_NEWTAB_BUTTON;
-  canvas->DrawImageInt(*GetThemeProvider()->GetImageSkiaNamed(overlay_id), 0, 0,
-                       alpha);
+    // Stroke.
+    gfx::ScopedCanvas scoped_canvas(canvas);
+    canvas->UndoDeviceScaleFactor();
+    SkPath stroke;
+    GetBorderPath(0, scale, false, &stroke);
+    // We want to draw a drop shadow either inside or outside the stroke,
+    // depending on whether we're pressed; so, either clip out what's outside
+    // the stroke, or clip out the fill inside it.
+    if (pressed)
+      canvas->ClipPath(stroke, true);
+    Op(stroke, fill, kDifference_SkPathOp, &stroke);
+    if (!pressed)
+      canvas->sk_canvas()->clipPath(fill, SkRegion::kDifference_Op, true);
+    // Now draw the stroke and shadow; the stroke will always be visible, while
+    // the shadow will be affected by the clip we set above.
+    SkPaint paint;
+    paint.setAntiAlias(true);
+    skia::RefPtr<SkDrawLooper> stroke_looper = CreateShadowDrawLooper(0x8C);
+    paint.setLooper(stroke_looper.get());
+    paint.setColor(SkColorSetA(SK_ColorBLACK, pressed ? 0x38 : 0x27));
+    canvas->DrawPath(stroke, paint);
+  } else {
+    // Fill.
+    gfx::ImageSkia* mask =
+        GetThemeProvider()->GetImageSkiaNamed(IDR_NEWTAB_BUTTON_MASK);
+    // The canvas and mask have to use the same scale factor.
+    const float fill_canvas_scale = mask->HasRepresentation(scale) ?
+        scale : ui::GetScaleForScaleFactor(ui::SCALE_FACTOR_100P);
+    gfx::Canvas fill_canvas(GetNewTabButtonSize(), fill_canvas_scale, false);
+    PaintFill(pressed, hover_value, fill_canvas_scale, fill, &fill_canvas);
+    gfx::ImageSkia image(fill_canvas.ExtractImageRep());
+    canvas->DrawImageInt(
+        gfx::ImageSkiaOperations::CreateMaskedImage(image, *mask), 0, 0);
+
+    // Stroke.  Draw the button border with a slight alpha.
+    static const SkAlpha kGlassFrameOverlayAlpha = 178;
+    static const SkAlpha kOpaqueFrameOverlayAlpha = 230;
+    const SkAlpha alpha = GetWidget()->ShouldWindowContentsBeTransparent() ?
+        kGlassFrameOverlayAlpha : kOpaqueFrameOverlayAlpha;
+    const int overlay_id = pressed ? IDR_NEWTAB_BUTTON_P : IDR_NEWTAB_BUTTON;
+    canvas->DrawImageInt(*GetThemeProvider()->GetImageSkiaNamed(overlay_id), 0,
+                         0, alpha);
+  }
 }
 
 bool NewTabButton::GetHitTestMask(gfx::Path* mask) const {
   DCHECK(mask);
 
-  if (tab_strip_->SizeTabButtonToTopOfTabStrip()) {
+  if (ui::MaterialDesignController::IsModeMaterial()) {
+    SkPath border;
+    const float scale = GetWidget()->GetCompositor()->device_scale_factor();
+    GetBorderPath(TabStrip::kNewTabButtonVerticalOffset * scale, scale,
+                  tab_strip_->SizeTabButtonToTopOfTabStrip(), &border);
+    mask->addPath(border, SkMatrix::MakeScale(1 / scale));
+  } else if (tab_strip_->SizeTabButtonToTopOfTabStrip()) {
     // When the button is sized to the top of the tab strip, we want the hit
     // test mask to be defined as the complete (rectangular) bounds of the
     // button.
@@ -393,56 +477,134 @@
   return true;
 }
 
+void NewTabButton::GetBorderPath(float button_y,
+                                 float scale,
+                                 bool extend_to_top,
+                                 SkPath* path) const {
+  path->moveTo(9.75 * scale - 1, button_y + 16 * scale + 1);
+  path->rCubicTo(-0.75 * scale, 0, -1.625 * scale, -0.5 * scale, -2 * scale,
+                 -1.5 * scale);
+  path->rLineTo(-5.75 * scale, -12.5 * scale);
+  if (extend_to_top) {
+    // Create the vertical extension by extending the side diagonals at the
+    // upper left and lower right corners until they reach the top and bottom of
+    // the border, respectively (in other words, "un-round-off" those corners
+    // and turn them into sharp points).  Then extend upward from the corner
+    // points to the top of the bounds.
+    const float dy = scale + 2;
+    const float dx = 11.5 / 25 * dy;
+    path->rLineTo(-dx, -dy);
+    path->rLineTo(0, -button_y - scale + 1);
+    path->lineTo(34 * scale + 1 + dx, 0);
+    path->rLineTo(0, button_y + 16 * scale + 1);
+  } else {
+    path->rCubicTo(-0.5 * scale, -1.125 * scale, 0.5 * scale, -scale - 2, scale,
+                   -scale - 2);
+    path->rLineTo(23.25 * scale + 2, 0);
+    path->rCubicTo(0.75 * scale, 0, 1.625 * scale, 0.5 * scale, 2 * scale,
+                   1.5 * scale);
+    path->rLineTo(5.75 * scale, 12.5 * scale);
+    path->rCubicTo(0.5 * scale, 1.125 * scale, -0.5 * scale, scale + 2, -scale,
+                   scale + 2);
+  }
+  path->close();
+}
+
 void NewTabButton::PaintFill(bool pressed,
                              double hover_value,
                              float scale,
+                             const SkPath& fill,
                              gfx::Canvas* canvas) const {
   bool custom_image;
   const int bg_id = tab_strip_->GetBackgroundResourceId(&custom_image);
 
+  gfx::ScopedCanvas scoped_canvas(canvas);
+
+  const bool md = ui::MaterialDesignController::IsModeMaterial();
+  if (md) {
+    canvas->UndoDeviceScaleFactor();
+
+    // For unpressed buttons, draw the fill and its shadow.
+    if (!pressed) {
+      gfx::ScopedCanvas scoped_canvas(canvas);
+
+      // For custom themes, clip out the fill path itself so only the shadow
+      // around it is drawn.  We'll draw the fill image below.
+      if (custom_image)
+        canvas->sk_canvas()->clipPath(fill, SkRegion::kDifference_Op, true);
+
+      SkPaint paint;
+      paint.setAntiAlias(true);
+      skia::RefPtr<SkDrawLooper> looper = CreateShadowDrawLooper(0x26);
+      paint.setLooper(looper.get());
+      paint.setColor(Tab::kInactiveTabColor);
+      canvas->DrawPath(fill, paint);
+    }
+
+    // Clip to just the fill region for any theme drawing and hover/pressed
+    // state overlay drawing below.  In non-MD mode, this is done on the caller
+    // side using image masking operations.
+    canvas->ClipPath(fill, true);
+    canvas->sk_canvas()->scale(scale, scale);
+  }
+
   // Draw the fill background image.
   const gfx::Size size(GetNewTabButtonSize());
-  const ui::ThemeProvider* theme_provider = GetThemeProvider();
-  gfx::ImageSkia* background = theme_provider->GetImageSkiaNamed(bg_id);
-  // For custom tab backgrounds the background starts at the top of the tab
-  // strip. Otherwise the background starts at the top of the frame.
-  const int offset_y = theme_provider->HasCustomImage(bg_id) ?
-      -GetLayoutConstant(TAB_TOP_EXCLUSION_HEIGHT) : background_offset_.y();
+  if (custom_image || !md) {
+    const ui::ThemeProvider* theme_provider = GetThemeProvider();
+    gfx::ImageSkia* background = theme_provider->GetImageSkiaNamed(bg_id);
+    // For custom tab backgrounds the background starts at the top of the tab
+    // strip. Otherwise the background starts at the top of the frame.
+    const int offset_y = theme_provider->HasCustomImage(bg_id) ?
+        -GetLayoutConstant(TAB_TOP_EXCLUSION_HEIGHT) : background_offset_.y();
 
-  // The new tab background is mirrored in RTL mode, but the theme background
-  // should never be mirrored. Mirror it here to compensate.
-  float x_scale = 1.0f;
-  int x = GetMirroredX() + background_offset_.x();
-  if (base::i18n::IsRTL()) {
-    x_scale = -1.0f;
-    // Offset by |width| such that the same region is painted as if there was
-    // no flip.
-    x += size.width();
-  }
-  canvas->TileImageInt(*background, x,
-                       TabStrip::kNewTabButtonVerticalOffset + offset_y,
-                       x_scale, 1.0f, 0, 0, size.width(), size.height());
+    // The new tab background is mirrored in RTL mode, but the theme background
+    // should never be mirrored. Mirror it here to compensate.
+    float x_scale = 1.0f;
+    int x = GetMirroredX() + background_offset_.x();
+    if (base::i18n::IsRTL()) {
+      x_scale = -1.0f;
+      // Offset by |width| such that the same region is painted as if there was
+      // no flip.
+      x += size.width();
+    }
+    canvas->TileImageInt(*background, x,
+                         TabStrip::kNewTabButtonVerticalOffset + offset_y,
+                         x_scale, 1.0f, 0, 0, size.width(), size.height());
 
-  // Adjust the alpha of the fill to match that of inactive tabs (except for
-  // pressed buttons, which get a different value).
-  static const SkAlpha kPressedAlpha = 145;
-  const SkAlpha alpha =
-      pressed ? kPressedAlpha : tab_strip_->GetInactiveAlpha(true);
-  if (alpha != 255) {
-    SkPaint paint;
-    paint.setAlpha(alpha);
-    paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
-    paint.setStyle(SkPaint::kFill_Style);
-    canvas->DrawRect(gfx::Rect(size), paint);
+    // For non-MD, adjust the alpha of the fill to match that of inactive tabs
+    // (except for pressed buttons, which get a different value).  For MD, we do
+    // this with an opacity recorder in TabStrip::PaintChildren() so the fill
+    // and stroke are both affected, to better match how tabs are handled, but
+    // in non-MD, the button stroke is already lighter than the tab stroke, and
+    // using the opacity recorder washes it out too much.
+    static const SkAlpha kPressedAlpha = 145;
+    const SkAlpha alpha =
+        pressed ? kPressedAlpha : tab_strip_->GetInactiveAlpha(true);
+    if (alpha != 255 && !md) {
+      SkPaint paint;
+      paint.setAlpha(alpha);
+      paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
+      paint.setStyle(SkPaint::kFill_Style);
+      canvas->DrawRect(gfx::Rect(size), paint);
+    }
   }
 
   // White highlight on hover.
   if (hover_value) {
     const int alpha =
-        gfx::Tween::LinearIntValueBetween(hover_value, 0x00, 0x40);
+        gfx::Tween::LinearIntValueBetween(hover_value, 0x00, md ? 0x4D : 0x40);
     canvas->FillRect(GetLocalBounds(),
                      SkColorSetA(SK_ColorWHITE, static_cast<SkAlpha>(alpha)));
   }
+
+  // For MD, most states' opacities are adjusted using an opacity recorder in
+  // TabStrip::PaintChildren(), but the pressed state is excluded there and
+  // instead rendered using a dark overlay here.  This produces a different
+  // effect than for non-MD, and avoiding the use of the opacity recorder keeps
+  // the stroke more visible in this state.
+  if (md && pressed)
+    canvas->FillRect(GetLocalBounds(), SkColorSetA(SK_ColorBLACK, 0x14));
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -927,7 +1089,7 @@
   static const SkAlpha kInactiveTabAlphaAsh = 230;
   static const SkAlpha kInactiveTabAlphaGlass = 200;
   static const SkAlpha kInactiveTabAlphaOpaque = 255;
-  static const double kMultiSelectionMultiplier = 0.75;
+  static const double kMultiSelectionMultiplier = 0.6;
 
   const chrome::HostDesktopType host_desktop_type =
       chrome::GetHostDesktopTypeForNativeView(GetWidget()->GetNativeView());
@@ -1270,13 +1432,11 @@
   Tabs selected_tabs;
 
   {
-    const chrome::HostDesktopType host_desktop_type =
-        chrome::GetHostDesktopTypeForNativeView(GetWidget()->GetNativeView());
-    const uint8_t inactive_tab_alpha =
-        (host_desktop_type == chrome::HOST_DESKTOP_TYPE_ASH) ?
-            GetInactiveAlpha(false) : 255;
+    // TODO(pkasting): This results in greyscale AA for the tab titles.  Work
+    // with Mike Reed to fix, or else convert to passing the tabs a memory
+    // canvas to paint on and then manually compositing.
     ui::CompositingRecorder opacity_recorder(context, size(),
-                                             inactive_tab_alpha);
+                                             GetInactiveAlpha(false));
 
     PaintClosingTabs(tab_count(), context);
 
@@ -1319,28 +1479,6 @@
     }
   }
 
-  if (GetWidget()->ShouldWindowContentsBeTransparent()) {
-    ui::PaintRecorder recorder(context, size());
-    // Make sure non-active tabs are somewhat transparent.
-    SkPaint paint;
-    // If there are multiple tabs selected, fade non-selected tabs more to make
-    // the selected tabs more noticable.
-    uint8_t alpha = GetInactiveAlpha(false);
-    paint.setColor(SkColorSetA(SK_ColorWHITE, alpha));
-    paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
-    paint.setStyle(SkPaint::kFill_Style);
-
-    gfx::Rect bounds(GetLocalBounds());
-    // The tab graphics include some shadows at the top, plus a 1 pixel top
-    // stroke.  Exclude this region when trying to make tabs transparent as it's
-    // transparent enough already, and drawing in this region can overlap the
-    // avatar button, leading to visual artifacts.  Also exclude the toolbar
-    // overlap region at the bottom.
-    gfx::Insets tab_insets(GetLayoutInsets(TAB));
-    bounds.Inset(0, tab_insets.top(), 0, tab_insets.bottom());
-    recorder.canvas()->DrawRect(bounds, paint);
-  }
-
   // Now selected but not active. We don't want these dimmed if using native
   // frame, so they're painted after initial pass.
   for (size_t i = 0; i < selected_tabs.size(); ++i)
@@ -1351,7 +1489,16 @@
     active_tab->Paint(context);
 
   // Paint the New Tab button.
-  newtab_button_->Paint(context);
+  const bool md = ui::MaterialDesignController::IsModeMaterial();
+  if (md && (newtab_button_->state() != views::CustomButton::STATE_PRESSED)) {
+    // Match the inactive tab opacity for non-pressed states.  See comments in
+    // NewTabButton::PaintFill() for why we don't do this for the pressed state.
+    ui::CompositingRecorder opacity_recorder(context, size(),
+                                             GetInactiveAlpha(true));
+    newtab_button_->Paint(context);
+  } else {
+    newtab_button_->Paint(context);
+  }
 
   // And the dragged tabs.
   for (size_t i = 0; i < tabs_dragging.size(); ++i)
@@ -1360,6 +1507,18 @@
   // If the active tab is being dragged, it goes last.
   if (active_tab && is_dragging)
     active_tab->Paint(context);
+
+  if (md) {
+    ui::PaintRecorder recorder(context, size());
+    gfx::Canvas* canvas = recorder.canvas();
+    if (active_tab) {
+      canvas->sk_canvas()->clipRect(
+          gfx::RectToSkRect(active_tab->GetMirroredBounds()),
+          SkRegion::kDifference_Op);
+    }
+    BrowserView::Paint1pxHorizontalLine(
+        canvas, SkColorSetA(SK_ColorBLACK, 0x40), GetLocalBounds(), true);
+  }
 }
 
 const char* TabStrip::GetClassName() const {
diff --git a/chrome/browser/ui/views/toolbar/app_menu.cc b/chrome/browser/ui/views/toolbar/app_menu.cc
index 3b920e7..cd65d6ae 100644
--- a/chrome/browser/ui/views/toolbar/app_menu.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu.cc
@@ -272,6 +272,7 @@
     set_background(in_menu_background_);
     SetBorder(views::Border::CreateEmptyBorder(0, kHorizontalPadding, 0,
                                                kHorizontalPadding));
+    SetFontList(MenuConfig::instance().font_list);
   }
 
   void SetOtherButtons(const InMenuButton* left, const InMenuButton* right) {
@@ -280,9 +281,6 @@
 
   // views::LabelButton
   void OnNativeThemeChanged(const ui::NativeTheme* theme) override {
-    const MenuConfig& menu_config = MenuConfig::instance(theme);
-    SetFontList(menu_config.font_list);
-
     if (theme) {
       SetTextColor(
           views::Button::STATE_DISABLED,
@@ -596,10 +594,9 @@
   void OnNativeThemeChanged(const ui::NativeTheme* theme) override {
     AppMenuView::OnNativeThemeChanged(theme);
 
-    const MenuConfig& menu_config = MenuConfig::instance(theme);
     zoom_label_->SetBorder(views::Border::CreateEmptyBorder(
         0, kZoomLabelHorizontalPadding, 0, kZoomLabelHorizontalPadding));
-    zoom_label_->SetFontList(menu_config.font_list);
+    zoom_label_->SetFontList(MenuConfig::instance().font_list);
     zoom_label_max_width_valid_ = false;
 
     if (theme) {
@@ -1115,7 +1112,7 @@
 
     if (model->GetCommandIdAt(i) == IDC_EDIT_MENU ||
         model->GetCommandIdAt(i) == IDC_ZOOM_MENU) {
-      const MenuConfig& config = item->GetMenuConfig();
+      const MenuConfig& config = views::MenuConfig::instance();
       int top_margin = config.item_top_margin + config.separator_height / 2;
       int bottom_margin =
           config.item_bottom_margin + config.separator_height / 2;
diff --git a/chrome/browser/ui/views/toolbar/app_menu_button.cc b/chrome/browser/ui/views/toolbar/app_menu_button.cc
index c4a1a82..eb9589d 100644
--- a/chrome/browser/ui/views/toolbar/app_menu_button.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu_button.cc
@@ -10,9 +10,9 @@
 #include "base/time/time.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/toolbar/app_menu_model.h"
 #include "chrome/browser/ui/views/extensions/browser_action_drag_data.h"
-#include "chrome/browser/ui/views/layout_constants.h"
 #include "chrome/browser/ui/views/toolbar/app_menu.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "extensions/common/feature_switch.h"
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container.cc b/chrome/browser/ui/views/toolbar/browser_actions_container.cc
index cea30f9..29658f4 100644
--- a/chrome/browser/ui/views/toolbar/browser_actions_container.cc
+++ b/chrome/browser/ui/views/toolbar/browser_actions_container.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_delegate.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
@@ -31,6 +32,7 @@
 #include "ui/base/dragdrop/drag_utils.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/nine_image_painter_factory.h"
+#include "ui/base/resource/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/theme_provider.h"
 #include "ui/gfx/canvas.h"
@@ -44,7 +46,11 @@
 namespace {
 
 // Horizontal spacing before the chevron (if visible).
-const int kChevronSpacing = ToolbarView::kStandardSpacing - 2;
+// TODO(tdanderson): In material design, the chevron should have the same size
+//                   and vertical spacing as the other action buttons.
+int GetChevronSpacing() {
+  return GetLayoutConstant(TOOLBAR_STANDARD_SPACING) - 2;
+}
 
 // Returns the ToolbarView for the given |browser|.
 ToolbarView* GetToolbarView(Browser* browser) {
@@ -315,7 +321,8 @@
 }
 
 int BrowserActionsContainer::GetChevronWidth() const {
-  return chevron_ ? chevron_->GetPreferredSize().width() + kChevronSpacing : 0;
+  return chevron_ ?
+      chevron_->GetPreferredSize().width() + GetChevronSpacing() : 0;
 }
 
 void BrowserActionsContainer::ShowExtensionMessageBubble(
@@ -417,7 +424,8 @@
     chevron_->SetVisible(true);
     gfx::Size chevron_size(chevron_->GetPreferredSize());
     chevron_->SetBounds(
-        width() - ToolbarView::kStandardSpacing - chevron_size.width(),
+        width() - GetLayoutConstant(TOOLBAR_STANDARD_SPACING) -
+            chevron_size.width(),
         0,
         chevron_size.width(),
         chevron_size.height());
@@ -466,11 +474,12 @@
   if (VisibleBrowserActions() != 0) {
     // Figure out where to display the indicator. This is a complex calculation:
 
-    // First, we subtract out the padding to the left of the icon area, which is
-    // ToolbarView::kStandardSpacing. If we're right-to-left, we also mirror the
-    // event.x() so that our calculations are consistent with left-to-right.
+    // First, we subtract out the padding to the left of the icon area. If
+    // we're right-to-left, we also mirror the event.x() so that our
+    // calculations are consistent with left-to-right.
     int offset_into_icon_area =
-        GetMirroredXInView(event.x()) - ToolbarView::kStandardSpacing;
+        GetMirroredXInView(event.x()) -
+            GetLayoutConstant(TOOLBAR_STANDARD_SPACING);
 
     // Next, figure out what row we're on. This only matters for overflow mode,
     // but the calculation is the same for both.
@@ -704,25 +713,20 @@
 
     // Convert back to a pixel offset into the container.  First find the X
     // coordinate of the drop icon.
-    int drop_icon_x = ToolbarView::kStandardSpacing +
+    const int drop_icon_x = GetLayoutConstant(TOOLBAR_STANDARD_SPACING) +
         (drop_position_->icon_in_row * ToolbarActionsBar::IconWidth(true));
-    // Next, find the space before the drop icon. This will either be
-    // left padding or item spacing, depending on whether this is the first
-    // icon.
-    // NOTE: Right now, these are the same. But let's do this right for if they
-    // ever aren't.
-    int space_before_drop_icon = drop_position_->icon_in_row == 0 ?
-        platform_settings().left_padding : platform_settings().item_spacing;
+    // Next, find the space before the drop icon.
+    const int space_before_drop_icon = platform_settings().item_spacing;
     // Now place the drop indicator halfway between this and the end of the
     // previous icon.  If there is an odd amount of available space between the
     // two icons (or the icon and the address bar) after subtracting the drop
     // indicator width, this calculation puts the extra pixel on the left side
     // of the indicator, since when the indicator is between the address bar and
     // the first icon, it looks better closer to the icon.
-    int drop_indicator_x = drop_icon_x -
+    const int drop_indicator_x = drop_icon_x -
         ((space_before_drop_icon + kDropIndicatorWidth) / 2);
-    int row_height = ToolbarActionsBar::IconHeight();
-    int drop_indicator_y = row_height * drop_position_->row;
+    const int row_height = ToolbarActionsBar::IconHeight();
+    const int drop_indicator_y = row_height * drop_position_->row;
     gfx::Rect indicator_bounds(drop_indicator_x,
                                drop_indicator_y,
                                kDropIndicatorWidth,
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container.h b/chrome/browser/ui/views/toolbar/browser_actions_container.h
index 97ca4ee8..22b7eab 100644
--- a/chrome/browser/ui/views/toolbar/browser_actions_container.h
+++ b/chrome/browser/ui/views/toolbar/browser_actions_container.h
@@ -52,19 +52,20 @@
 // layout is similar to this:
 //   rI_I_IcCs
 // Where the letters are as follows:
-//   r: An invisible resize area.  This is ToolbarView::kStandardSpacing pixels
-//      wide and directly adjacent to the omnibox. Only shown for the main
-//      container.
-//   I: An icon.  This is as wide as the IDR_BROWSER_ACTION image.
-//   _: kItemSpacing pixels of empty space.
-//   c: kChevronSpacing pixels of empty space.  Only present if C is present.
+//   r: An invisible resize area.  This is
+//      GetLayoutConstant(TOOLBAR_STANDARD_SPACING) pixels wide and directly
+//      adjacent to the omnibox. Only shown for the main container.
+//   I: An icon. In material design this has a width of 28. Otherwise it is as
+//      wide as the IDR_BROWSER_ACTION image.
+//   _: ToolbarActionsBar::PlatformSettings::item_spacing pixels of empty space.
+//   c: GetChevronSpacing() pixels of empty space. Only present if C is present.
 //   C: An optional chevron, as wide as the IDR_BROWSER_ACTIONS_OVERFLOW image,
 //      and visible only when both of the following statements are true:
 //      - The container is set to a width smaller than needed to show all icons.
 //      - There is no other container in 'overflow' mode to handle the
 //        non-visible icons for this container.
-//   s: ToolbarView::kStandardSpacing pixels of empty space (before the app
-//      menu).
+//   s: GetLayoutConstant(TOOLBAR_STANDARD_SPACING) pixels of empty space
+//      (before the app menu).
 // The reason the container contains the trailing space "s", rather than having
 // it be handled by the parent view, is so that when the chevron is invisible
 // and the user starts dragging an icon around, we have the space to draw the
diff --git a/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc b/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc
index 20e3fab..0232e6c2 100644
--- a/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc
+++ b/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc
@@ -74,8 +74,7 @@
 int ExtensionToolbarMenuView::GetHeightForWidth(int width) const {
   // The width passed in here includes the full width of the menu, so we need
   // to omit the necessary padding.
-  const views::MenuConfig& menu_config =
-      static_cast<const views::MenuItemView*>(parent())->GetMenuConfig();
+  const views::MenuConfig& menu_config = views::MenuConfig::instance();
   int end_padding = menu_config.arrow_to_edge_padding -
       container_->toolbar_actions_bar()->platform_settings().item_spacing;
   width -= start_padding() + end_padding;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
index 524fb95..e11905b7 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
@@ -67,10 +67,9 @@
       called_register_command_(false),
       wants_to_run_(false),
       menu_(nullptr),
+      ink_drop_delegate_(new views::ButtonInkDropDelegate(this, this)),
       weak_factory_(this) {
-  scoped_ptr<views::InkDropDelegate> new_ink_drop_delegate(
-      new views::ButtonInkDropDelegate(this, this));
-  SetInkDropDelegate(new_ink_drop_delegate.Pass());
+  set_ink_drop_delegate(ink_drop_delegate_.get());
   set_id(VIEW_ID_BROWSER_ACTION);
   view_controller_->SetDelegate(this);
   SetHorizontalAlignment(gfx::ALIGN_CENTER);
@@ -109,6 +108,8 @@
   if (context_menu_owner == this)
     context_menu_owner = nullptr;
   view_controller_->SetDelegate(nullptr);
+  ink_drop_delegate_.reset();
+  set_ink_drop_delegate(nullptr);
 }
 
 void ToolbarActionView::GetAccessibleState(ui::AXViewState* state) {
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.h b/chrome/browser/ui/views/toolbar/toolbar_action_view.h
index 7df2efe..71f00a4 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.h
@@ -183,6 +183,8 @@
 
   content::NotificationRegistrar registrar_;
 
+  scoped_ptr<views::InkDropDelegate> ink_drop_delegate_;
+
   base::WeakPtrFactory<ToolbarActionView> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ToolbarActionView);
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button.cc b/chrome/browser/ui/views/toolbar/toolbar_button.cc
index 03bf129c..65788cc 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_button.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_button.cc
@@ -8,7 +8,7 @@
 #include "base/location.h"
 #include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
-#include "chrome/browser/ui/views/layout_constants.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "ui/accessibility/ax_view_state.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index 2218f48..182b887e 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -26,12 +26,12 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/global_error/global_error_service.h"
 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/view_ids.h"
 #include "chrome/browser/ui/views/autofill/save_card_icon_view.h"
 #include "chrome/browser/ui/views/extensions/extension_popup.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views/layout_constants.h"
 #include "chrome/browser/ui/views/location_bar/page_action_image_view.h"
 #include "chrome/browser/ui/views/location_bar/page_action_with_badge_view.h"
 #include "chrome/browser/ui/views/location_bar/star_view.h"
@@ -480,6 +480,8 @@
     const int element_padding = GetLayoutConstant(TOOLBAR_ELEMENT_PADDING);
     const int browser_actions_width =
         browser_actions_->GetPreferredSize().width();
+    const int right_padding =
+        GetLayoutConstant(TOOLBAR_LOCATION_BAR_RIGHT_PADDING);
     const int content_width =
         GetLayoutInsets(TOOLBAR).width() +
         back_->GetPreferredSize().width() + element_padding +
@@ -489,9 +491,7 @@
              ? element_padding + home_->GetPreferredSize().width()
              : 0) +
         GetLayoutConstant(TOOLBAR_STANDARD_SPACING) +
-        GetLayoutConstant(TOOLBAR_LOCATION_BAR_RIGHT_PADDING) +
-        browser_actions_width +
-        (browser_actions_width > 0 ? element_padding : 0) +
+        (browser_actions_width > 0 ? browser_actions_width : right_padding) +
         app_menu_button_->GetPreferredSize().width();
     size.Enlarge(content_width, 0);
   }
@@ -504,6 +504,8 @@
     const int element_padding = GetLayoutConstant(TOOLBAR_ELEMENT_PADDING);
     const int browser_actions_width =
         browser_actions_->GetMinimumSize().width();
+    const int right_padding =
+        GetLayoutConstant(TOOLBAR_LOCATION_BAR_RIGHT_PADDING);
     const int content_width =
         GetLayoutInsets(TOOLBAR).width() +
         back_->GetMinimumSize().width() + element_padding +
@@ -513,9 +515,7 @@
              ? element_padding + home_->GetMinimumSize().width()
              : 0) +
         GetLayoutConstant(TOOLBAR_STANDARD_SPACING) +
-        GetLayoutConstant(TOOLBAR_LOCATION_BAR_RIGHT_PADDING) +
-        browser_actions_width +
-        (browser_actions_width > 0 ? element_padding : 0) +
+        (browser_actions_width > 0 ? browser_actions_width : right_padding) +
         app_menu_button_->GetMinimumSize().width();
     size.Enlarge(content_width, 0);
   }
@@ -535,9 +535,9 @@
 
   // We assume all child elements except the location bar are the same height.
   // Set child_y such that buttons appear vertically centered.
-  int child_height =
+  const int child_height =
       std::min(back_->GetPreferredSize().height(), height());
-  int child_y = CenteredChildY(height(), child_height);
+  const int child_y = CenteredChildY(height(), child_height);
 
   // If the window is maximized, we extend the back button to the left so that
   // clicking on the left-most pixel will activate the back button.
@@ -546,8 +546,9 @@
   //                will be slightly the wrong size.  We should force a
   //                Layout() in this case.
   //                http://crbug.com/5540
-  bool maximized = browser_->window() && browser_->window()->IsMaximized();
-  int back_width = back_->GetPreferredSize().width();
+  const bool maximized =
+      browser_->window() && browser_->window()->IsMaximized();
+  const int back_width = back_->GetPreferredSize().width();
   const gfx::Insets insets(GetLayoutInsets(TOOLBAR));
   if (maximized) {
     back_->SetBounds(0, child_y, back_width + insets.left(), child_height);
@@ -580,36 +581,38 @@
   next_element_x =
       home_->bounds().right() + GetLayoutConstant(TOOLBAR_STANDARD_SPACING);
 
-  int browser_actions_desired_width =
-      browser_actions_->GetPreferredSize().width();
   int app_menu_width = app_menu_button_->GetPreferredSize().width();
-  const int location_bar_right_padding =
+  const int right_padding =
       GetLayoutConstant(TOOLBAR_LOCATION_BAR_RIGHT_PADDING);
 
+  // Note that the browser actions container has its own internal left and right
+  // padding to visually separate it from the location bar and app menu button.
+  // However if the container is empty we must account for the |right_padding|
+  // value used to visually separate the location bar and app menu button.
   int available_width = std::max(
-      0, width() - insets.right() - app_menu_width -
-             (browser_actions_desired_width > 0 ? element_padding : 0) -
-             location_bar_right_padding - next_element_x);
+      0,
+      width() - insets.right() - app_menu_width -
+      (browser_actions_->GetPreferredSize().IsEmpty() ? right_padding : 0) -
+      next_element_x);
   // Don't allow the omnibox to shrink to the point of non-existence, so
   // subtract its minimum width from the available width to reserve it.
-  int minimum_location_bar_width = location_bar_->GetMinimumSize().width();
-  int browser_actions_width = browser_actions_->GetWidthForMaxWidth(
-      available_width - minimum_location_bar_width);
+  const int browser_actions_width = browser_actions_->GetWidthForMaxWidth(
+      available_width - location_bar_->GetMinimumSize().width());
   available_width -= browser_actions_width;
-  int location_bar_width = available_width;
+  const int location_bar_width = available_width;
 
-  int location_height = location_bar_->GetPreferredSize().height();
-  int location_y = CenteredChildY(height(), location_height);
+  const int location_height = location_bar_->GetPreferredSize().height();
+  const int location_y = CenteredChildY(height(), location_height);
 
   location_bar_->SetBounds(next_element_x, location_y,
                            location_bar_width, location_height);
-  next_element_x = location_bar_->bounds().right() + location_bar_right_padding;
 
+  next_element_x = location_bar_->bounds().right();
   browser_actions_->SetBounds(
       next_element_x, child_y, browser_actions_width, child_height);
   next_element_x = browser_actions_->bounds().right();
-  if (browser_actions_width > 0)
-    next_element_x += element_padding;
+  if (!browser_actions_width)
+    next_element_x += right_padding;
 
   // The browser actions need to do a layout explicitly, because when an
   // extension is loaded/unloaded/changed, BrowserActionContainer removes and
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.h b/chrome/browser/ui/views/toolbar/toolbar_view.h
index 80eef0d7..edf6015 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.h
@@ -148,12 +148,6 @@
   const char* GetClassName() const override;
   bool AcceleratorPressed(const ui::Accelerator& acc) override;
 
-  enum {
-    // The apparent horizontal space between most items, and the vertical
-    // padding above and below them.
-    kStandardSpacing = 3,
-  };
-
  protected:
   // AccessiblePaneView:
   bool SetPaneFocusAndFocusDefault() override;
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 a67d885..d41dace 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -368,9 +368,10 @@
   LoadAuthExtension(true /* force */, false /* offline */);
 }
 
-void GaiaScreenHandler::HandleIdentifierEntered(
-    const std::string& account_identifier) {
-  if (!Delegate()->IsUserWhitelisted(account_identifier))
+void GaiaScreenHandler::HandleIdentifierEntered(const std::string& user_email) {
+  if (!Delegate()->IsUserWhitelisted(
+          user_manager::UserManager::Get()->GetKnownUserAccountId(
+              user_email, std::string() /* gaia_id */)))
     ShowWhitelistCheckFailedError();
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc
index 675b541..0054e2fd 100644
--- a/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc
@@ -32,6 +32,7 @@
 #include "chromeos/network/network_handler.h"
 #include "chromeos/network/network_state_handler.h"
 #include "components/login/localized_values_builder.h"
+#include "components/strings/grit/components_strings.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
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 903f88e..b1cb3c27 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -287,7 +287,7 @@
     max_mode_delegate_.reset(nullptr);
   }
   proximity_auth::ScreenlockBridge::Get()->SetLockHandler(nullptr);
-  proximity_auth::ScreenlockBridge::Get()->SetFocusedUser("");
+  proximity_auth::ScreenlockBridge::Get()->SetFocusedUser(EmptyAccountId());
 }
 
 // static
@@ -1223,8 +1223,7 @@
 void SigninScreenHandler::HandleFocusPod(const AccountId& account_id) {
   SetUserInputMethod(account_id.GetUserEmail(), ime_state_.get());
   WallpaperManager::Get()->SetUserWallpaperDelayed(account_id);
-  proximity_auth::ScreenlockBridge::Get()->SetFocusedUser(
-      account_id.GetUserEmail());
+  proximity_auth::ScreenlockBridge::Get()->SetFocusedUser(account_id);
   if (delegate_)
     delegate_->CheckUserStatus(account_id);
   if (!test_focus_pod_callback_.is_null())
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 484fe98..56112fc 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -189,7 +189,7 @@
   virtual void CheckUserStatus(const AccountId& account_id) = 0;
 
   // Returns true if user is allowed to log in by domain policy.
-  virtual bool IsUserWhitelisted(const std::string& user_id) = 0;
+  virtual bool IsUserWhitelisted(const AccountId& account_id) = 0;
 
  protected:
   virtual ~SigninScreenHandlerDelegate() {}
diff --git a/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc
index 286dba6..d9a85d9 100644
--- a/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc
@@ -398,8 +398,7 @@
   const AccountId manager_account_id = AccountId::FromUserEmailGaiaId(
       gaia::SanitizeEmail(manager_raw_account_id.GetUserEmail()),
       manager_raw_account_id.GetGaiaId());
-  delegate_->AuthenticateManager(manager_account_id.GetUserEmail(),
-                                 manager_password);
+  delegate_->AuthenticateManager(manager_account_id, manager_password);
 }
 
 // TODO(antrim) : this is an explicit code duplications with UserImageScreen.
diff --git a/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.h
index 3af31ea..7fcc42e 100644
--- a/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.h
@@ -32,7 +32,7 @@
 
     // Starts supervised user creation flow, with manager identified by
     // |manager_id| and |manager_password|.
-    virtual void AuthenticateManager(const std::string& manager_id,
+    virtual void AuthenticateManager(const AccountId& manager_account_id,
                                      const std::string& manager_password) = 0;
 
     // Starts supervised user creation flow, with supervised user that would
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui.cc b/chrome/browser/ui/webui/local_discovery/local_discovery_ui.cc
index eda0cdc..b676af7 100644
--- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui.cc
+++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui.cc
@@ -12,6 +12,7 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
diff --git a/chrome/browser/ui/webui/media_router/media_cast_mode.cc b/chrome/browser/ui/webui/media_router/media_cast_mode.cc
index b9cc136..f742fa7 100644
--- a/chrome/browser/ui/webui/media_router/media_cast_mode.cc
+++ b/chrome/browser/ui/webui/media_router/media_cast_mode.cc
@@ -31,16 +31,14 @@
 }
 
 bool IsValidCastModeNum(int cast_mode_num) {
-  return cast_mode_num >= MediaCastMode::DEFAULT &&
-         cast_mode_num < MediaCastMode::NUM_CAST_MODES;
-}
-
-MediaCastMode GetPreferredCastMode(const CastModeSet& cast_modes) {
-  if (cast_modes.empty()) {
-    LOG(ERROR) << "Called with empty cast_modes!";
-    return MediaCastMode::DEFAULT;
+  switch (cast_mode_num) {
+    case MediaCastMode::DEFAULT:
+    case MediaCastMode::TAB_MIRROR:
+    case MediaCastMode::DESKTOP_MIRROR:
+      return true;
+    default:
+      return false;
   }
-  return *cast_modes.begin();
 }
 
 }  // namespace media_router
diff --git a/chrome/browser/ui/webui/media_router/media_cast_mode.h b/chrome/browser/ui/webui/media_router/media_cast_mode.h
index 94630d2..6167c0f6 100644
--- a/chrome/browser/ui/webui/media_router/media_cast_mode.h
+++ b/chrome/browser/ui/webui/media_router/media_cast_mode.h
@@ -16,15 +16,13 @@
 enum MediaCastMode {
   // The default presentation for the WebContents.  Only available when the
   // document has provided a default presentation URL.
-  DEFAULT,
+  DEFAULT = 0x1,
   // Capture the rendered WebContents and stream it to a media sink.  Always
   // available.
-  TAB_MIRROR,
+  TAB_MIRROR = 0x2,
   // Capture the entire desktop and stream it to a media sink.  Always
   // available.
-  DESKTOP_MIRROR,
-  // The number of cast modes; not a valid cast mode.  Add new cast modes above.
-  NUM_CAST_MODES,
+  DESKTOP_MIRROR = 0x4,
 };
 
 using CastModeSet = std::set<MediaCastMode>;
@@ -37,10 +35,6 @@
 // Returns true if |cast_mode_num| is a valid MediaCastMode, false otherwise.
 bool IsValidCastModeNum(int cast_mode_num);
 
-// Returns the preferred cast mode from the current set of cast modes.
-// There must be at least one cast mode in |cast_modes|.
-MediaCastMode GetPreferredCastMode(const CastModeSet& cast_modes);
-
 }  // namespace media_router
 
 #endif  // CHROME_BROWSER_UI_WEBUI_MEDIA_ROUTER_MEDIA_CAST_MODE_H_
diff --git a/chrome/browser/ui/webui/media_router/media_cast_mode_unittest.cc b/chrome/browser/ui/webui/media_router/media_cast_mode_unittest.cc
index 6be1e85f..574cdad 100644
--- a/chrome/browser/ui/webui/media_router/media_cast_mode_unittest.cc
+++ b/chrome/browser/ui/webui/media_router/media_cast_mode_unittest.cc
@@ -12,47 +12,21 @@
 
 namespace media_router {
 
-TEST(MediaCastModeTest, PreferredCastMode) {
-  CastModeSet cast_modes;
-
-  EXPECT_EQ(MediaCastMode::DEFAULT, GetPreferredCastMode(cast_modes));
-
-  cast_modes.insert(MediaCastMode::DESKTOP_MIRROR);
-  EXPECT_EQ(MediaCastMode::DESKTOP_MIRROR,
-            GetPreferredCastMode(cast_modes));
-
-  cast_modes.insert(MediaCastMode::TAB_MIRROR);
-  EXPECT_EQ(MediaCastMode::TAB_MIRROR,
-            GetPreferredCastMode(cast_modes));
-
-  cast_modes.insert(MediaCastMode::DEFAULT);
-  EXPECT_EQ(MediaCastMode::DEFAULT,
-            GetPreferredCastMode(cast_modes));
-
-  cast_modes.erase(MediaCastMode::TAB_MIRROR);
-  EXPECT_EQ(MediaCastMode::DEFAULT,
-            GetPreferredCastMode(cast_modes));
-
-  cast_modes.erase(MediaCastMode::DESKTOP_MIRROR);
-  EXPECT_EQ(MediaCastMode::DEFAULT,
-            GetPreferredCastMode(cast_modes));
-}
-
 TEST(MediaCastModeTest, MediaCastModeToDescription) {
-  for (int cast_mode = MediaCastMode::DEFAULT;
-       cast_mode < MediaCastMode::NUM_CAST_MODES; cast_mode++) {
-    EXPECT_TRUE(!MediaCastModeToDescription(
-        static_cast<MediaCastMode>(cast_mode), "youtube.com").empty());
-  }
+  EXPECT_FALSE(MediaCastModeToDescription(MediaCastMode::DEFAULT, "youtube.com")
+                   .empty());
+  EXPECT_FALSE(
+      MediaCastModeToDescription(MediaCastMode::TAB_MIRROR, "").empty());
+  EXPECT_FALSE(
+      MediaCastModeToDescription(MediaCastMode::DESKTOP_MIRROR, "").empty());
 }
 
 TEST(MediaCastModeTest, IsValidCastModeNum) {
-  for (int cast_mode = MediaCastMode::DEFAULT;
-       cast_mode < MediaCastMode::NUM_CAST_MODES; cast_mode++) {
-    EXPECT_TRUE(IsValidCastModeNum(cast_mode));
-  }
-  EXPECT_FALSE(IsValidCastModeNum(MediaCastMode::NUM_CAST_MODES));
+  EXPECT_TRUE(IsValidCastModeNum(MediaCastMode::DEFAULT));
+  EXPECT_TRUE(IsValidCastModeNum(MediaCastMode::TAB_MIRROR));
+  EXPECT_TRUE(IsValidCastModeNum(MediaCastMode::DESKTOP_MIRROR));
   EXPECT_FALSE(IsValidCastModeNum(-1));
+  EXPECT_FALSE(IsValidCastModeNum(666));
 }
 
 }  // namespace media_router
diff --git a/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc b/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc
index 36a534fb..16a2ba2 100644
--- a/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc
@@ -278,10 +278,6 @@
   MediaRouterUI* media_router_ui = static_cast<MediaRouterUI*>(
       media_router_dialog->GetWebUI()->GetController());
   DCHECK(media_router_ui);
-  if (!media_router_ui) {
-    Reset();
-    return;
-  }
 
   scoped_ptr<CreatePresentationConnectionRequest> create_connection_request(
       TakeCreateConnectionRequest());
diff --git a/chrome/browser/ui/webui/media_router/media_router_localized_strings_provider.cc b/chrome/browser/ui/webui/media_router/media_router_localized_strings_provider.cc
index c6a109c7..ae504a3 100644
--- a/chrome/browser/ui/webui/media_router/media_router_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_localized_strings_provider.cc
@@ -34,6 +34,8 @@
 }
 
 void AddMediaRouterContainerStrings(content::WebUIDataSource* html_source) {
+  html_source->AddLocalizedString("autoCastMode",
+                                  IDS_MEDIA_ROUTER_AUTO_CAST_MODE);
   html_source->AddLocalizedString("deviceMissing",
                                   IDS_MEDIA_ROUTER_DEVICE_MISSING);
   html_source->AddLocalizedString("selectCastModeHeader",
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.cc b/chrome/browser/ui/webui/media_router/media_router_ui.cc
index 6fa422e..f535b4e 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.cc
@@ -4,12 +4,15 @@
 
 #include "chrome/browser/ui/webui/media_router/media_router_ui.h"
 
+#include <algorithm>
 #include <string>
 
 #include "base/guid.h"
+#include "base/i18n/string_compare.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/media/router/create_presentation_connection_request.h"
 #include "chrome/browser/media/router/issue.h"
 #include "chrome/browser/media/router/issues_observer.h"
@@ -36,6 +39,7 @@
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/constants.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "third_party/icu/source/i18n/unicode/coll.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/web_dialogs/web_dialog_delegate.h"
 
@@ -220,6 +224,17 @@
       router_,
       base::Bind(&MediaRouterUI::OnRoutesUpdated, base::Unretained(this))));
 
+  // Create |collator_| before |query_result_manager_| so that |collator_| is
+  // already set up when we get a callback from |query_result_manager_|.
+  UErrorCode error = U_ZERO_ERROR;
+  const std::string& locale = g_browser_process->GetApplicationLocale();
+  collator_.reset(
+      icu::Collator::createInstance(icu::Locale(locale.c_str()), error));
+  if (U_FAILURE(error)) {
+    DLOG(ERROR) << "Failed to create collator for locale " << locale;
+    collator_.reset();
+  }
+
   query_result_manager_.reset(new QueryResultManager(router_));
   query_result_manager_->AddObserver(this);
 
@@ -287,7 +302,8 @@
   // for now.
   MediaSource source = query_result_manager_->GetSourceForCastMode(cast_mode);
   if (source.Empty()) {
-    LOG(ERROR) << "No corresponding MediaSource for cast mode " << cast_mode;
+    LOG(ERROR) << "No corresponding MediaSource for cast mode "
+               << static_cast<int>(cast_mode);
     return false;
   }
 
@@ -362,6 +378,30 @@
 void MediaRouterUI::OnResultsUpdated(
     const std::vector<MediaSinkWithCastModes>& sinks) {
   sinks_ = sinks;
+
+  const icu::Collator* collator_ptr = collator_.get();
+  std::sort(
+      sinks_.begin(), sinks_.end(),
+      [collator_ptr](const MediaSinkWithCastModes& sink1,
+                     const MediaSinkWithCastModes& sink2) {
+        if (collator_ptr) {
+          base::string16 sink1_name = base::UTF8ToUTF16(sink1.sink.name());
+          base::string16 sink2_name = base::UTF8ToUTF16(sink2.sink.name());
+          UCollationResult result = base::i18n::CompareString16WithCollator(
+              *collator_ptr, sink1_name, sink2_name);
+          if (result != UCOL_EQUAL)
+            return result == UCOL_LESS;
+        } else {
+          // Fall back to simple string comparison if collator is not
+          // available.
+          int val = sink1.sink.name().compare(sink2.sink.name());
+          if (val)
+            return val < 0;
+        }
+
+        return sink1.sink.id() < sink2.sink.id();
+      });
+
   if (ui_initialized_) handler_->UpdateSinks(sinks_);
 }
 
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.h b/chrome/browser/ui/webui/media_router/media_router_ui.h
index 958b5bb7b..88f17cb4 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.h
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.h
@@ -22,14 +22,19 @@
 #include "chrome/browser/ui/webui/media_router/media_sink_with_cast_modes.h"
 #include "chrome/browser/ui/webui/media_router/query_result_manager.h"
 #include "content/public/browser/web_ui_data_source.h"
+#include "third_party/icu/source/common/unicode/uversion.h"
 
 namespace content {
 class WebContents;
-}  // namespace content
+}
 
 namespace extensions {
 class ExtensionRegistry;
-}  // namespace extensions
+}
+
+namespace U_ICU_NAMESPACE {
+class Collator;
+}
 
 namespace media_router {
 
@@ -122,6 +127,7 @@
   virtual const std::string& GetRouteProviderExtensionId() const;
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest, SortedSinks);
   FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest,
                            UIMediaRoutesObserverFiltersNonDisplayRoutes);
   FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest, GetExtensionNameExtensionPresent);
@@ -212,6 +218,10 @@
   // |current_route_request_id_| when there is a new route request.
   int route_request_counter_;
 
+  // Used for locale-aware sorting of sinks by name. Set during |InitCommon()|
+  // using the current locale. Set to null
+  scoped_ptr<icu::Collator> collator_;
+
   std::vector<MediaSinkWithCastModes> sinks_;
   std::vector<MediaRoute> routes_;
   CastModeSet cast_modes_;
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui_unittest.cc b/chrome/browser/ui/webui/media_router/media_router_ui_unittest.cc
index 3b4ff917..768db1f 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui_unittest.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_ui_unittest.cc
@@ -6,6 +6,9 @@
 #include "chrome/browser/media/router/media_route.h"
 #include "chrome/browser/media/router/mock_media_router.h"
 #include "chrome/browser/ui/webui/media_router/media_router_ui.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_web_ui.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_builder.h"
@@ -19,21 +22,66 @@
 
 namespace media_router {
 
-class MediaRouterUITest : public ::testing::Test {
+class MockRoutesUpdatedCallback {
  public:
-  MediaRouterUITest() {}
-  ~MediaRouterUITest() override {}
-
   MOCK_METHOD1(OnRoutesUpdated, void(const std::vector<MediaRoute>& routes));
 };
 
+class MediaRouterUITest : public ::testing::Test {
+ public:
+  MediaRouterUITest() {
+    web_contents_.reset(content::WebContents::Create(
+        content::WebContents::CreateParams(&profile_)));
+    web_ui_.set_web_contents(web_contents_.get());
+    media_router_ui_.reset(new MediaRouterUI(&web_ui_));
+  }
+
+  ~MediaRouterUITest() override = default;
+
+ protected:
+  content::TestBrowserThreadBundle thread_bundle_;
+  TestingProfile profile_;
+  content::TestWebUI web_ui_;
+  scoped_ptr<content::WebContents> web_contents_;
+  scoped_ptr<MediaRouterUI> media_router_ui_;
+};
+
+TEST_F(MediaRouterUITest, SortedSinks) {
+  std::vector<MediaSinkWithCastModes> unsorted_sinks;
+  std::string sink_id1("sink3");
+  std::string sink_name1("B sink");
+  MediaSinkWithCastModes sink1(
+      MediaSink(sink_id1, sink_name1, MediaSink::IconType::CAST));
+  unsorted_sinks.push_back(sink1);
+
+  std::string sink_id2("sink1");
+  std::string sink_name2("A sink");
+  MediaSinkWithCastModes sink2(
+      MediaSink(sink_id2, sink_name2, MediaSink::IconType::CAST));
+  unsorted_sinks.push_back(sink2);
+
+  std::string sink_id3("sink2");
+  std::string sink_name3("B sink");
+  MediaSinkWithCastModes sink3(
+      MediaSink(sink_id3, sink_name3, MediaSink::IconType::CAST));
+  unsorted_sinks.push_back(sink3);
+
+  // Sorted order is 2, 3, 1.
+  media_router_ui_->OnResultsUpdated(unsorted_sinks);
+  const auto& sorted_sinks = media_router_ui_->sinks_;
+  EXPECT_EQ(sink_name2, sorted_sinks[0].sink.name());
+  EXPECT_EQ(sink_id3, sorted_sinks[1].sink.id());
+  EXPECT_EQ(sink_id1, sorted_sinks[2].sink.id());
+}
+
 TEST_F(MediaRouterUITest, UIMediaRoutesObserverFiltersNonDisplayRoutes) {
   MockMediaRouter mock_router;
   EXPECT_CALL(mock_router, RegisterMediaRoutesObserver(_)).Times(1);
+  MockRoutesUpdatedCallback mock_callback;
   scoped_ptr<MediaRouterUI::UIMediaRoutesObserver> observer(
       new MediaRouterUI::UIMediaRoutesObserver(
-          &mock_router, base::Bind(&MediaRouterUITest::OnRoutesUpdated,
-                                   base::Unretained(this))));
+          &mock_router, base::Bind(&MockRoutesUpdatedCallback::OnRoutesUpdated,
+                                   base::Unretained(&mock_callback))));
 
   MediaRoute display_route_1("routeId1", MediaSource("mediaSource"), "sinkId1",
                              "desc 1", true, "", true);
@@ -47,7 +95,8 @@
   routes.push_back(display_route_2);
 
   std::vector<MediaRoute> filtered_routes;
-  EXPECT_CALL(*this, OnRoutesUpdated(_)).WillOnce(SaveArg<0>(&filtered_routes));
+  EXPECT_CALL(mock_callback, OnRoutesUpdated(_))
+      .WillOnce(SaveArg<0>(&filtered_routes));
   observer->OnRoutesUpdated(routes);
 
   ASSERT_EQ(2u, filtered_routes.size());
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 ce1da635..baeea3da 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
@@ -56,11 +56,11 @@
     if (!sink.description().empty())
       sink_val->SetString("description", sink.description());
 
-    scoped_ptr<base::ListValue> cast_modes_val(new base::ListValue);
+    int cast_mode_bits = 0;
     for (MediaCastMode cast_mode : sink_with_cast_modes.cast_modes)
-      cast_modes_val->AppendInteger(cast_mode);
+      cast_mode_bits |= cast_mode;
 
-    sink_val->Set("castModes", cast_modes_val.Pass());
+    sink_val->SetInteger("castModes", cast_mode_bits);
     value->Append(sink_val.release());
   }
 
@@ -279,10 +279,6 @@
       CastModesToValue(cast_modes,
                        media_router_ui_->GetPresentationRequestSourceName()));
   initial_data.Set("castModes", cast_modes_list.release());
-  if (!cast_modes.empty()) {
-    initial_data.SetInteger("initialCastModeType",
-                            GetPreferredCastMode(cast_modes));
-  }
 
   web_ui()->CallJavascriptFunction(kSetInitialData, initial_data);
   media_router_ui_->UIInitialized();
@@ -308,6 +304,7 @@
   }
 
   if (!IsValidCastModeNum(cast_mode_num)) {
+    // TODO(imcheng): Record error condition with UMA.
     DVLOG(1) << "Invalid cast mode: " << cast_mode_num << ". Aborting.";
     return;
   }
diff --git a/chrome/browser/ui/webui/media_router/media_router_webui_message_handler_unittest.cc b/chrome/browser/ui/webui/media_router/media_router_webui_message_handler_unittest.cc
index d3873ed..487e4d83 100644
--- a/chrome/browser/ui/webui/media_router/media_router_webui_message_handler_unittest.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_webui_message_handler_unittest.cc
@@ -97,9 +97,9 @@
   EXPECT_EQ("media_router.ui.setSinkList", call_data.function_name());
   const base::Value* arg1 = call_data.arg1();
   const base::ListValue* sinks_list_value = nullptr;
-  EXPECT_TRUE(arg1->GetAsList(&sinks_list_value));
+  ASSERT_TRUE(arg1->GetAsList(&sinks_list_value));
   const base::DictionaryValue* sink_value = nullptr;
-  EXPECT_TRUE(sinks_list_value->GetDictionary(0, &sink_value));
+  ASSERT_TRUE(sinks_list_value->GetDictionary(0, &sink_value));
 
   std::string value;
   EXPECT_TRUE(sink_value->GetString("id", &value));
@@ -108,11 +108,9 @@
   EXPECT_TRUE(sink_value->GetString("name", &value));
   EXPECT_EQ(sink_name, value);
 
-  const base::ListValue* cast_modes_value = nullptr;
-  EXPECT_TRUE(sink_value->GetList("castModes", &cast_modes_value));
-  int cast_mode = -1;
-  EXPECT_TRUE(cast_modes_value->GetInteger(0, &cast_mode));
-  EXPECT_EQ(static_cast<int>(MediaCastMode::TAB_MIRROR), cast_mode);
+  int cast_mode_bits = -1;
+  ASSERT_TRUE(sink_value->GetInteger("castModes", &cast_mode_bits));
+  EXPECT_EQ(static_cast<int>(MediaCastMode::TAB_MIRROR), cast_mode_bits);
 }
 
 TEST_F(MediaRouterWebUIMessageHandlerTest, UpdateRoutes) {
@@ -134,9 +132,9 @@
   EXPECT_EQ("media_router.ui.setRouteList", call_data.function_name());
   const base::Value* arg1 = call_data.arg1();
   const base::ListValue* routes_list_value = nullptr;
-  EXPECT_TRUE(arg1->GetAsList(&routes_list_value));
+  ASSERT_TRUE(arg1->GetAsList(&routes_list_value));
   const base::DictionaryValue* route_value = nullptr;
-  EXPECT_TRUE(routes_list_value->GetDictionary(0, &route_value));
+  ASSERT_TRUE(routes_list_value->GetDictionary(0, &route_value));
 
   std::string value;
   EXPECT_TRUE(route_value->GetString("id", &value));
@@ -178,12 +176,12 @@
             call_data.function_name());
   const base::Value* arg1 = call_data.arg1();
   const base::StringValue* sink_id_value = nullptr;
-  EXPECT_TRUE(arg1->GetAsString(&sink_id_value));
+  ASSERT_TRUE(arg1->GetAsString(&sink_id_value));
   EXPECT_EQ(sink_id, sink_id_value->GetString());
 
   const base::Value* arg2 = call_data.arg2();
   const base::DictionaryValue* route_value = nullptr;
-  EXPECT_TRUE(arg2->GetAsDictionary(&route_value));
+  ASSERT_TRUE(arg2->GetAsDictionary(&route_value));
 
   std::string value;
   EXPECT_TRUE(route_value->GetString("id", &value));
@@ -216,7 +214,7 @@
   EXPECT_EQ("media_router.ui.setIssue", call_data.function_name());
   const base::Value* arg1 = call_data.arg1();
   const base::DictionaryValue* issue_value = nullptr;
-  EXPECT_TRUE(arg1->GetAsDictionary(&issue_value));
+  ASSERT_TRUE(arg1->GetAsDictionary(&issue_value));
 
   std::string value;
   EXPECT_TRUE(issue_value->GetString("id", &value));
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
index 8444e47..852a7b0 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
@@ -25,8 +25,8 @@
 #include "chrome/browser/ui/webui/net_internals/net_internals_ui.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
 #include "components/net_log/chrome_net_log.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
@@ -316,7 +316,7 @@
   bool enable;
   ASSERT_TRUE(list_value->GetBoolean(0, &enable));
   browser()->profile()->GetPrefs()->SetBoolean(
-      data_reduction_proxy::prefs::kDataReductionProxyEnabled, enable);
+      prefs::kDataSaverEnabled, enable);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/webui/ntp/ntp_user_data_logger.h b/chrome/browser/ui/webui/ntp/ntp_user_data_logger.h
index a1c749a9..af3c6f8 100644
--- a/chrome/browser/ui/webui/ntp/ntp_user_data_logger.h
+++ b/chrome/browser/ui/webui/ntp/ntp_user_data_logger.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/gtest_prod_util.h"
 #include "base/strings/string16.h"
 #include "base/time/time.h"
 #include "chrome/common/ntp_logging_events.h"
@@ -63,6 +64,11 @@
  private:
   friend class content::WebContentsUserData<NTPUserDataLogger>;
 
+  FRIEND_TEST_ALL_PREFIXES(SearchTabHelperTest,
+                           OnMostVisitedItemsChangedFromServer);
+  FRIEND_TEST_ALL_PREFIXES(SearchTabHelperTest,
+                           OnMostVisitedItemsChangedFromClient);
+
   // True if at least one iframe came from a server-side suggestion.
   bool has_server_side_suggestions_;
 
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index bfcc9144..b93c86c5 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -80,6 +80,7 @@
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/signin/core/common/profile_management_switches.h"
 #include "components/signin/core/common/signin_pref_names.h"
+#include "components/strings/grit/components_strings.h"
 #include "components/ui/zoom/page_zoom.h"
 #include "components/user_manager/user_type.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/ui/webui/options/options_ui.cc b/chrome/browser/ui/webui/options/options_ui.cc
index 56e784c2..1ec0ded 100644
--- a/chrome/browser/ui/webui/options/options_ui.cc
+++ b/chrome/browser/ui/webui/options/options_ui.cc
@@ -53,6 +53,7 @@
 #include "chrome/grit/locale_settings.h"
 #include "components/omnibox/browser/autocomplete_match.h"
 #include "components/omnibox/browser/autocomplete_result.h"
+#include "components/strings/grit/components_strings.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/url_data_source.h"
diff --git a/chrome/browser/ui/webui/options/options_ui_browsertest.cc b/chrome/browser/ui/webui/options/options_ui_browsertest.cc
index 2287d97..71db625 100644
--- a/chrome/browser/ui/webui/options/options_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/options/options_ui_browsertest.cc
@@ -21,6 +21,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/signin/core/browser/account_tracker_service.h"
 #include "components/signin/core/browser/signin_manager.h"
+#include "components/strings/grit/components_strings.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/webui/options/reset_profile_settings_handler.cc b/chrome/browser/ui/webui/options/reset_profile_settings_handler.cc
index 9f77a9a..98143dd 100644
--- a/chrome/browser/ui/webui/options/reset_profile_settings_handler.cc
+++ b/chrome/browser/ui/webui/options/reset_profile_settings_handler.cc
@@ -19,6 +19,7 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/strings/grit/components_strings.h"
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_ui.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc b/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc
index 99035ac..91433b68 100644
--- a/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc
+++ b/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/options/sync_setup_handler.h"
 
+#include <string>
 #include <vector>
 
 #include "base/command_line.h"
@@ -16,7 +17,7 @@
 #include "chrome/browser/signin/signin_error_controller_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/browser/sync/profile_sync_test_util.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
 #include "chrome/common/chrome_switches.h"
@@ -195,13 +196,10 @@
 
     mock_pss_ = static_cast<ProfileSyncServiceMock*>(
         ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-            profile_.get(),
-            ProfileSyncServiceMock::BuildMockProfileSyncService));
+            profile_.get(), BuildMockProfileSyncService));
     EXPECT_CALL(*mock_pss_, GetAuthError()).WillRepeatedly(ReturnRef(error_));
     ON_CALL(*mock_pss_, GetPassphraseType()).WillByDefault(
         Return(syncer::IMPLICIT_PASSPHRASE));
-    ON_CALL(*mock_pss_, GetPassphraseTime()).WillByDefault(
-        Return(base::Time()));
     ON_CALL(*mock_pss_, GetExplicitPassphraseTime()).WillByDefault(
         Return(base::Time()));
     ON_CALL(*mock_pss_, GetRegisteredDataTypes())
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index a57567de7..252f0efd2 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -1222,7 +1222,10 @@
   UErrorCode errorCode = U_ZERO_ERROR;
   const char* locale = g_browser_process->GetApplicationLocale().c_str();
   UMeasurementSystem system = ulocdata_getMeasurementSystem(locale, &errorCode);
-  if (errorCode > U_ZERO_ERROR || system == UMS_LIMIT)
+  // On error, assume the units are SI.
+  // Since the only measurement units print preview's WebUI cares about are
+  // those for measuring distance, assume anything non-US is SI.
+  if (errorCode > U_ZERO_ERROR || system != UMS_US)
     system = UMS_SI;
 
   // Getting the number formatting based on the locale and writing to
diff --git a/chrome/browser/ui/webui/settings/sync_handler.cc b/chrome/browser/ui/webui/settings/sync_handler.cc
index b60851a..f25724b 100644
--- a/chrome/browser/ui/webui/settings/sync_handler.cc
+++ b/chrome/browser/ui/webui/settings/sync_handler.cc
@@ -15,8 +15,10 @@
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
 #include "base/values.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_avatar_icon_util.h"
 #include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/browser/profiles/profile_window.h"
@@ -48,7 +50,9 @@
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "net/base/url_util.h"
+#include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/webui/web_ui_util.h"
 
 #if defined(OS_CHROMEOS)
 #include "components/signin/core/browser/signin_manager_base.h"
@@ -766,6 +770,23 @@
   sync_status->SetBoolean("hasUnrecoverableError",
                           service && service->HasUnrecoverableError());
 
+  ProfileInfoCache& cache =
+      g_browser_process->profile_manager()->GetProfileInfoCache();
+  ProfileAttributesEntry* entry = nullptr;
+  if (cache.GetProfileAttributesWithPath(profile_->GetPath(), &entry)) {
+    sync_status->SetString("name", entry->GetName());
+
+    if (entry->IsUsingGAIAPicture() && entry->GetGAIAPicture()) {
+      gfx::Image icon =
+          profiles::GetAvatarIconForWebUI(entry->GetAvatarIcon(), true);
+      sync_status->SetString("iconURL",
+                             webui::GetBitmapDataUrl(icon.AsBitmap()));
+    } else {
+      sync_status->SetString("iconURL", profiles::GetDefaultAvatarIconUrl(
+                                            entry->GetAvatarIconIndex()));
+    }
+  }
+
   return sync_status.Pass();
 }
 
diff --git a/chrome/browser/ui/webui/settings/sync_handler_unittest.cc b/chrome/browser/ui/webui/settings/sync_handler_unittest.cc
index 80d09aac..9d34786 100644
--- a/chrome/browser/ui/webui/settings/sync_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/sync_handler_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/settings/sync_handler.h"
 
+#include <string>
 #include <vector>
 
 #include "base/command_line.h"
@@ -16,7 +17,7 @@
 #include "chrome/browser/signin/signin_error_controller_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/browser/sync/profile_sync_test_util.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
 #include "chrome/common/chrome_switches.h"
@@ -196,13 +197,10 @@
 
     mock_pss_ = static_cast<ProfileSyncServiceMock*>(
         ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-            profile_.get(),
-            ProfileSyncServiceMock::BuildMockProfileSyncService));
+            profile_.get(), BuildMockProfileSyncService));
     EXPECT_CALL(*mock_pss_, GetAuthError()).WillRepeatedly(ReturnRef(error_));
     ON_CALL(*mock_pss_, GetPassphraseType()).WillByDefault(
         Return(syncer::IMPLICIT_PASSPHRASE));
-    ON_CALL(*mock_pss_, GetPassphraseTime()).WillByDefault(
-        Return(base::Time()));
     ON_CALL(*mock_pss_, GetExplicitPassphraseTime()).WillByDefault(
         Return(base::Time()));
     ON_CALL(*mock_pss_, GetRegisteredDataTypes())
diff --git a/chrome/browser/ui/webui/signin/login_ui_service.cc b/chrome/browser/ui/webui/signin/login_ui_service.cc
index 115396b..0fcc5d3 100644
--- a/chrome/browser/ui/webui/signin/login_ui_service.cc
+++ b/chrome/browser/ui/webui/signin/login_ui_service.cc
@@ -11,16 +11,11 @@
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
-#include "chrome/browser/ui/sync/inline_login_dialog.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
 #include "chrome/common/url_constants.h"
 #include "components/signin/core/browser/signin_header_helper.h"
 #include "components/signin/core/common/profile_management_switches.h"
 
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/app_mode/app_mode_utils.h"
-#endif
-
 LoginUIService::LoginUIService(Profile* profile)
     : ui_(NULL), profile_(profile) {
 }
@@ -62,8 +57,7 @@
 
 void LoginUIService::ShowLoginPopup() {
 #if defined(OS_CHROMEOS)
-  if (chrome::IsRunningInForcedAppMode())
-    InlineLoginDialog::Show(profile_);
+  NOTREACHED();
 #else
   chrome::ScopedTabbedBrowserDisplayer displayer(
       profile_, chrome::GetActiveDesktop());
diff --git a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
index 3fc1e82..66c7d21 100644
--- a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
+++ b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
@@ -39,6 +39,7 @@
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/proximity_auth/screenlock_bridge.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
@@ -313,7 +314,7 @@
 }
 
 void UserManagerScreenHandler::ShowUserPodCustomIcon(
-    const std::string& user_email,
+    const AccountId& account_id,
     const proximity_auth::ScreenlockBridge::UserPodCustomIconOptions&
         icon_options) {
   scoped_ptr<base::DictionaryValue> icon = icon_options.ToDictionaryValue();
@@ -321,15 +322,14 @@
     return;
   web_ui()->CallJavascriptFunction(
       "login.AccountPickerScreen.showUserPodCustomIcon",
-      base::StringValue(user_email),
-      *icon);
+      base::StringValue(account_id.GetUserEmail()), *icon);
 }
 
 void UserManagerScreenHandler::HideUserPodCustomIcon(
-    const std::string& user_email) {
+    const AccountId& account_id) {
   web_ui()->CallJavascriptFunction(
       "login.AccountPickerScreen.hideUserPodCustomIcon",
-      base::StringValue(user_email));
+      base::StringValue(account_id.GetUserEmail()));
 }
 
 void UserManagerScreenHandler::EnableInput() {
@@ -337,24 +337,23 @@
 }
 
 void UserManagerScreenHandler::SetAuthType(
-    const std::string& user_email,
+    const AccountId& account_id,
     proximity_auth::ScreenlockBridge::LockHandler::AuthType auth_type,
     const base::string16& auth_value) {
-  if (GetAuthType(user_email) ==
+  if (GetAuthType(account_id) ==
       proximity_auth::ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD)
     return;
 
-  user_auth_type_map_[user_email] = auth_type;
-  web_ui()->CallJavascriptFunction(
-      "login.AccountPickerScreen.setAuthType",
-      base::StringValue(user_email),
-      base::FundamentalValue(auth_type),
-      base::StringValue(auth_value));
+  user_auth_type_map_[account_id.GetUserEmail()] = auth_type;
+  web_ui()->CallJavascriptFunction("login.AccountPickerScreen.setAuthType",
+                                   base::StringValue(account_id.GetUserEmail()),
+                                   base::FundamentalValue(auth_type),
+                                   base::StringValue(auth_value));
 }
 
 proximity_auth::ScreenlockBridge::LockHandler::AuthType
-UserManagerScreenHandler::GetAuthType(const std::string& user_email) const {
-  UserAuthTypeMap::const_iterator it = user_auth_type_map_.find(user_email);
+UserManagerScreenHandler::GetAuthType(const AccountId& account_id) const {
+  const auto it = user_auth_type_map_.find(account_id.GetUserEmail());
   if (it == user_auth_type_map_.end())
     return proximity_auth::ScreenlockBridge::LockHandler::OFFLINE_PASSWORD;
   return it->second;
@@ -365,20 +364,18 @@
   return proximity_auth::ScreenlockBridge::LockHandler::LOCK_SCREEN;
 }
 
-void UserManagerScreenHandler::Unlock(const std::string& user_email) {
-  base::FilePath path =
-      profiles::GetPathOfProfileWithEmail(g_browser_process->profile_manager(),
-                                          user_email);
+void UserManagerScreenHandler::Unlock(const AccountId& account_id) {
+  const base::FilePath path = profiles::GetPathOfProfileWithEmail(
+      g_browser_process->profile_manager(), account_id.GetUserEmail());
   if (!path.empty()) {
     authenticating_profile_path_ = path;
     ReportAuthenticationResult(true, ProfileMetrics::AUTH_LOCAL);
   }
 }
 
-void UserManagerScreenHandler::AttemptEasySignin(
-    const std::string& user_email,
-    const std::string& secret,
-    const std::string& key_label) {
+void UserManagerScreenHandler::AttemptEasySignin(const AccountId& account_id,
+                                                 const std::string& secret,
+                                                 const std::string& key_label) {
   NOTREACHED();
 }
 
@@ -550,18 +547,20 @@
     const base::ListValue* args) {
   std::string email;
   CHECK(args->GetString(0, &email));
-  GetScreenlockRouter(email)->OnAuthAttempted(GetAuthType(email), "");
+  GetScreenlockRouter(email)
+      ->OnAuthAttempted(GetAuthType(AccountId::FromUserEmail(email)), "");
 }
 
 void UserManagerScreenHandler::HandleHardlockUserPod(
     const base::ListValue* args) {
   std::string email;
   CHECK(args->GetString(0, &email));
+  const AccountId account_id = AccountId::FromUserEmail(email);
   SetAuthType(
-      email,
+      account_id,
       proximity_auth::ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD,
       base::string16());
-  HideUserPodCustomIcon(email);
+  HideUserPodCustomIcon(account_id);
 }
 
 void UserManagerScreenHandler::HandleRemoveUserWarningLoadStats(
diff --git a/chrome/browser/ui/webui/signin/user_manager_screen_handler.h b/chrome/browser/ui/webui/signin/user_manager_screen_handler.h
index 9d87349..b26d916d 100644
--- a/chrome/browser/ui/webui/signin/user_manager_screen_handler.h
+++ b/chrome/browser/ui/webui/signin/user_manager_screen_handler.h
@@ -23,6 +23,7 @@
 #include "content/public/browser/web_ui_message_handler.h"
 #include "google_apis/gaia/gaia_oauth_client.h"
 
+class AccountId;
 class GaiaAuthFetcher;
 
 namespace base {
@@ -40,11 +41,16 @@
   UserManagerScreenHandler();
   ~UserManagerScreenHandler() override;
 
+  void GetLocalizedValues(base::DictionaryValue* localized_strings);
+
+ private:
+  // An observer for any changes to Profiles in the ProfileInfoCache so that
+  // all the visible user manager screens can be updated.
+  class ProfileUpdateObserver;
+
   // WebUIMessageHandler implementation.
   void RegisterMessages() override;
 
-  void GetLocalizedValues(base::DictionaryValue* localized_strings);
-
   // content::NotificationObserver implementation:
   void Observe(int type,
                const content::NotificationSource& source,
@@ -53,27 +59,22 @@
   // proximity_auth::ScreenlockBridge::LockHandler implementation.
   void ShowBannerMessage(const base::string16& message) override;
   void ShowUserPodCustomIcon(
-      const std::string& user_email,
+      const AccountId& account_id,
       const proximity_auth::ScreenlockBridge::UserPodCustomIconOptions&
           icon_options) override;
-  void HideUserPodCustomIcon(const std::string& user_email) override;
+  void HideUserPodCustomIcon(const AccountId& account_id) override;
   void EnableInput() override;
   void SetAuthType(
-      const std::string& user_email,
+      const AccountId& account_id,
       proximity_auth::ScreenlockBridge::LockHandler::AuthType auth_type,
       const base::string16& auth_value) override;
-  AuthType GetAuthType(const std::string& user_email) const override;
+  AuthType GetAuthType(const AccountId& account_id) const override;
   ScreenType GetScreenType() const override;
-  void Unlock(const std::string& user_email) override;
-  void AttemptEasySignin(const std::string& user_email,
+  void Unlock(const AccountId& account_id) override;
+  void AttemptEasySignin(const AccountId& account_id,
                          const std::string& secret,
                          const std::string& key_label) override;
 
- private:
-  // An observer for any changes to Profiles in the ProfileInfoCache so that
-  // all the visible user manager screens can be updated.
-  class ProfileUpdateObserver;
-
   void HandleInitialize(const base::ListValue* args);
   void HandleAddUser(const base::ListValue* args);
   void HandleAuthenticatedLaunchUser(const base::ListValue* args);
diff --git a/chrome/browser/ui/webui/uber/uber_ui.cc b/chrome/browser/ui/webui/uber/uber_ui.cc
index a90fa966..80fed92 100644
--- a/chrome/browser/ui/webui/uber/uber_ui.cc
+++ b/chrome/browser/ui/webui/uber/uber_ui.cc
@@ -15,6 +15,7 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/strings/grit/components_strings.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
diff --git a/chrome/browser/ui/webui/uber/uber_ui_browsertest.cc b/chrome/browser/ui/webui/uber/uber_ui_browsertest.cc
index 12d065c6..05c2e1a 100644
--- a/chrome/browser/ui/webui/uber/uber_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/uber/uber_ui_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <string>
+#include <utility>
 
 #include "base/command_line.h"
 #include "base/macros.h"
@@ -63,12 +64,13 @@
 
   scoped_refptr<const extensions::Extension> extension =
       extensions::ExtensionBuilder()
-          .SetManifest(extensions::DictionaryBuilder()
-                           .Set("name", "History Override")
-                           .Set("version", "1")
-                           .Set("manifest_version", 2)
-                           .Set("permission",
-                                extensions::ListBuilder().Append("history")))
+          .SetManifest(
+              extensions::DictionaryBuilder()
+                  .Set("name", "History Override")
+                  .Set("version", "1")
+                  .Set("manifest_version", 2)
+                  .Set("permission",
+                       std::move(extensions::ListBuilder().Append("history"))))
           .Build();
 
   ExtensionService* service = extensions::ExtensionSystem::Get(
diff --git a/chrome/browser_tests.isolate b/chrome/browser_tests.isolate
index d90c90aa..4b6e6c3 100644
--- a/chrome/browser_tests.isolate
+++ b/chrome/browser_tests.isolate
@@ -65,6 +65,7 @@
           '../ppapi/tests/test_page.css.mock-http-headers',
           '../testing/test_env.py',
           '../third_party/accessibility-audit/axs_testing.js',
+          '../third_party/chaijs/chai.js',
           '../third_party/mocha/mocha.js',
           '../third_party/pyftpdlib/',
           '../third_party/pywebsocket/',
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index 2e8333b..7a790eb 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -21,6 +21,8 @@
       'browser/extensions/api/file_system/request_file_system_notification.h',
       'browser/extensions/api/input_ime/input_ime_api.cc',
       'browser/extensions/api/input_ime/input_ime_api.h',
+      'browser/extensions/api/input_ime/input_ime_api_chromeos.cc',
+      'browser/extensions/api/input_ime/input_ime_api_chromeos.h',
       'browser/extensions/api/log_private/filter_handler.cc',
       'browser/extensions/api/log_private/filter_handler.h',
       'browser/extensions/api/log_private/log_parser.cc',
@@ -93,10 +95,6 @@
       'browser/apps/app_url_redirector.h',
       'browser/apps/app_window_registry_util.cc',
       'browser/apps/app_window_registry_util.h',
-      'browser/apps/ephemeral_app_service.cc',
-      'browser/apps/ephemeral_app_service.h',
-      'browser/apps/ephemeral_app_service_factory.cc',
-      'browser/apps/ephemeral_app_service_factory.h',
       'browser/apps/install_chrome_app.cc',
       'browser/apps/install_chrome_app.h',
       'browser/apps/per_app_settings_service.cc',
@@ -1128,6 +1126,13 @@
             'browser/extensions/display_info_provider_aura.h',
           ],
         }],
+        ['OS=="win" or OS=="linux"', {
+          'sources': [
+            'browser/extensions/api/input_ime/input_ime_api.cc',
+            'browser/extensions/api/input_ime/input_ime_api.h',
+            'browser/extensions/api/input_ime/input_ime_api_nonchromeos.cc',
+          ],
+        }],
         ['enable_app_list==1', {
           'sources': [
             '<@(chrome_browser_extensions_app_list_sources)',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 4fda529..82da044 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -57,7 +57,6 @@
       'browser/ui/bookmarks/bookmark_bar.h',
       'browser/ui/bookmarks/bookmark_bar_constants.h',
       'browser/ui/bookmarks/bookmark_bar_instructions_delegate.h',
-      'browser/ui/bookmarks/bookmark_bubble_delegate.h',
       'browser/ui/bookmarks/bookmark_bubble_observer.h',
       'browser/ui/bookmarks/bookmark_editor.cc',
       'browser/ui/bookmarks/bookmark_editor.h',
@@ -107,11 +106,17 @@
       'browser/ui/passwords/account_chooser_more_combobox_model.h',
       'browser/ui/passwords/manage_passwords_state.cc',
       'browser/ui/passwords/manage_passwords_state.h',
+      'browser/ui/passwords/manage_passwords_ui_controller.cc',
+      'browser/ui/passwords/manage_passwords_ui_controller.h',
       'browser/ui/passwords/manage_passwords_view_utils.cc',
       'browser/ui/passwords/manage_passwords_view_utils.h',
       'browser/ui/passwords/password_manager_presenter.cc',
       'browser/ui/passwords/password_manager_presenter.h',
       'browser/ui/passwords/password_ui_view.h',
+      'browser/ui/passwords/passwords_client_ui_delegate.cc',
+      'browser/ui/passwords/passwords_client_ui_delegate.h',
+      'browser/ui/passwords/passwords_model_delegate.cc',
+      'browser/ui/passwords/passwords_model_delegate.h',
       'browser/ui/platform_keys_certificate_selector_chromeos.h',
       'browser/ui/prefs/prefs_tab_helper.cc',
       'browser/ui/prefs/prefs_tab_helper.h',
@@ -157,6 +162,7 @@
       'browser/ui/simple_message_box_internal.cc',
       'browser/ui/simple_message_box_internal.h',
       'browser/ui/status_bubble.h',
+      'browser/ui/sync/bubble_sync_promo_delegate.h',
       'browser/ui/sync/profile_signin_confirmation_helper.cc',
       'browser/ui/sync/profile_signin_confirmation_helper.h',
       'browser/ui/sync/tab_contents_synced_tab_delegate.cc',
@@ -617,6 +623,8 @@
       'browser/ui/ash/vpn_delegate_chromeos.h',
       'browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc',
       'browser/ui/views/ash/chrome_browser_main_extra_parts_ash.h',
+      'browser/ui/views/ash/tab_scrubber.cc',
+      'browser/ui/views/ash/tab_scrubber.h',
       'browser/ui/views/touch_uma/touch_uma_ash.cc',
       'browser/ui/window_sizer/window_sizer_ash.cc',
     ],
@@ -638,10 +646,8 @@
       'browser/ui/views/frame/browser_header_painter_ash.h',
       'browser/ui/views/frame/browser_non_client_frame_view_ash.cc',
       'browser/ui/views/frame/browser_non_client_frame_view_ash.h',
-      'browser/ui/views/frame/browser_non_client_frame_view_factory_ash.cc',
       'browser/ui/views/frame/immersive_mode_controller_ash.cc',
       'browser/ui/views/frame/immersive_mode_controller_ash.h',
-      'browser/ui/views/frame/immersive_mode_controller_factory_ash.cc',
       'browser/ui/views/frame/web_app_left_header_view_ash.cc',
       'browser/ui/views/frame/web_app_left_header_view_ash.h',
       'browser/ui/views/tabs/window_finder_ash.cc',
@@ -1173,6 +1179,8 @@
       'browser/ui/cocoa/passwords/passwords_list_view_controller.mm',
       'browser/ui/cocoa/passwords/pending_password_view_controller.h',
       'browser/ui/cocoa/passwords/pending_password_view_controller.mm',
+      'browser/ui/cocoa/passwords/save_pending_password_view_controller.h',
+      'browser/ui/cocoa/passwords/save_pending_password_view_controller.mm',
       'browser/ui/cocoa/presentation_mode_controller.h',
       'browser/ui/cocoa/presentation_mode_controller.mm',
       'browser/ui/cocoa/profiles/avatar_base_controller.h',
@@ -1606,6 +1614,8 @@
       'browser/ui/global_error/global_error_service_factory.h',
       'browser/ui/infobar_container_delegate.cc',
       'browser/ui/infobar_container_delegate.h',
+      'browser/ui/layout_constants.cc',
+      'browser/ui/layout_constants.h',
       'browser/ui/location_bar/location_bar.cc',
       'browser/ui/location_bar/location_bar.h',
       'browser/ui/location_bar/location_bar_util.cc',
@@ -1650,17 +1660,11 @@
       'browser/ui/passwords/manage_passwords_bubble_model.cc',
       'browser/ui/passwords/manage_passwords_bubble_model.h',
       'browser/ui/passwords/manage_passwords_icon_view.h',
-      'browser/ui/passwords/manage_passwords_ui_controller.cc',
-      'browser/ui/passwords/manage_passwords_ui_controller.h',
       'browser/ui/passwords/manage_passwords_view_utils_desktop.cc',
       'browser/ui/passwords/manage_passwords_view_utils_desktop.h',
       'browser/ui/passwords/password_dialog_controller.h',
       'browser/ui/passwords/password_dialog_controller_impl.cc',
       'browser/ui/passwords/password_dialog_controller_impl.h',
-      'browser/ui/passwords/passwords_client_ui_delegate.cc',
-      'browser/ui/passwords/passwords_client_ui_delegate.h',
-      'browser/ui/passwords/passwords_model_delegate.cc',
-      'browser/ui/passwords/passwords_model_delegate.h',
       'browser/ui/pdf/adobe_reader_info_win.cc',
       'browser/ui/pdf/adobe_reader_info_win.h',
       'browser/ui/pdf/chrome_pdf_web_contents_helper_client.cc',
@@ -1706,8 +1710,6 @@
       'browser/ui/sync/browser_synced_window_delegate.h',
       'browser/ui/sync/browser_synced_window_delegates_getter.cc',
       'browser/ui/sync/browser_synced_window_delegates_getter.h',
-      'browser/ui/sync/inline_login_dialog.cc',
-      'browser/ui/sync/inline_login_dialog.h',
       'browser/ui/sync/sync_promo_ui.cc',
       'browser/ui/sync/sync_promo_ui.h',
       'browser/ui/tab_contents/tab_contents_iterator.cc',
@@ -2059,8 +2061,6 @@
       'browser/ui/views/bookmarks/bookmark_bubble_view.h',
       'browser/ui/views/bookmarks/bookmark_editor_view.cc',
       'browser/ui/views/bookmarks/bookmark_editor_view.h',
-      'browser/ui/views/bookmarks/bookmark_sync_promo_view.cc',
-      'browser/ui/views/bookmarks/bookmark_sync_promo_view.h',
       'browser/ui/views/browser_dialogs_views_mac.cc',
       'browser/ui/views/chrome_browser_main_extra_parts_views.cc',
       'browser/ui/views/chrome_browser_main_extra_parts_views.h',
@@ -2079,6 +2079,8 @@
       'browser/ui/views/login_prompt_views.cc',
       'browser/ui/views/login_view.cc',
       'browser/ui/views/login_view.h',
+      'browser/ui/views/sync/bubble_sync_promo_view.cc',
+      'browser/ui/views/sync/bubble_sync_promo_view.h',
       'browser/ui/views/website_settings/permission_selector_view.cc',
       'browser/ui/views/website_settings/permission_selector_view.h',
       'browser/ui/views/website_settings/permission_selector_view_observer.h',
@@ -2124,8 +2126,6 @@
       'browser/ui/views/apps/glass_app_window_frame_view_win.h',
       'browser/ui/views/apps/shaped_app_window_targeter.cc',
       'browser/ui/views/apps/shaped_app_window_targeter.h',
-      'browser/ui/views/ash/tab_scrubber.cc',
-      'browser/ui/views/ash/tab_scrubber.h',
       'browser/ui/views/auto_keep_alive.cc',
       'browser/ui/views/auto_keep_alive.h',
       'browser/ui/views/autofill/autofill_dialog_views.cc',
@@ -2236,6 +2236,7 @@
       'browser/ui/views/frame/browser_non_client_frame_view.h',
       'browser/ui/views/frame/browser_non_client_frame_view_factory_android.cc',
       'browser/ui/views/frame/browser_non_client_frame_view_factory_mac.mm',
+      'browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc',
       'browser/ui/views/frame/browser_non_client_frame_view_mac.h',
       'browser/ui/views/frame/browser_non_client_frame_view_mac.mm',
       'browser/ui/views/frame/browser_root_view.cc',
@@ -2258,6 +2259,7 @@
       'browser/ui/views/frame/immersive_mode_controller.h',
       'browser/ui/views/frame/immersive_mode_controller_factory_android.cc',
       'browser/ui/views/frame/immersive_mode_controller_factory_mac.cc',
+      'browser/ui/views/frame/immersive_mode_controller_factory_views.cc',
       'browser/ui/views/frame/immersive_mode_controller_stub.cc',
       'browser/ui/views/frame/immersive_mode_controller_stub.h',
       'browser/ui/views/frame/minimize_button_metrics_win.cc',
@@ -2298,8 +2300,6 @@
       'browser/ui/views/infobars/infobar_container_view.h',
       'browser/ui/views/infobars/infobar_view.cc',
       'browser/ui/views/infobars/infobar_view.h',
-      'browser/ui/views/layout_constants.cc',
-      'browser/ui/views/layout_constants.h',
       'browser/ui/views/load_complete_listener.cc',
       'browser/ui/views/load_complete_listener.h',
       'browser/ui/views/location_bar/background_with_1_px_border.cc',
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index 691651d..fdef707 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -377,6 +377,12 @@
             ['chromeos==1', {
               'sources': [ '<@(chrome_common_extensions_chromeos_sources)' ],
             }],
+            ['OS=="win" or OS=="linux"', {
+              'sources': [
+                'common/extensions/api/input_ime/input_components_handler.cc',
+                'common/extensions/api/input_ime/input_components_handler.h',
+              ]
+            }]
           ],
         }],
         ['enable_extensions==1 and chromeos==1', {
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 20c6f40..b6be22a 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -54,9 +54,6 @@
       'browser/apps/app_speech_recognition_browsertest.cc',
       'browser/apps/app_url_redirector_browsertest.cc',
       'browser/apps/app_window_browsertest.cc',
-      'browser/apps/ephemeral_app_browsertest.cc',
-      'browser/apps/ephemeral_app_browsertest.h',
-      'browser/apps/ephemeral_app_service_browsertest.cc',
       'browser/apps/event_page_browsertest.cc',
       'browser/apps/guest_view/app_view_browsertest.cc',
       'browser/apps/guest_view/extension_view/extension_view_browsertest.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index bd9e5230..83f9388 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -31,7 +31,6 @@
       'browser/android/shortcut_info_unittest.cc',
       'browser/android/thumbnail/scoped_ptr_expiring_cache_unittest.cc',
       'browser/app_controller_mac_unittest.mm',
-      'browser/autocomplete/autocomplete_provider_unittest.cc',
       'browser/autocomplete/bookmark_provider_unittest.cc',
       'browser/autocomplete/builtin_provider_unittest.cc',
       'browser/autocomplete/history_quick_provider_unittest.cc',
@@ -230,17 +229,13 @@
       'browser/storage/durable_storage_permission_context_unittest.cc',
       'browser/sync/abstract_profile_sync_service_test.cc',
       'browser/sync/abstract_profile_sync_service_test.h',
-      'browser/sync/backend_migrator_unittest.cc',
       'browser/sync/glue/search_engine_data_type_controller_unittest.cc',
       'browser/sync/glue/sync_backend_host_impl_unittest.cc',
-      'browser/sync/profile_sync_auth_provider_unittest.cc',
       'browser/sync/profile_sync_service_autofill_unittest.cc',
       'browser/sync/profile_sync_service_bookmark_unittest.cc',
       'browser/sync/profile_sync_service_factory_unittest.cc',
       'browser/sync/profile_sync_service_startup_unittest.cc',
       'browser/sync/profile_sync_service_typed_url_unittest.cc',
-      'browser/sync/profile_sync_service_unittest.cc',
-      'browser/sync/startup_controller_unittest.cc',
       'browser/sync/sync_startup_tracker_unittest.cc',
       'browser/sync/test/test_http_bridge_factory.cc',
       'browser/sync/test/test_http_bridge_factory.h',
@@ -409,7 +404,7 @@
       'browser/ui/cocoa/passwords/passwords_bubble_cocoa_unittest.mm',
       'browser/ui/cocoa/passwords/passwords_bubble_controller_unittest.mm',
       'browser/ui/cocoa/passwords/passwords_list_view_controller_unittest.mm',
-      'browser/ui/cocoa/passwords/pending_password_view_controller_unittest.mm',
+      'browser/ui/cocoa/passwords/save_pending_password_view_controller_unittest.mm',
       'browser/ui/cocoa/profiles/avatar_button_controller_unittest.mm',
       'browser/ui/cocoa/profiles/avatar_button_unittest.mm',
       'browser/ui/cocoa/profiles/avatar_icon_controller_unittest.mm',
@@ -455,10 +450,12 @@
       'browser/ui/find_bar/find_backend_unittest.cc',
       'browser/ui/login/login_prompt_unittest.cc',
       'browser/ui/passwords/manage_passwords_state_unittest.cc',
+      'browser/ui/passwords/manage_passwords_ui_controller_unittest.cc',
       'browser/ui/passwords/manage_passwords_view_utils_unittest.cc',
       'browser/ui/passwords/password_bubble_experiment_unittest.cc',
       'browser/ui/passwords/password_manager_presenter_unittest.cc',
       'browser/ui/search_engines/keyword_editor_controller_unittest.cc',
+      'browser/ui/startup/startup_browser_creator_win_unittest.cc',
       'browser/ui/sync/profile_signin_confirmation_helper_unittest.cc',
       'browser/ui/sync/sync_promo_ui_unittest.cc',
       'browser/ui/tests/ui_gfx_image_unittest.cc',
@@ -467,7 +464,6 @@
       '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',
@@ -545,7 +541,6 @@
       'browser/renderer_context_menu/render_view_context_menu_test_util.cc',
       'browser/renderer_context_menu/render_view_context_menu_test_util.h',
       'browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc',
-      'browser/ui/passwords/manage_passwords_ui_controller_unittest.cc',
       'browser/ui/website_settings/mock_permission_bubble_view.cc',
       'browser/ui/website_settings/mock_permission_bubble_view.h',
     ],
@@ -1372,7 +1367,6 @@
       'browser/ui/views/bookmarks/bookmark_context_menu_unittest.cc',
       'browser/ui/views/bookmarks/bookmark_editor_view_unittest.cc',
       'browser/ui/views/bookmarks/bookmark_menu_delegate_unittest.cc',
-      'browser/ui/views/bookmarks/bookmark_sync_promo_view_unittest.cc',
       'browser/ui/views/confirm_bubble_views_unittest.cc',
       'browser/ui/views/crypto_module_password_dialog_view_unittest.cc',
       'browser/ui/views/desktop_media_picker_views_unittest.cc',
@@ -1386,6 +1380,7 @@
       'browser/ui/views/frame/web_contents_close_handler_unittest.cc',
       'browser/ui/views/omnibox/omnibox_view_views_unittest.cc',
       'browser/ui/views/status_icons/status_tray_win_unittest.cc',
+      'browser/ui/views/sync/bubble_sync_promo_view_unittest.cc',
       'browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views_unittest.cc',
       'browser/ui/views/tabs/fake_base_tab_strip_controller.cc',
       'browser/ui/views/tabs/fake_base_tab_strip_controller.h',
@@ -2006,6 +2001,17 @@
             'test/base/test_browser_window_aura.h',
           ],
         }],
+        ['use_ash==1', {
+          'sources': [
+            'test/base/default_ash_event_generator_delegate.cc',
+            'test/base/default_ash_event_generator_delegate.h',
+          ],
+          'dependencies': [
+            '../ash/ash.gyp:ash',
+            '../ui/aura/aura.gyp:aura',
+            '../ui/aura/aura.gyp:aura_test_support',
+          ],
+        }],
         ['configuration_policy==1', {
           'dependencies': [
             '../components/components.gyp:policy_component_test_support',
diff --git a/chrome/chrome_watcher/BUILD.gn b/chrome/chrome_watcher/BUILD.gn
index efd9155..f220580 100644
--- a/chrome/chrome_watcher/BUILD.gn
+++ b/chrome/chrome_watcher/BUILD.gn
@@ -33,6 +33,7 @@
     ":chrome_watcher_resources",
     ":client",
     "//base",
+    "//base:base_static",
     "//build/config/sanitizers:deps",
     "//chrome/installer/util",
     "//components/browser_watcher",
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 9443ec0..692790e 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -254,6 +254,9 @@
 // Disables Domain Reliability Monitoring.
 const char kDisableDomainReliability[]      = "disable-domain-reliability";
 
+// Disable download notification.
+const char kDisableDownloadNotification[] = "disable-download-notification";
+
 // Disable extensions.
 const char kDisableExtensions[]             = "disable-extensions";
 
@@ -403,9 +406,6 @@
 // Enables Domain Reliability Monitoring.
 const char kEnableDomainReliability[] = "enable-domain-reliability";
 
-// Download Notification. (value is "", "enabled" or "disabled")
-const char kEnableDownloadNotification[] = "enable-download-notification";
-
 // Enables experimental hotword features specific to always-on.
 const char kEnableExperimentalHotwordHardware[] = "enable-hotword-hardware";
 
@@ -1331,6 +1331,11 @@
     "disable-auto-hiding-toolbar-threshold";
 #endif // defined(OS_ANDROID)
 
+#if defined(OS_WIN) || defined(OS_LINUX)
+extern const char kEnableInputImeAPI[] = "enable-input-ime-api";
+extern const char kDisableInputImeAPI[] = "disable-input-ime-api";
+#endif
+
 bool AboutInSettingsEnabled() {
   return SettingsWindowEnabled() &&
          !base::CommandLine::ForCurrentProcess()->HasSwitch(
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 6a4e48f..2e931fc 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -74,6 +74,7 @@
 extern const char kDisableDeviceDiscoveryNotifications[];
 extern const char kDisableDinosaurEasterEgg[];
 extern const char kDisableDomainReliability[];
+extern const char kDisableDownloadNotification[];
 extern const char kDisableExtensionsFileAccessCheck[];
 extern const char kDisableExtensionsHttpThrottling[];
 extern const char kDisableExtensions[];
@@ -116,7 +117,6 @@
 extern const char kEnableCloudPrintProxy[];
 extern const char kEnableDevToolsExperiments[];
 extern const char kEnableDeviceDiscoveryNotifications[];
-extern const char kEnableDownloadNotification[];
 extern const char kEnableDomainReliability[];
 extern const char kEnableExperimentalHotwordHardware[];
 extern const char kEnableExtensionActivityLogging[];
@@ -397,6 +397,11 @@
 extern const char kEnableWaylandServer[];
 #endif
 
+#if defined(OS_WIN) || defined(OS_LINUX)
+extern const char kEnableInputImeAPI[];
+extern const char kDisableInputImeAPI[];
+#endif
+
 bool AboutInSettingsEnabled();
 bool MdExtensionsEnabled();
 bool MdHistoryEnabled();
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index a4a90aa..f258ccf 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -512,13 +512,19 @@
     "channel": "trunk",
     "extension_types": ["extension"]
   },
-  "input": {
+  "input": [{
     "channel": "stable",
     "extension_types": ["extension", "legacy_packaged_app"],
     // TODO(kalman): Um what does this inply?
     "inplies_full_url_access": true,
     "platforms": ["chromeos"]
-  },
+  }, {
+    "channel": "dev",
+    "extension_types": ["extension", "legacy_packaged_app"],
+    // TODO(kalman): Um what does this inply?
+    "inplies_full_url_access": true,
+    "platforms": ["win", "linux"]
+  }],
   "inputMethodPrivate": [{
     "channel": "stable",
     "extension_types": ["extension", "legacy_packaged_app", "platform_app"],
diff --git a/chrome/common/extensions/api/cast_streaming_rtp_stream.idl b/chrome/common/extensions/api/cast_streaming_rtp_stream.idl
index 70b4662..8425609 100644
--- a/chrome/common/extensions/api/cast_streaming_rtp_stream.idl
+++ b/chrome/common/extensions/api/cast_streaming_rtp_stream.idl
@@ -27,6 +27,10 @@
     // Minimum latency in milliseconds. Defaults to |maxLatency|.
     long? minLatency;
 
+    // Starting latency for animated content in milliseconds.
+    // Defaults to |maxLatency|.
+    long? animatedLatency;
+
     DOMString codecName;
 
     // Synchronization source identifier.
diff --git a/chrome/common/extensions/api/common_extension_api_unittest.cc b/chrome/common/extensions/api/common_extension_api_unittest.cc
index f858062..d306d80 100644
--- a/chrome/common/extensions/api/common_extension_api_unittest.cc
+++ b/chrome/common/extensions/api/common_extension_api_unittest.cc
@@ -5,6 +5,7 @@
 #include "extensions/common/extension_api.h"
 
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/files/file_path.h"
@@ -199,14 +200,19 @@
 }
 
 TEST(ExtensionAPITest, IsAnyFeatureAvailableToContext) {
-  scoped_refptr<const Extension> app = ExtensionBuilder()
-    .SetManifest(DictionaryBuilder()
-      .Set("name", "app")
-      .Set("app", DictionaryBuilder()
-        .Set("background", DictionaryBuilder()
-          .Set("scripts", ListBuilder().Append("background.js"))))
-      .Set("version", "1")
-      .Set("manifest_version", 2)).Build();
+  scoped_refptr<const Extension> app =
+      ExtensionBuilder()
+          .SetManifest(
+              DictionaryBuilder()
+                  .Set("name", "app")
+                  .Set("app", DictionaryBuilder().Set(
+                                  "background",
+                                  DictionaryBuilder().Set(
+                                      "scripts", std::move(ListBuilder().Append(
+                                                     "background.js")))))
+                  .Set("version", "1")
+                  .Set("manifest_version", 2))
+          .Build();
   scoped_refptr<const Extension> extension = ExtensionBuilder()
     .SetManifest(DictionaryBuilder()
       .Set("name", "extension")
diff --git a/chrome/common/extensions/api/file_browser_handlers/file_browser_handler_manifest_unittest.cc b/chrome/common/extensions/api/file_browser_handlers/file_browser_handler_manifest_unittest.cc
index 9493700..11886ad6 100644
--- a/chrome/common/extensions/api/file_browser_handlers/file_browser_handler_manifest_unittest.cc
+++ b/chrome/common/extensions/api/file_browser_handlers/file_browser_handler_manifest_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/strings/string_number_conversions.h"
 #include "chrome/common/extensions/api/file_browser_handlers/file_browser_handler.h"
 #include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
@@ -34,13 +36,14 @@
       .Set("version", "1.0.0")
       .Set("manifest_version", 2)
       .Set("file_browser_handlers",
-           extensions::ListBuilder().Append(
+           std::move(extensions::ListBuilder().Append(
                extensions::DictionaryBuilder()
                    .Set("id", "open")
                    .Set("default_title", "open")
-                   .Set("file_filters", extensions::ListBuilder()
-                                            .Append("filesystem:*.txt")
-                                            .Append("filesystem:*.html"))));
+                   .Set("file_filters",
+                        std::move(extensions::ListBuilder()
+                                      .Append("filesystem:*.txt")
+                                      .Append("filesystem:*.html"))))));
   scoped_ptr<base::DictionaryValue> bad_manifest_value(
       bad_manifest_builder.Build());
 
@@ -49,7 +52,8 @@
   extensions::DictionaryBuilder good_manifest_builder(
       *make_scoped_ptr(bad_manifest_value->DeepCopy()).get());
   good_manifest_builder.Set(
-      "permissions", extensions::ListBuilder().Append("fileBrowserHandler"));
+      "permissions",
+      std::move(extensions::ListBuilder().Append("fileBrowserHandler")));
 
   extensions::ExtensionBuilder bad_app_builder;
   bad_app_builder.SetManifest(bad_manifest_value.Pass());
@@ -98,21 +102,22 @@
 TEST_F(FileBrowserHandlerManifestTest, ValidFileBrowserHandler) {
   scoped_refptr<const Extension> extension =
       ExtensionBuilder()
-          .SetManifest(
-               DictionaryBuilder()
-                   .Set("name", "file browser handler test")
-                   .Set("version", "1.0.0")
-                   .Set("manifest_version", 2)
-                   .Set("permissions",
-                        extensions::ListBuilder().Append("fileBrowserHandler"))
-                   .Set("file_browser_handlers",
-                        ListBuilder().Append(
-                            DictionaryBuilder()
-                                .Set("id", "ExtremelyCoolAction")
-                                .Set("default_title", "Be Amazed")
-                                .Set("default_icon", "icon.png")
-                                .Set("file_filters", ListBuilder().Append(
-                                                         "filesystem:*.txt")))))
+          .SetManifest(DictionaryBuilder()
+                           .Set("name", "file browser handler test")
+                           .Set("version", "1.0.0")
+                           .Set("manifest_version", 2)
+                           .Set("permissions",
+                                std::move(extensions::ListBuilder().Append(
+                                    "fileBrowserHandler")))
+                           .Set("file_browser_handlers",
+                                std::move(ListBuilder().Append(
+                                    DictionaryBuilder()
+                                        .Set("id", "ExtremelyCoolAction")
+                                        .Set("default_title", "Be Amazed")
+                                        .Set("default_icon", "icon.png")
+                                        .Set("file_filters",
+                                             std::move(ListBuilder().Append(
+                                                 "filesystem:*.txt")))))))
           .Build();
 
   ASSERT_TRUE(extension.get());
@@ -138,21 +143,22 @@
   scoped_refptr<const Extension> extension =
       ExtensionBuilder()
           .SetID(extension_misc::kQuickOfficeExtensionId)
-          .SetManifest(
-               DictionaryBuilder()
-                   .Set("name", "file browser handler test")
-                   .Set("version", "1.0.0")
-                   .Set("manifest_version", 2)
-                   .Set("permissions",
-                        extensions::ListBuilder().Append("fileBrowserHandler"))
-                   .Set("file_browser_handlers",
-                        ListBuilder().Append(
-                            DictionaryBuilder()
-                                .Set("id", "ID")
-                                .Set("default_title", "Default title")
-                                .Set("default_icon", "icon.png")
-                                .Set("file_filters", ListBuilder().Append(
-                                                         "filesystem:*.txt")))))
+          .SetManifest(DictionaryBuilder()
+                           .Set("name", "file browser handler test")
+                           .Set("version", "1.0.0")
+                           .Set("manifest_version", 2)
+                           .Set("permissions",
+                                std::move(extensions::ListBuilder().Append(
+                                    "fileBrowserHandler")))
+                           .Set("file_browser_handlers",
+                                std::move(ListBuilder().Append(
+                                    DictionaryBuilder()
+                                        .Set("id", "ID")
+                                        .Set("default_title", "Default title")
+                                        .Set("default_icon", "icon.png")
+                                        .Set("file_filters",
+                                             std::move(ListBuilder().Append(
+                                                 "filesystem:*.txt")))))))
           .Build();
 
   ASSERT_TRUE(extension.get());
@@ -171,23 +177,25 @@
 TEST_F(FileBrowserHandlerManifestTest, ValidFileBrowserHandlerWithCreate) {
   scoped_refptr<const Extension> extension =
       ExtensionBuilder()
-          .SetManifest(
-               DictionaryBuilder()
-                   .Set("name", "file browser handler test create")
-                   .Set("version", "1.0.0")
-                   .Set("manifest_version", 2)
-                   .Set("permissions",
-                        extensions::ListBuilder().Append("fileBrowserHandler"))
-                   .Set("file_browser_handlers",
-                        ListBuilder().Append(
-                            DictionaryBuilder()
-                                .Set("id", "ID")
-                                .Set("default_title", "Default title")
-                                .Set("default_icon", "icon.png")
-                                .Set("file_filters",
-                                     ListBuilder().Append("filesystem:*.txt"))
-                                .Set("file_access",
-                                     ListBuilder().Append("create")))))
+          .SetManifest(DictionaryBuilder()
+                           .Set("name", "file browser handler test create")
+                           .Set("version", "1.0.0")
+                           .Set("manifest_version", 2)
+                           .Set("permissions",
+                                std::move(extensions::ListBuilder().Append(
+                                    "fileBrowserHandler")))
+                           .Set("file_browser_handlers",
+                                std::move(ListBuilder().Append(
+                                    DictionaryBuilder()
+                                        .Set("id", "ID")
+                                        .Set("default_title", "Default title")
+                                        .Set("default_icon", "icon.png")
+                                        .Set("file_filters",
+                                             std::move(ListBuilder().Append(
+                                                 "filesystem:*.txt")))
+                                        .Set("file_access",
+                                             std::move(ListBuilder().Append(
+                                                 "create")))))))
           .Build();
 
   ASSERT_TRUE(extension.get());
diff --git a/chrome/common/extensions/api/input_ime.json b/chrome/common/extensions/api/input_ime.json
index 7a4b0e6..ac19b70d 100644
--- a/chrome/common/extensions/api/input_ime.json
+++ b/chrome/common/extensions/api/input_ime.json
@@ -105,6 +105,7 @@
         "name": "setComposition",
         "type": "function",
         "description": "Set the current composition. If this extension does not own the active IME, this fails.",
+        "platforms": ["chromeos"],
         "parameters": [
           {
             "name": "parameters",
@@ -174,6 +175,7 @@
         "name": "clearComposition",
         "type": "function",
         "description": "Clear the current composition. If this extension does not own the active IME, this fails.",
+        "platforms": ["chromeos"],
         "parameters": [
           {
             "name": "parameters",
@@ -203,6 +205,7 @@
         "name": "commitText",
         "type": "function",
         "description": "Commits the provided text to the current input.",
+        "platforms": ["chromeos"],
         "parameters": [
           {
             "name": "parameters",
@@ -236,6 +239,7 @@
         "name": "sendKeyEvents",
         "type": "function",
         "description": "Sends the key events.  This function is expected to be used by virtual keyboards.  When key(s) on a virtual keyboard is pressed by a user, this function is used to propagate that event to the system.",
+        "platforms": ["chromeos"],
         "parameters": [
           {
             "name": "parameters",
@@ -267,12 +271,14 @@
         "name": "hideInputView",
         "type": "function",
         "description": "Hides the input view window, which is popped up automatically by system. If the input view window is already hidden, this function will do nothing.",
+        "platforms": ["chromeos"],
         "parameters": []
       },
       {
         "name": "setCandidateWindowProperties",
         "type": "function",
         "description": "Sets the properties of the candidate window. This fails if the extension doesn't own the active IME",
+        "platforms": ["chromeos"],
         "parameters": [
           {
             "name": "parameters",
@@ -342,6 +348,7 @@
         "name": "setCandidates",
         "type": "function",
         "description": "Sets the current candidate list. This fails if this extension doesn't own the active IME",
+        "platforms": ["chromeos"],
         "parameters": [
           {
             "name": "parameters",
@@ -394,6 +401,7 @@
         "name": "setCursorPosition",
         "type": "function",
         "description": "Set the position of the cursor in the candidate window. This is a no-op if this extension does not own the active IME.",
+        "platforms": ["chromeos"],
         "parameters": [
           {
             "name": "parameters",
@@ -427,6 +435,7 @@
         "name": "setMenuItems",
         "type": "function",
         "description": "Adds the provided menu items to the language menu when this IME is active.",
+        "platforms": ["chromeos"],
         "parameters": [
           {
             "name": "parameters",
@@ -458,6 +467,7 @@
         "name": "updateMenuItems",
         "type": "function",
         "description": "Updates the state of the MenuItems specified",
+        "platforms": ["chromeos"],
         "parameters": [
           {
             "name": "parameters",
@@ -489,6 +499,7 @@
         "name": "deleteSurroundingText",
         "type": "function",
         "description": "Deletes the text around the caret.",
+        "platforms": ["chromeos"],
         "parameters": [
           {
             "name": "parameters",
@@ -526,6 +537,7 @@
         "name": "keyEventHandled",
         "type": "function",
         "description": "Indicates that the key event received by onKeyEvent is handled.  This should only be called if the onKeyEvent listener is asynchronous.",
+        "platforms": ["chromeos", "win", "linux"],
         "parameters": [
           {"type": "string", "name": "requestId", "description": "Request id of the event that was handled.  This should come from keyEvent.requestId"},
           {"type": "boolean", "name": "response", "description": "True if the keystroke was handled, false if not"}
@@ -537,6 +549,7 @@
         "name": "onActivate",
         "type": "function",
         "description": "This event is sent when an IME is activated. It signals that the IME will be receiving onKeyPress events.",
+        "platforms": ["chromeos"],
         "parameters": [
           {
             "type": "string",
@@ -554,6 +567,7 @@
         "name": "onDeactivated",
         "type": "function",
         "description": "This event is sent when an IME is deactivated. It signals that the IME will no longer be receiving onKeyPress events.",
+        "platforms": ["chromeos", "win", "linux"],
         "parameters": [
           {
             "type": "string",
@@ -566,6 +580,7 @@
         "name": "onFocus",
         "type": "function",
         "description": "This event is sent when focus enters a text box. It is sent to all extensions that are listening to this event, and enabled by the user.",
+        "platforms": ["chromeos", "win", "linux"],
         "parameters": [
           {
             "$ref": "InputContext",
@@ -578,6 +593,7 @@
         "name": "onBlur",
         "type": "function",
         "description": "This event is sent when focus leaves a text box. It is sent to all extensions that are listening to this event, and enabled by the user.",
+        "platforms": ["chromeos", "win", "linux"],
         "parameters": [
           {
             "type": "integer",
@@ -590,6 +606,7 @@
         "name": "onInputContextUpdate",
         "type": "function",
         "description": "This event is sent when the properties of the current InputContext change, such as the the type. It is sent to all extensions that are listening to this event, and enabled by the user.",
+        "platforms": ["chromeos"],
         "parameters": [
           {
             "$ref": "InputContext",
@@ -602,6 +619,7 @@
         "name": "onKeyEvent",
         "type": "function",
         "description": "This event is sent if this extension owns the active IME.",
+        "platforms": ["chromeos", "win", "linux"],
         "options": {
           "supportsFilters": false,
           "supportsListeners": true,
@@ -641,6 +659,7 @@
         "name": "onCandidateClicked",
         "type": "function",
         "description": "This event is sent if this extension owns the active IME.",
+        "platforms": ["chromeos"],
         "parameters": [
           {
             "type": "string",
@@ -663,6 +682,7 @@
         "name": "onMenuItemActivated",
         "type": "function",
         "description": "Called when the user selects a menu item",
+        "platforms": ["chromeos"],
         "parameters": [
           {
             "type": "string",
@@ -680,6 +700,7 @@
         "name": "onSurroundingTextChanged",
         "type": "function",
         "description": "Called when the editable string around caret is changed or when the caret position is moved. The text length is limited to 100 characters for each back and forth direction.",
+        "platforms": ["chromeos"],
         "parameters": [
           {
             "type": "string",
@@ -715,6 +736,7 @@
         "name": "onReset",
         "type": "function",
         "description": "This event is sent when chrome terminates ongoing text input session.",
+        "platforms": ["chromeos", "win", "linux"],
         "parameters": [
           {
             "type": "string",
diff --git a/chrome/common/extensions/api/schemas.gypi b/chrome/common/extensions/api/schemas.gypi
index 46643785..51a5797 100644
--- a/chrome/common/extensions/api/schemas.gypi
+++ b/chrome/common/extensions/api/schemas.gypi
@@ -172,6 +172,11 @@
           '<@(chromeos_non_compiled_schema_files)',
         ],
       }],
+      ['OS=="linux" or OS=="win"', {
+        'schema_files': [
+	  'input_ime.json',
+	],
+      }],
       ['enable_webrtc==1', {
         'schema_files': [
           '<@(webrtc_schema_files)',
diff --git a/chrome/common/extensions/features/chrome_channel_feature_filter_unittest.cc b/chrome/common/extensions/features/chrome_channel_feature_filter_unittest.cc
index 061bda4..10540a34 100644
--- a/chrome/common/extensions/features/chrome_channel_feature_filter_unittest.cc
+++ b/chrome/common/extensions/features/chrome_channel_feature_filter_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/common/extensions/features/chrome_channel_feature_filter.h"
 
 #include <string>
+#include <utility>
 
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
@@ -177,12 +178,17 @@
   scoped_ptr<base::DictionaryValue> rule(
       DictionaryBuilder()
           .Set("feature1",
-               ListBuilder()
-                   .Append(DictionaryBuilder().Set("channel", "beta").Set(
-                       "extension_types", ListBuilder().Append("extension")))
-                   .Append(DictionaryBuilder().Set("channel", "beta").Set(
-                       "extension_types",
-                       ListBuilder().Append("legacy_packaged_app"))))
+               std::move(ListBuilder()
+                             .Append(DictionaryBuilder()
+                                         .Set("channel", "beta")
+                                         .Set("extension_types",
+                                              std::move(ListBuilder().Append(
+                                                  "extension"))))
+                             .Append(DictionaryBuilder()
+                                         .Set("channel", "beta")
+                                         .Set("extension_types",
+                                              std::move(ListBuilder().Append(
+                                                  "legacy_packaged_app"))))))
           .Build());
 
   scoped_ptr<BaseFeatureProvider> provider(
@@ -234,18 +240,18 @@
   scoped_ptr<base::DictionaryValue> rule(
       DictionaryBuilder()
           .Set("channel", "trunk")
-          .Set("extension_types", ListBuilder().Append("extension"))
+          .Set("extension_types", std::move(ListBuilder().Append("extension")))
           .Build());
   simple_feature->Parse(rule.get());
   features->push_back(simple_feature.Pass());
 
   // Rule: "legacy_packaged_app", channel stable.
   simple_feature.reset(CreateFeature<SimpleFeature>());
-  rule =
-      DictionaryBuilder()
-          .Set("channel", "stable")
-          .Set("extension_types", ListBuilder().Append("legacy_packaged_app"))
-          .Build();
+  rule = DictionaryBuilder()
+             .Set("channel", "stable")
+             .Set("extension_types",
+                  std::move(ListBuilder().Append("legacy_packaged_app")))
+             .Build();
   simple_feature->Parse(rule.get());
   features->push_back(simple_feature.Pass());
 
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index 7948607..70b5f66 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/command_line.h"
 #include "base/json/json_file_value_serializer.h"
 #include "base/logging.h"
@@ -1299,11 +1301,12 @@
 testing::AssertionResult ShowsAllHostsWarning(const std::string& pattern) {
   scoped_refptr<Extension> extension =
       ExtensionBuilder()
-          .SetManifest(DictionaryBuilder()
-                           .Set("name", "TLDWildCardTest")
-                           .Set("version", "0.1.0")
-                           .Set("permissions", ListBuilder().Append(pattern))
-                           .Build())
+          .SetManifest(
+              DictionaryBuilder()
+                  .Set("name", "TLDWildCardTest")
+                  .Set("version", "0.1.0")
+                  .Set("permissions", std::move(ListBuilder().Append(pattern)))
+                  .Build())
           .Build();
 
   return VerifyHasPermissionMessage(
diff --git a/chrome/common/extensions/permissions/permissions_data_unittest.cc b/chrome/common/extensions/permissions/permissions_data_unittest.cc
index 620fb8b..c2cc98e3 100644
--- a/chrome/common/extensions/permissions/permissions_data_unittest.cc
+++ b/chrome/common/extensions/permissions/permissions_data_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
 #include <vector>
 
 #include "base/command_line.h"
@@ -60,14 +61,13 @@
     permissions.Append(host_permissions);
 
   return ExtensionBuilder()
-      .SetManifest(
-          DictionaryBuilder()
-              .Set("name", id)
-              .Set("description", "an extension")
-              .Set("manifest_version", 2)
-              .Set("version", "1.0.0")
-              .Set("permissions", permissions.Pass())
-              .Build())
+      .SetManifest(DictionaryBuilder()
+                       .Set("name", id)
+                       .Set("description", "an extension")
+                       .Set("manifest_version", 2)
+                       .Set("version", "1.0.0")
+                       .Set("permissions", std::move(permissions))
+                       .Build())
       .SetLocation(location)
       .SetID(id)
       .Build();
diff --git a/chrome/common/instant_types.h b/chrome/common/instant_types.h
index 617f8f9..fe66a4e 100644
--- a/chrome/common/instant_types.h
+++ b/chrome/common/instant_types.h
@@ -142,6 +142,10 @@
   // The external URL that should be pinged when this item is suggested/clicked.
   GURL impression_url;
   GURL click_url;
+
+  // True if it's a server side suggestion.
+  // Otherwise, it's a client side suggestion.
+  bool is_server_side_suggestion;
 };
 
 // An InstantMostVisitedItem along with its assigned restricted ID.
diff --git a/chrome/common/localized_error.cc b/chrome/common/localized_error.cc
index e36cfe1e..114c252 100644
--- a/chrome/common/localized_error.cc
+++ b/chrome/common/localized_error.cc
@@ -15,7 +15,6 @@
 #include "base/values.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/grit/chromium_strings.h"
-#include "chrome/grit/generated_resources.h"
 #include "chrome/grit/google_chrome_strings.h"
 #include "components/error_page/common/error_page_params.h"
 #include "components/error_page/common/net_error_info.h"
diff --git a/chrome/common/pepper_permission_util_unittest.cc b/chrome/common/pepper_permission_util_unittest.cc
index 12bab48..7575fa28 100644
--- a/chrome/common/pepper_permission_util_unittest.cc
+++ b/chrome/common/pepper_permission_util_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <set>
 #include <string>
+#include <utility>
 
 #include "chrome/common/extensions/features/feature_channel.h"
 #include "components/crx_file/id_util.h"
@@ -30,8 +31,8 @@
           .Set("name", "Has Dependent Modules")
           .Set("version", "1.0")
           .Set("manifest_version", 2)
-          .Set("import",
-               ListBuilder().Append(DictionaryBuilder().Set("id", import_id)))
+          .Set("import", std::move(ListBuilder().Append(
+                             DictionaryBuilder().Set("id", import_id))))
           .Build();
 
   return ExtensionBuilder()
@@ -92,10 +93,11 @@
           .Set("manifest_version", 2)
           .Set("export",
                DictionaryBuilder()
-                   .Set("resources", ListBuilder().Append("*"))
+                   .Set("resources", std::move(ListBuilder().Append("*")))
                    // Add the extension to the whitelist.  This
                    // restricts import to |whitelisted_id| only.
-                   .Set("whitelist", ListBuilder().Append(whitelisted_id)))
+                   .Set("whitelist",
+                        std::move(ListBuilder().Append(whitelisted_id))))
           .Build();
   scoped_refptr<Extension> shared_module =
       ExtensionBuilder().SetManifest(shared_module_manifest.Pass()).Build();
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index dd363714..4f61165 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -69,7 +69,7 @@
 const char kSessionExitType[] = "profile.exit_type";
 
 // An integer pref. Holds one of several values:
-// 0: (deprecated) open the homepage on startup.
+// 0: unused, previously indicated to open the homepage on startup
 // 1: restore the last session.
 // 2: this was used to indicate a specific session should be restored. It is
 //    no longer used, but saved to avoid conflict with old preferences.
@@ -78,12 +78,6 @@
 // 5: open the New Tab Page on startup.
 const char kRestoreOnStartup[] = "session.restore_on_startup";
 
-// A preference to keep track of whether we have already checked whether we
-// need to migrate the user from kRestoreOnStartup=0 to kRestoreOnStartup=4.
-// We only need to do this check once, on upgrade from m18 or lower to m19 or
-// higher.
-const char kRestoreOnStartupMigrated[] = "session.restore_on_startup_migrated";
-
 // The URLs to restore on startup or when the home button is pressed. The URLs
 // are only restored on startup if kRestoreOnStartup is 4.
 const char kURLsToRestoreOnStartup[] = "session.startup_urls";
@@ -337,6 +331,11 @@
     "webkit.webprefs.loads_images_automatically";
 const char kWebKitPluginsEnabled[] = "webkit.webprefs.plugins_enabled";
 
+// Boolean that is true when Data Saver is enabled.
+// TODO(bengr): Migrate the preference string to "data_saver.enabled"
+// (crbug.com/564207).
+const char kDataSaverEnabled[] = "spdy_proxy.enabled";
+
 // Boolean that is true when SafeBrowsing is enabled.
 const char kSafeBrowsingEnabled[] = "safebrowsing.enabled";
 
@@ -419,6 +418,15 @@
 const char kInstantUIZeroSuggestUrlPrefix[] =
     "instant_ui.zero_suggest_url_prefix";
 
+// A boolean pref set to true if prediction of network actions is allowed.
+// Actions include DNS prefetching, TCP and SSL preconnection, prerendering
+// of web pages, and resource prefetching.
+// NOTE: The "dns_prefetching.enabled" value is used so that historical user
+// preferences are not lost.
+// TODO(bnc): Remove kNetworkPredictionEnabled once kNetworkPredictionOptions
+// is functioning as per crbug.com/334602.
+const char kNetworkPredictionEnabled[] = "dns_prefetching.enabled";
+
 // A preference of enum chrome_browser_net::NetworkPredictionOptions shows
 // if prediction of network actions is allowed, depending on network type.
 // Actions include DNS prefetching, TCP and SSL preconnection, prerendering
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 1ead3de..117e571 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -29,7 +29,6 @@
 #endif
 extern const char kProfileIconVersion[];
 extern const char kRestoreOnStartup[];
-extern const char kRestoreOnStartupMigrated[];
 extern const char kSessionExitedCleanly[];
 extern const char kSessionExitType[];
 extern const char kSupervisedUserCustodianEmail[];
@@ -141,6 +140,7 @@
 extern const char kWebKitForceEnableZoom[];
 extern const char kWebKitPasswordEchoEnabled[];
 #endif
+extern const char kDataSaverEnabled[];
 extern const char kSafeBrowsingEnabled[];
 extern const char kSafeBrowsingExtendedReportingEnabled[];
 extern const char kSafeBrowsingProceedAnywayDisabled[];
@@ -165,6 +165,7 @@
 extern const char kLastPolicyCheckTime[];
 #endif
 extern const char kInstantUIZeroSuggestUrlPrefix[];
+extern const char kNetworkPredictionEnabled[];
 extern const char kNetworkPredictionOptions[];
 extern const char kDefaultAppsInstallState[];
 extern const char kHideWebStoreIcon[];
diff --git a/chrome/installer/mini_installer/BUILD.gn b/chrome/installer/mini_installer/BUILD.gn
index c205f8c..03251bd 100644
--- a/chrome/installer/mini_installer/BUILD.gn
+++ b/chrome/installer/mini_installer/BUILD.gn
@@ -180,12 +180,13 @@
   # This target is special so we manually override most linker flags and
   # specify our own to keep the size down.
   configs -= [
+    "//build/config:executable_config",
     "//build/config/compiler:compiler",
-    "//build/config/win:common_linker_setup",
     "//build/config/win:console",
   ]
   configs += [
     ":mini_installer_compiler_flags",
+    "//build/config/win:sdk_link",
     "//build/config/win:windowed",
   ]
 
diff --git a/chrome/installer/mini_installer/decompress.cc b/chrome/installer/mini_installer/decompress.cc
index 6440b21..2792d89 100644
--- a/chrome/installer/mini_installer/decompress.cc
+++ b/chrome/installer/mini_installer/decompress.cc
@@ -192,7 +192,7 @@
     };
 
     wchar_t path[MAX_PATH] = {0};
-    for (int i = 0; i < _countof(candidate_paths); ++i) {
+    for (size_t i = 0; i < _countof(candidate_paths); ++i) {
       path[0] = L'\0';
       DWORD result = ::ExpandEnvironmentStringsW(candidate_paths[i],
                                                  path, _countof(path));
diff --git a/chrome/installer/mini_installer/decompress_test.cc b/chrome/installer/mini_installer/decompress_test.cc
index 1592bb4..a9149b0 100644
--- a/chrome/installer/mini_installer/decompress_test.cc
+++ b/chrome/installer/mini_installer/decompress_test.cc
@@ -33,5 +33,5 @@
   // Check if the expanded file is a valid executable.
   DWORD type = static_cast<DWORD>(-1);
   EXPECT_TRUE(GetBinaryType(dest_path.value().c_str(), &type));
-  EXPECT_EQ(SCS_32BIT_BINARY, type);
+  EXPECT_EQ(static_cast<DWORD>(SCS_32BIT_BINARY), type);
 }
diff --git a/chrome/installer/mini_installer/mini_string_test.cc b/chrome/installer/mini_installer/mini_string_test.cc
index a2ef7bf..f881011 100644
--- a/chrome/installer/mini_installer/mini_string_test.cc
+++ b/chrome/installer/mini_installer/mini_string_test.cc
@@ -26,7 +26,7 @@
   static const wchar_t kTestString[] = L"1234567890";
 
   StackString<MAX_PATH> str;
-  EXPECT_EQ(MAX_PATH, str.capacity());
+  EXPECT_EQ(static_cast<size_t>(MAX_PATH), str.capacity());
 
   std::wstring compare_str;
 
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc
index 65b28829..3e41d6ef 100644
--- a/chrome/installer/setup/install.cc
+++ b/chrome/installer/setup/install.cc
@@ -340,15 +340,12 @@
   bool do_not_create_desktop_shortcut = false;
   bool do_not_create_quick_launch_shortcut = false;
   bool do_not_create_taskbar_shortcut = false;
-  bool alternate_desktop_shortcut = false;
   prefs.GetBool(master_preferences::kDoNotCreateDesktopShortcut,
                 &do_not_create_desktop_shortcut);
   prefs.GetBool(master_preferences::kDoNotCreateQuickLaunchShortcut,
                 &do_not_create_quick_launch_shortcut);
   prefs.GetBool(master_preferences::kDoNotCreateTaskbarShortcut,
                 &do_not_create_taskbar_shortcut);
-  prefs.GetBool(master_preferences::kAltShortcutText,
-                &alternate_desktop_shortcut);
 
   BrowserDistribution* dist = product.distribution();
 
@@ -380,28 +377,9 @@
 
   if (!do_not_create_desktop_shortcut ||
       shortcut_operation == ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING) {
-    const base::string16 alternate_shortcut_name =
-        dist->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME_ALTERNATE);
-
-    ShellUtil::ShortcutProperties desktop_properties(base_properties);
-    if (alternate_desktop_shortcut && !alternate_shortcut_name.empty())
-      desktop_properties.set_shortcut_name(alternate_shortcut_name);
     ExecuteAndLogShortcutOperation(
-        ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist, desktop_properties,
+        ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist, base_properties,
         shortcut_operation);
-
-    // On update there is no harm in always trying to update the alternate
-    // Desktop shortcut (if it exists for this distribution).
-    if (!alternate_desktop_shortcut &&
-        shortcut_operation == ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING &&
-        !alternate_shortcut_name.empty()) {
-      desktop_properties.set_shortcut_name(
-          dist->GetShortcutName(
-              BrowserDistribution::SHORTCUT_CHROME_ALTERNATE));
-      ExecuteAndLogShortcutOperation(
-          ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist, desktop_properties,
-          shortcut_operation);
-    }
   }
 
   if (!do_not_create_quick_launch_shortcut ||
diff --git a/chrome/installer/setup/install_unittest.cc b/chrome/installer/setup/install_unittest.cc
index cfbca40..d48f6bf 100644
--- a/chrome/installer/setup/install_unittest.cc
+++ b/chrome/installer/setup/install_unittest.cc
@@ -91,7 +91,7 @@
     expected_start_menu_properties_.set_dual_mode(
         InstallUtil::ShouldInstallMetroProperties());
 
-    prefs_.reset(GetFakeMasterPrefs(false, false, false));
+    prefs_.reset(GetFakeMasterPrefs(false, false));
 
     ASSERT_TRUE(fake_user_desktop_.CreateUniqueTempDir());
     ASSERT_TRUE(fake_common_desktop_.CreateUniqueTempDir());
@@ -117,9 +117,6 @@
     base::string16 shortcut_name(
         dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
         installer::kLnkExt);
-    base::string16 alternate_shortcut_name(
-        dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME_ALTERNATE) +
-        installer::kLnkExt);
 
     user_desktop_shortcut_ =
         fake_user_desktop_.path().Append(shortcut_name);
@@ -140,8 +137,6 @@
             .Append(dist_->GetStartMenuShortcutSubfolder(
                 BrowserDistribution::SUBFOLDER_CHROME))
             .Append(shortcut_name);
-    user_alternate_desktop_shortcut_ =
-        fake_user_desktop_.path().Append(alternate_shortcut_name);
   }
 
   void TearDown() override {
@@ -156,8 +151,7 @@
 
   installer::MasterPreferences* GetFakeMasterPrefs(
       bool do_not_create_desktop_shortcut,
-      bool do_not_create_quick_launch_shortcut,
-      bool alternate_desktop_shortcut) {
+      bool do_not_create_quick_launch_shortcut) {
     const struct {
       const char* pref_name;
       bool is_desired;
@@ -166,8 +160,6 @@
         do_not_create_desktop_shortcut },
       { installer::master_preferences::kDoNotCreateQuickLaunchShortcut,
         do_not_create_quick_launch_shortcut },
-      { installer::master_preferences::kAltShortcutText,
-        alternate_desktop_shortcut },
     };
 
     std::string master_prefs("{\"distribution\":{");
@@ -209,7 +201,6 @@
   base::FilePath system_desktop_shortcut_;
   base::FilePath system_start_menu_shortcut_;
   base::FilePath system_start_menu_subdir_shortcut_;
-  base::FilePath user_alternate_desktop_shortcut_;
 };
 
 }  // namespace
@@ -271,23 +262,9 @@
                               expected_properties_);
 }
 
-TEST_F(InstallShortcutTest, CreateAllShortcutsAlternateDesktopName) {
-  scoped_ptr<installer::MasterPreferences> prefs_alt_desktop(
-      GetFakeMasterPrefs(false, false, true));
-  installer::CreateOrUpdateShortcuts(
-      chrome_exe_, *product_, *prefs_alt_desktop, installer::CURRENT_USER,
-      installer::INSTALL_SHORTCUT_CREATE_ALL);
-  base::win::ValidateShortcut(user_alternate_desktop_shortcut_,
-                              expected_properties_);
-  base::win::ValidateShortcut(user_quick_launch_shortcut_,
-                              expected_properties_);
-  base::win::ValidateShortcut(user_start_menu_shortcut_,
-                              expected_start_menu_properties_);
-}
-
 TEST_F(InstallShortcutTest, CreateAllShortcutsButDesktopShortcut) {
   scoped_ptr<installer::MasterPreferences> prefs_no_desktop(
-      GetFakeMasterPrefs(true, false, false));
+      GetFakeMasterPrefs(true, false));
   installer::CreateOrUpdateShortcuts(
       chrome_exe_, *product_, *prefs_no_desktop, installer::CURRENT_USER,
       installer::INSTALL_SHORTCUT_CREATE_ALL);
@@ -300,7 +277,7 @@
 
 TEST_F(InstallShortcutTest, CreateAllShortcutsButQuickLaunchShortcut) {
   scoped_ptr<installer::MasterPreferences> prefs_no_ql(
-      GetFakeMasterPrefs(false, true, false));
+      GetFakeMasterPrefs(false, true));
   installer::CreateOrUpdateShortcuts(
       chrome_exe_, *product_, *prefs_no_ql, installer::CURRENT_USER,
       installer::INSTALL_SHORTCUT_CREATE_ALL);
diff --git a/chrome/installer/setup/setup_util_unittest.cc b/chrome/installer/setup/setup_util_unittest.cc
index d8a5c85..ba79d59 100644
--- a/chrome/installer/setup/setup_util_unittest.cc
+++ b/chrome/installer/setup/setup_util_unittest.cc
@@ -243,7 +243,8 @@
 
 // Launching a subprocess at normal priority class is a noop.
 TEST(SetupUtilTest, AdjustFromNormalPriority) {
-  ASSERT_EQ(NORMAL_PRIORITY_CLASS, ::GetPriorityClass(::GetCurrentProcess()));
+  ASSERT_EQ(static_cast<DWORD>(NORMAL_PRIORITY_CLASS),
+            ::GetPriorityClass(::GetCurrentProcess()));
   EXPECT_EQ(PCCR_UNCHANGED, RelaunchAndDoProcessPriorityAdjustment());
 }
 
@@ -599,14 +600,14 @@
     RegKey key(root_, path_.c_str(), KEY_SET_VALUE);
     ASSERT_TRUE(key.Valid());
     ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(nullptr, 5U));
-    ASSERT_EQ(
-        1, base::win::RegistryValueIterator(root_, path_.c_str()).ValueCount());
+    ASSERT_EQ(1u, base::win::RegistryValueIterator(root_, path_.c_str())
+                      .ValueCount());
     ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"foo", L"bar"));
-    ASSERT_EQ(
-        2, base::win::RegistryValueIterator(root_, path_.c_str()).ValueCount());
+    ASSERT_EQ(2u, base::win::RegistryValueIterator(root_, path_.c_str())
+                      .ValueCount());
     ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"baz", L"huh"));
-    ASSERT_EQ(
-        3, base::win::RegistryValueIterator(root_, path_.c_str()).ValueCount());
+    ASSERT_EQ(3u, base::win::RegistryValueIterator(root_, path_.c_str())
+                      .ValueCount());
   }
 
   ASSERT_TRUE(RegKey(root_, path_.c_str(), KEY_WRITE).Valid());
@@ -631,7 +632,7 @@
   // Ensure that all values are absent.
   {
     base::win::RegistryValueIterator it(root_, path_.c_str());
-    ASSERT_EQ(0, it.ValueCount());
+    ASSERT_EQ(0u, it.ValueCount());
   }
 }
 
diff --git a/chrome/installer/util/app_command.cc b/chrome/installer/util/app_command.cc
index 0d6be906..66242b5 100644
--- a/chrome/installer/util/app_command.cc
+++ b/chrome/installer/util/app_command.cc
@@ -57,7 +57,7 @@
 
   command_line_.swap(cmd_line);
 
-  for (int i = 0; i < arraysize(kNameBoolVars); ++i) {
+  for (size_t i = 0; i < arraysize(kNameBoolVars); ++i) {
     DWORD value = 0;  // Set default to false.
     // Note: ReadValueDW only modifies out param on success.
     key.ReadValueDW(kNameBoolVars[i].name, &value);
@@ -83,7 +83,7 @@
                                     true)
       ->set_log_message("setting AppCommand CommandLine registry value");
 
-  for (int i = 0; i < arraysize(kNameBoolVars); ++i) {
+  for (size_t i = 0; i < arraysize(kNameBoolVars); ++i) {
     const wchar_t* var_name = kNameBoolVars[i].name;
     bool var_data = this->*(kNameBoolVars[i].data);
 
diff --git a/chrome/installer/util/browser_distribution.cc b/chrome/installer/util/browser_distribution.cc
index 3e2ef533..317086e8 100644
--- a/chrome/installer/util/browser_distribution.cc
+++ b/chrome/installer/util/browser_distribution.cc
@@ -161,16 +161,10 @@
 base::string16 BrowserDistribution::GetShortcutName(
     ShortcutType shortcut_type) {
   switch (shortcut_type) {
-    case SHORTCUT_CHROME_ALTERNATE:
-      // TODO(calamity): Change IDS_OEM_MAIN_SHORTCUT_NAME in
-      // chromium_strings.grd to "The Internet" (so that it doesn't collide with
-      // the value in google_chrome_strings.grd) then change this to
-      // installer::GetLocalizedString(IDS_OEM_MAIN_SHORTCUT_NAME_BASE)
-      return L"The Internet";
     case SHORTCUT_APP_LAUNCHER:
       return installer::GetLocalizedString(IDS_APP_LIST_SHORTCUT_NAME_BASE);
     default:
-      DCHECK_EQ(shortcut_type, SHORTCUT_CHROME);
+      DCHECK_EQ(SHORTCUT_CHROME, shortcut_type);
       return GetBaseAppName();
   }
 }
@@ -178,8 +172,7 @@
 int BrowserDistribution::GetIconIndex(ShortcutType shortcut_type) {
   if (shortcut_type == SHORTCUT_APP_LAUNCHER)
     return icon_resources::kAppLauncherIndex;
-  DCHECK(shortcut_type == SHORTCUT_CHROME ||
-         shortcut_type == SHORTCUT_CHROME_ALTERNATE) << shortcut_type;
+  DCHECK_EQ(SHORTCUT_CHROME, shortcut_type);
   return icon_resources::kApplicationIndex;
 }
 
@@ -193,7 +186,7 @@
     case SUBFOLDER_APPS:
       return installer::GetLocalizedString(IDS_APP_SHORTCUTS_SUBDIR_NAME_BASE);
     default:
-      DCHECK_EQ(subfolder_type, SUBFOLDER_CHROME);
+      DCHECK_EQ(SUBFOLDER_CHROME, subfolder_type);
       return GetShortcutName(SHORTCUT_CHROME);
   }
 }
diff --git a/chrome/installer/util/browser_distribution.h b/chrome/installer/util/browser_distribution.h
index 6bdf657..a8af2694 100644
--- a/chrome/installer/util/browser_distribution.h
+++ b/chrome/installer/util/browser_distribution.h
@@ -33,7 +33,6 @@
 
   enum ShortcutType {
     SHORTCUT_CHROME,
-    SHORTCUT_CHROME_ALTERNATE,
     SHORTCUT_APP_LAUNCHER
   };
 
@@ -82,8 +81,7 @@
   virtual base::string16 GetDisplayName();
 
   // Returns the localized name of the shortcut identified by |shortcut_type|
-  // for this distribution or empty string if |shortcut_type| is unsupported
-  // by this BrowserDistribution.
+  // for this distribution.
   virtual base::string16 GetShortcutName(ShortcutType shortcut_type);
 
   // Returns the index of the icon for the product identified by
diff --git a/chrome/installer/util/delete_tree_work_item.cc b/chrome/installer/util/delete_tree_work_item.cc
index 404f08575..7dbb9e7 100644
--- a/chrome/installer/util/delete_tree_work_item.cc
+++ b/chrome/installer/util/delete_tree_work_item.cc
@@ -33,7 +33,7 @@
     const std::vector<base::FilePath>& key_paths)
     : root_path_(root_path),
       temp_path_(temp_path),
-      copied_to_backup_(false) {
+      moved_to_backup_(false) {
   if (!SafeCast(key_paths.size(), &num_key_files_)) {
     NOTREACHED() << "Impossibly large key_paths collection";
   } else if (num_key_files_ != 0) {
@@ -111,31 +111,23 @@
   }
 
   // Now that we've taken care of the key files, take care of the rest.
-  if (!root_path_.empty() && base::PathExists(root_path_)) {
-    if (!ignore_failure_) {
-      if (!backup_path_.CreateUniqueTempDirUnderPath(temp_path_)) {
-        PLOG(ERROR) << "Failed to get backup path in folder "
-                    << temp_path_.value();
-        return false;
-      } else {
-        base::FilePath backup =
-            backup_path_.path().Append(root_path_.BaseName());
-        if (!base::CopyDirectory(root_path_, backup, true)) {
-          LOG(ERROR) << "can not copy " << root_path_.value()
-                     << " to backup path " << backup.value();
-          return false;
-        } else {
-          copied_to_backup_ = true;
-        }
-      }
-    }
-    if (!base::DeleteFile(root_path_, true)) {
-      LOG(ERROR) << "can not delete " << root_path_.value();
-      return ignore_failure_;
-    }
+  if (root_path_.empty() || !base::PathExists(root_path_))
+    return true;
+
+  if (ignore_failure_) {
+    if (DeleteRoot())
+      return true;
+    // The file cannot be removed, but perhaps it can be moved into
+    // the temporary backup path. Consumers are responsible for making
+    // a best-effort attempt to remove the backup path. SelfCleaningTempDir
+    // is generally used for the backup path, so in the
+    // worst case the file(s) will be removed after the next reboot.
+    MoveRootToBackup();
+    return true;
   }
 
-  return true;
+  // Attempt to move the root to the backup.
+  return MoveRootToBackup();
 }
 
 // If there are files in backup paths move them back.
@@ -143,9 +135,9 @@
   if (ignore_failure_)
     return;
 
-  if (copied_to_backup_) {
-    DCHECK(!backup_path_.path().empty());
-    base::FilePath backup = backup_path_.path().Append(root_path_.BaseName());
+  if (moved_to_backup_) {
+    base::FilePath backup = GetBackupPath();
+    DCHECK(!backup.empty());
     if (base::PathExists(backup))
       base::Move(backup, root_path_);
   }
@@ -165,3 +157,34 @@
     }
   }
 }
+
+base::FilePath DeleteTreeWorkItem::GetBackupPath() {
+  if (backup_path_.path().empty() &&
+      !backup_path_.CreateUniqueTempDirUnderPath(temp_path_)) {
+    PLOG(ERROR) << "Failed to get backup path in folder " << temp_path_.value();
+    return base::FilePath();
+  }
+
+  DCHECK(!backup_path_.path().empty());
+  return backup_path_.path().Append(root_path_.BaseName());
+}
+
+bool DeleteTreeWorkItem::DeleteRoot() {
+  if (base::DeleteFile(root_path_, true))
+    return true;
+  LOG(ERROR) << "Failed to delete " << root_path_.value();
+  return false;
+}
+
+bool DeleteTreeWorkItem::MoveRootToBackup() {
+  base::FilePath backup = GetBackupPath();
+  if (backup.empty())
+    return false;
+  if (base::Move(root_path_, backup)) {
+    moved_to_backup_ = true;
+    return true;
+  }
+  PLOG(ERROR) << "Failed to move " << root_path_.value()
+              << " to backup path " << backup.value();
+  return false;
+}
diff --git a/chrome/installer/util/delete_tree_work_item.h b/chrome/installer/util/delete_tree_work_item.h
index e233af51..b059431 100644
--- a/chrome/installer/util/delete_tree_work_item.h
+++ b/chrome/installer/util/delete_tree_work_item.h
@@ -28,10 +28,23 @@
  private:
   friend class WorkItem;
 
+  // |root_path| will be moved to |temp_path| (rather than copied there and then
+  // deleted). For best results in this case, |root_path| and |temp_path|
+  // should be on the same volume; otherwise, the move will be simulated
+  // by a copy-and-delete operation.
   DeleteTreeWorkItem(const base::FilePath& root_path,
                      const base::FilePath& temp_path,
                      const std::vector<base::FilePath>& key_paths);
 
+  // Return temporary path for work based on |backup_path_| and |root_path_|.
+  base::FilePath GetBackupPath();
+
+  // Attempts to delete |root_path_|. Returns true on success.
+  bool DeleteRoot();
+
+  // Attempts to move |root_path_| to backup. Returns true on success.
+  bool MoveRootToBackup();
+
   // Root path to delete.
   base::FilePath root_path_;
 
@@ -53,8 +66,8 @@
   // The temporary directory into which the original root_path_ has been moved.
   base::ScopedTempDir backup_path_;
 
-  // Set to true once root_path_ has been copied into backup_path_.
-  bool copied_to_backup_;
+  // Set to true once root_path_ has been moved into backup_path_.
+  bool moved_to_backup_;
 };
 
 #endif  // CHROME_INSTALLER_UTIL_DELETE_TREE_WORK_ITEM_H_
diff --git a/chrome/installer/util/delete_tree_work_item_unittest.cc b/chrome/installer/util/delete_tree_work_item_unittest.cc
index 48f321f4..e8bc9cd4 100644
--- a/chrome/installer/util/delete_tree_work_item_unittest.cc
+++ b/chrome/installer/util/delete_tree_work_item_unittest.cc
@@ -207,6 +207,20 @@
     EXPECT_FALSE(work_item->Do());
   }
 
+  {
+    base::ScopedTempDir temp_dir;
+    ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+    // No key paths, the deletion should succeed.
+    std::vector<base::FilePath> key_paths;
+    scoped_ptr<DeleteTreeWorkItem> work_item(
+        WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, temp_dir.path(),
+        key_paths));
+
+    EXPECT_TRUE(work_item->Do());
+    work_item->Rollback();
+  }
+
   // verify everything is still there.
   EXPECT_TRUE(base::PathExists(key_path));
   EXPECT_TRUE(base::PathExists(file_name_delete_1));
diff --git a/chrome/installer/util/google_chrome_distribution.cc b/chrome/installer/util/google_chrome_distribution.cc
index 86e53da9..49490d4 100644
--- a/chrome/installer/util/google_chrome_distribution.cc
+++ b/chrome/installer/util/google_chrome_distribution.cc
@@ -158,14 +158,11 @@
     ShortcutType shortcut_type) {
   int string_id = IDS_PRODUCT_NAME_BASE;
   switch (shortcut_type) {
-    case SHORTCUT_CHROME_ALTERNATE:
-      string_id = IDS_OEM_MAIN_SHORTCUT_NAME_BASE;
-      break;
     case SHORTCUT_APP_LAUNCHER:
       string_id = IDS_APP_LIST_SHORTCUT_NAME_BASE;
       break;
     default:
-      DCHECK_EQ(shortcut_type, SHORTCUT_CHROME);
+      DCHECK_EQ(SHORTCUT_CHROME, shortcut_type);
       break;
   }
   return installer::GetLocalizedString(string_id);
@@ -174,8 +171,7 @@
 int GoogleChromeDistribution::GetIconIndex(ShortcutType shortcut_type) {
   if (shortcut_type == SHORTCUT_APP_LAUNCHER)
     return icon_resources::kAppLauncherIndex;
-  DCHECK(shortcut_type == SHORTCUT_CHROME ||
-         shortcut_type == SHORTCUT_CHROME_ALTERNATE) << shortcut_type;
+  DCHECK_EQ(SHORTCUT_CHROME, shortcut_type);
   return icon_resources::kApplicationIndex;
 }
 
diff --git a/chrome/installer/util/google_chrome_sxs_distribution.cc b/chrome/installer/util/google_chrome_sxs_distribution.cc
index 421d240..471f880 100644
--- a/chrome/installer/util/google_chrome_sxs_distribution.cc
+++ b/chrome/installer/util/google_chrome_sxs_distribution.cc
@@ -36,14 +36,11 @@
 base::string16 GoogleChromeSxSDistribution::GetShortcutName(
     ShortcutType shortcut_type) {
   switch (shortcut_type) {
-    case SHORTCUT_CHROME_ALTERNATE:
-      // There is no alternate shortcut name on SxS Chrome.
-      return base::string16();
     case SHORTCUT_APP_LAUNCHER:
       return installer::GetLocalizedString(
           IDS_APP_LIST_SHORTCUT_NAME_CANARY_BASE);
     default:
-      DCHECK_EQ(shortcut_type, SHORTCUT_CHROME);
+      DCHECK_EQ(SHORTCUT_CHROME, shortcut_type);
       return installer::GetLocalizedString(IDS_SXS_SHORTCUT_NAME_BASE);
   }
 }
@@ -90,8 +87,7 @@
 int GoogleChromeSxSDistribution::GetIconIndex(ShortcutType shortcut_type) {
   if (shortcut_type == SHORTCUT_APP_LAUNCHER)
     return icon_resources::kSxSAppLauncherIndex;
-  DCHECK(shortcut_type == SHORTCUT_CHROME ||
-         shortcut_type == SHORTCUT_CHROME_ALTERNATE) << shortcut_type;
+  DCHECK_EQ(SHORTCUT_CHROME, shortcut_type);
   return icon_resources::kSxSApplicationIndex;
 }
 
diff --git a/chrome/installer/util/installation_validator.cc b/chrome/installer/util/installation_validator.cc
index 5c0e25f..4c2aa04dc 100644
--- a/chrome/installer/util/installation_validator.cc
+++ b/chrome/installer/util/installation_validator.cc
@@ -146,7 +146,7 @@
          app_cmd.is_run_as_user(),
          "be marked to run as user"},
   };
-  for (int i = 0; i < arraysize(check_list); ++i) {
+  for (size_t i = 0; i < arraysize(check_list); ++i) {
     bool expected = flags_exp.find(check_list[i].exp_key) != flags_exp.end();
     if (check_list[i].val != expected) {
       *is_valid = false;
diff --git a/chrome/installer/util/installer_state.cc b/chrome/installer/util/installer_state.cc
index d6175e5e..90c868c 100644
--- a/chrome/installer/util/installer_state.cc
+++ b/chrome/installer/util/installer_state.cc
@@ -521,7 +521,7 @@
     installer::kChromeOldExe,
   };
 
-  for (int i = 0; i < arraysize(kChromeFilenames); ++i) {
+  for (size_t i = 0; i < arraysize(kChromeFilenames); ++i) {
     base::FilePath chrome_exe(target_path().Append(kChromeFilenames[i]));
     scoped_ptr<FileVersionInfo> file_version_info(
         FileVersionInfo::CreateFileVersionInfo(chrome_exe));
diff --git a/chrome/installer/util/master_preferences.cc b/chrome/installer/util/master_preferences.cc
index 6e3daf6..13c5cc0e 100644
--- a/chrome/installer/util/master_preferences.cc
+++ b/chrome/installer/util/master_preferences.cc
@@ -146,7 +146,7 @@
   };
 
   std::string name(installer::master_preferences::kDistroDict);
-  for (int i = 0; i < arraysize(translate_switches); ++i) {
+  for (size_t i = 0; i < arraysize(translate_switches); ++i) {
     if (cmd_line.HasSwitch(translate_switches[i].cmd_line_switch)) {
       name.assign(installer::master_preferences::kDistroDict);
       name.append(".").append(translate_switches[i].distribution_switch);
diff --git a/chrome/installer/util/master_preferences.h b/chrome/installer/util/master_preferences.h
index 0c375c3..8304890 100644
--- a/chrome/installer/util/master_preferences.h
+++ b/chrome/installer/util/master_preferences.h
@@ -35,7 +35,6 @@
 //
 // {
 //   "distribution": {
-//      "alternate_shortcut_text": false,
 //      "chrome_shortcut_icon_index": 0,
 //      "create_all_shortcuts": true,
 //      "import_bookmarks": false,
diff --git a/chrome/installer/util/master_preferences_constants.cc b/chrome/installer/util/master_preferences_constants.cc
index 0e7bcc8..f201fad7 100644
--- a/chrome/installer/util/master_preferences_constants.cc
+++ b/chrome/installer/util/master_preferences_constants.cc
@@ -6,7 +6,6 @@
 
 namespace installer {
 namespace master_preferences {
-  const char kAltShortcutText[] = "alternate_shortcut_text";
   const char kChrome[] = "chrome";
   const char kChromeShortcutIconIndex[] = "chrome_shortcut_icon_index";
   const char kCreateAllShortcuts[] = "create_all_shortcuts";
diff --git a/chrome/installer/util/master_preferences_constants.h b/chrome/installer/util/master_preferences_constants.h
index dbdd1dce..4b9029a 100644
--- a/chrome/installer/util/master_preferences_constants.h
+++ b/chrome/installer/util/master_preferences_constants.h
@@ -15,8 +15,6 @@
 // is specified in master preference as well as command line, the command line
 // value takes precedence.
 
-// Boolean. Use alternate text for the shortcut. Cmd line override present.
-extern const char kAltShortcutText[];
 // Boolean. This is to be a Chrome install. (When using MultiInstall)
 extern const char kChrome[];
 // Integer. Icon index from chrome.exe to use for shortcuts.
diff --git a/chrome/installer/util/master_preferences_unittest.cc b/chrome/installer/util/master_preferences_unittest.cc
index de28bbd..ebe28ff 100644
--- a/chrome/installer/util/master_preferences_unittest.cc
+++ b/chrome/installer/util/master_preferences_unittest.cc
@@ -68,7 +68,6 @@
       "     \"system_level\": true,\n"
       "     \"verbose_logging\": true,\n"
       "     \"require_eula\": true,\n"
-      "     \"alternate_shortcut_text\": true,\n"
       "     \"chrome_shortcut_icon_index\": 1,\n"
       "     \"ping_delay\": 40\n"
       "  },\n"
@@ -98,7 +97,6 @@
       installer::master_preferences::kSystemLevel,
       installer::master_preferences::kVerboseLogging,
       installer::master_preferences::kRequireEula,
-      installer::master_preferences::kAltShortcutText,
   };
 
   for (int i = 0; i < arraysize(expected_true); ++i) {
diff --git a/chrome/installer/util/prebuild/create_string_rc.py b/chrome/installer/util/prebuild/create_string_rc.py
index 032549b..3ea154a 100755
--- a/chrome/installer/util/prebuild/create_string_rc.py
+++ b/chrome/installer/util/prebuild/create_string_rc.py
@@ -63,7 +63,6 @@
   'IDS_INSTALL_INSUFFICIENT_RIGHTS',
   'IDS_INSTALL_NO_PRODUCTS_TO_UPDATE',
   'IDS_INSTALL_MULTI_INSTALLATION_EXISTS',
-  'IDS_OEM_MAIN_SHORTCUT_NAME',
   'IDS_SHORTCUT_TOOLTIP',
   'IDS_SHORTCUT_NEW_WINDOW',
   'IDS_APP_LIST_SHORTCUT_NAME',
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index 1174117..d40272f6 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -1640,8 +1640,7 @@
   // HKCU has precedence over HKLM for these registrations: http://goo.gl/xjczJ.
   // Look in HKCU second to override any identical values found in HKLM.
   const HKEY roots[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER };
-  for (int i = 0; i < arraysize(roots); ++i) {
-    const HKEY root = roots[i];
+  for (const HKEY root : roots) {
     for (base::win::RegistryKeyIterator iter(root, base_key.c_str());
          iter.Valid(); ++iter) {
       client_path.assign(base_key).append(1, L'\\').append(iter.Name());
diff --git a/chrome/installer/util/user_experiment.cc b/chrome/installer/util/user_experiment.cc
index af0bb684..6b796a2 100644
--- a/chrome/installer/util/user_experiment.cc
+++ b/chrome/installer/util/user_experiment.cc
@@ -350,7 +350,7 @@
   if (!GoogleUpdateSettings::GetBrand(&brand))
     brand.clear();  // Could still be viable for catch-all rules
 
-  for (int i = 0; i < arraysize(kExperiments); ++i) {
+  for (size_t i = 0; i < arraysize(kExperiments); ++i) {
     base::string16 experiment_locale = kExperiments[i].locale;
     if (experiment_locale != locale && experiment_locale != L"*")
       continue;
diff --git a/chrome/renderer/autofill/form_autocomplete_browsertest.cc b/chrome/renderer/autofill/form_autocomplete_browsertest.cc
index 3ce69aa..ac7e4995 100644
--- a/chrome/renderer/autofill/form_autocomplete_browsertest.cc
+++ b/chrome/renderer/autofill/form_autocomplete_browsertest.cc
@@ -387,6 +387,68 @@
   VerifyNoSubmitMessagesReceived(render_thread_.get());
 }
 
+// Test that a FocusNoLongerOnForm message is sent if focus goes from an
+// interacted form to an element outside the form.
+TEST_F(FormAutocompleteTest,
+       InteractedFormNoLongerFocused_FocusNoLongerOnForm) {
+  // Load a form.
+  LoadHTML(
+      "<html><input type='text' id='different'/>"
+      "<form id='myForm' action='http://example.com/blade.php'>"
+      "<input name='fname' id='fname' value='Bob'/>"
+      "<input name='lname' value='Deckard'/><input type=submit></form></html>");
+
+  // Simulate user input so that the form is "remembered".
+  WebDocument document = GetMainFrame()->document();
+  WebElement element = document.getElementById(WebString::fromUTF8("fname"));
+  ASSERT_FALSE(element.isNull());
+  WebInputElement fname_element = element.to<WebInputElement>();
+  SimulateUserInputChangeForElement(&fname_element, std::string("Rick"));
+
+  // Change focus to a different node outside the form.
+  WebElement different =
+      document.getElementById(WebString::fromUTF8("different"));
+  SetFocused(different);
+
+  ProcessPendingMessages();
+
+  EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching(
+                  AutofillHostMsg_FocusNoLongerOnForm::ID) != nullptr);
+}
+
+// Test that a FocusNoLongerOnForm message is sent if focus goes from one
+// interacted form to another.
+TEST_F(FormAutocompleteTest, InteractingInDifferentForms_FocusNoLongerOnForm) {
+  // Load a form.
+  LoadHTML(
+      "<html><form id='myForm' action='http://example.com/blade.php'>"
+      "<input name='fname' id='fname' value='Bob'/>"
+      "<input name='lname' value='Deckard'/><input type=submit></form>"
+      "<form id='myForm2' action='http://example.com/runner.php'>"
+      "<input name='fname' id='fname2' value='Bob'/>"
+      "<input name='lname' value='Deckard'/><input type=submit></form></html>");
+
+  // Simulate user input in the first form so that the form is "remembered".
+  WebDocument document = GetMainFrame()->document();
+  WebElement element = document.getElementById(WebString::fromUTF8("fname"));
+  ASSERT_FALSE(element.isNull());
+  WebInputElement fname_element = element.to<WebInputElement>();
+  SimulateUserInputChangeForElement(&fname_element, std::string("Rick"));
+
+  // Simulate user input in the second form so that a "no longer focused"
+  // message is sent for the first form.
+  document = GetMainFrame()->document();
+  element = document.getElementById(WebString::fromUTF8("fname2"));
+  ASSERT_FALSE(element.isNull());
+  fname_element = element.to<WebInputElement>();
+  SimulateUserInputChangeForElement(&fname_element, std::string("John"));
+
+  ProcessPendingMessages();
+
+  EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching(
+                  AutofillHostMsg_FocusNoLongerOnForm::ID) != nullptr);
+}
+
 // Tests that submitting a form that has autocomplete="off" generates
 // WillSubmitForm and FormSubmitted messages.
 TEST_F(FormAutocompleteTest, AutoCompleteOffFormSubmit) {
diff --git a/chrome/renderer/extensions/cast_streaming_native_handler.cc b/chrome/renderer/extensions/cast_streaming_native_handler.cc
index b861f826..ec51402 100644
--- a/chrome/renderer/extensions/cast_streaming_native_handler.cc
+++ b/chrome/renderer/extensions/cast_streaming_native_handler.cc
@@ -4,8 +4,11 @@
 
 #include "chrome/renderer/extensions/cast_streaming_native_handler.h"
 
+#include <algorithm>
 #include <functional>
 #include <iterator>
+#include <string>
+#include <vector>
 
 #include "base/location.h"
 #include "base/logging.h"
@@ -89,6 +92,9 @@
   cast_params->max_latency_ms = ext_params.max_latency;
   cast_params->min_latency_ms =
       ext_params.min_latency ? *ext_params.min_latency : ext_params.max_latency;
+  cast_params->animated_latency_ms = ext_params.animated_latency
+                                         ? *ext_params.animated_latency
+                                         : ext_params.max_latency;
   cast_params->codec_name = ext_params.codec_name;
   cast_params->ssrc = ext_params.ssrc;
   cast_params->feedback_ssrc = ext_params.feedback_ssrc;
@@ -126,6 +132,7 @@
   ext_params->payload_type = cast_params.payload_type;
   ext_params->max_latency = cast_params.max_latency_ms;
   ext_params->min_latency.reset(new int(cast_params.min_latency_ms));
+  ext_params->animated_latency.reset(new int(cast_params.animated_latency_ms));
   ext_params->codec_name = cast_params.codec_name;
   ext_params->ssrc = cast_params.ssrc;
   ext_params->feedback_ssrc = cast_params.feedback_ssrc;
diff --git a/chrome/renderer/extensions/chrome_extensions_renderer_client.cc b/chrome/renderer/extensions/chrome_extensions_renderer_client.cc
index 2327e42..adf845c 100644
--- a/chrome/renderer/extensions/chrome_extensions_renderer_client.cc
+++ b/chrome/renderer/extensions/chrome_extensions_renderer_client.cc
@@ -72,18 +72,12 @@
   if (is_initial_navigation && old_url.is_empty() && frame->opener()) {
     blink::WebLocalFrame* opener_frame = frame->opener()->toWebLocalFrame();
 
-    // We usually want to compare against the URL that determines the type of
-    // process.  In default Chrome, that's the URL of the opener's top frame and
-    // not the opener frame itself.  In --site-per-process, we can use the
-    // opener frame itself.
-    // TODO(nick): Either wire this up to SiteIsolationPolicy, or to state on
-    // |opener_frame|/its ancestors.
-    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kSitePerProcess) ||
-        extensions::IsIsolateExtensionsEnabled())
-      old_url = opener_frame->document().url();
-    else
-      old_url = opener_frame->top()->document().url();
+    // We want to compare against the URL that determines the type of
+    // process.  Use the URL of the opener's local frame root, which will
+    // correctly handle any site isolation modes (--site-per-process and
+    // --isolate-extensions).
+    blink::WebLocalFrame* local_root = opener_frame->localRoot();
+    old_url = local_root->document().url();
 
     // If we're about to open a normal web page from a same-origin opener stuck
     // in an extension process (other than the Chrome Web Store), we want to
diff --git a/chrome/renderer/extensions/renderer_permissions_policy_delegate_unittest.cc b/chrome/renderer/extensions/renderer_permissions_policy_delegate_unittest.cc
index a2cee09..1dd8737 100644
--- a/chrome/renderer/extensions/renderer_permissions_policy_delegate_unittest.cc
+++ b/chrome/renderer/extensions/renderer_permissions_policy_delegate_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/command_line.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.h"
@@ -49,10 +51,11 @@
 scoped_refptr<const Extension> CreateTestExtension(const std::string& id) {
   return ExtensionBuilder()
       .SetManifest(DictionaryBuilder()
-          .Set("name", "Extension with ID " + id)
-          .Set("version", "1.0")
-          .Set("manifest_version", 2)
-          .Set("permissions", ListBuilder().Append("<all_urls>")))
+                       .Set("name", "Extension with ID " + id)
+                       .Set("version", "1.0")
+                       .Set("manifest_version", 2)
+                       .Set("permissions",
+                            std::move(ListBuilder().Append("<all_urls>"))))
       .SetID(id)
       .Build();
 }
diff --git a/chrome/renderer/media/cast_rtp_stream.cc b/chrome/renderer/media/cast_rtp_stream.cc
index 8b2b84b9..ab2a3242 100644
--- a/chrome/renderer/media/cast_rtp_stream.cc
+++ b/chrome/renderer/media/cast_rtp_stream.cc
@@ -163,18 +163,35 @@
                          AudioSenderConfig* config) {
   config->ssrc = params.payload.ssrc;
   config->receiver_ssrc = params.payload.feedback_ssrc;
-  if (config->ssrc == config->receiver_ssrc)
+  if (config->ssrc == config->receiver_ssrc) {
+    DVLOG(1) << "ssrc " << config->ssrc << " cannot be equal to receiver_ssrc";
     return false;
+  }
   config->min_playout_delay = base::TimeDelta::FromMilliseconds(
                                   params.payload.min_latency_ms ?
                                   params.payload.min_latency_ms :
                                   params.payload.max_latency_ms);
   config->max_playout_delay =
       base::TimeDelta::FromMilliseconds(params.payload.max_latency_ms);
-  if (config->min_playout_delay <= base::TimeDelta())
+  config->animated_playout_delay = base::TimeDelta::FromMilliseconds(
+      params.payload.animated_latency_ms ? params.payload.animated_latency_ms
+                                         : params.payload.max_latency_ms);
+  if (config->min_playout_delay <= base::TimeDelta()) {
+    DVLOG(1) << "min_playout_delay " << config->min_playout_delay
+             << " is too small";
     return false;
-  if (config->min_playout_delay > config->max_playout_delay)
+  }
+  if (config->min_playout_delay > config->max_playout_delay) {
+    DVLOG(1) << "min_playout_delay " << config->min_playout_delay
+             << " is too big";
     return false;
+  }
+  if (config->animated_playout_delay < config->min_playout_delay ||
+      config->animated_playout_delay > config->max_playout_delay) {
+    DVLOG(1) << "animated_playout_delay " << config->animated_playout_delay
+             << " is out of range";
+    return false;
+  }
   config->rtp_payload_type = params.payload.payload_type;
   config->use_external_encoder = false;
   config->frequency = params.payload.clock_rate;
@@ -187,16 +204,21 @@
     case 8000:
       break;
     default:
+      DVLOG(1) << "frequency " << config->frequency << " is invalid";
       return false;
   }
   config->channels = params.payload.channels;
-  if (config->channels < 1)
+  if (config->channels < 1) {
+    DVLOG(1) << "channels " << config->channels << " is invalid";
     return false;
+  }
   config->bitrate = params.payload.max_bitrate * kBitrateMultiplier;
-  if (params.payload.codec_name == kCodecNameOpus)
+  if (params.payload.codec_name == kCodecNameOpus) {
     config->codec = media::cast::CODEC_AUDIO_OPUS;
-  else
+  } else {
+    DVLOG(1) << "codec_name " << params.payload.codec_name << " is invalid";
     return false;
+  }
   config->aes_key = params.payload.aes_key;
   config->aes_iv_mask = params.payload.aes_iv_mask;
   return true;
@@ -206,29 +228,51 @@
                          VideoSenderConfig* config) {
   config->ssrc = params.payload.ssrc;
   config->receiver_ssrc = params.payload.feedback_ssrc;
-  if (config->ssrc == config->receiver_ssrc)
+  if (config->ssrc == config->receiver_ssrc) {
+    DVLOG(1) << "ssrc " << config->ssrc << " cannot be equal to receiver_ssrc";
     return false;
+  }
   config->min_playout_delay = base::TimeDelta::FromMilliseconds(
                                   params.payload.min_latency_ms ?
                                   params.payload.min_latency_ms :
                                   params.payload.max_latency_ms);
   config->max_playout_delay =
       base::TimeDelta::FromMilliseconds(params.payload.max_latency_ms);
-  if (config->min_playout_delay <= base::TimeDelta())
+  config->animated_playout_delay = base::TimeDelta::FromMilliseconds(
+      params.payload.animated_latency_ms ? params.payload.animated_latency_ms
+                                         : params.payload.max_latency_ms);
+  if (config->min_playout_delay <= base::TimeDelta()) {
+    DVLOG(1) << "min_playout_delay " << config->min_playout_delay
+             << " is too small";
     return false;
-  if (config->min_playout_delay > config->max_playout_delay)
+  }
+  if (config->min_playout_delay > config->max_playout_delay) {
+    DVLOG(1) << "min_playout_delay " << config->min_playout_delay
+             << " is too big";
     return false;
+  }
+  if (config->animated_playout_delay < config->min_playout_delay ||
+      config->animated_playout_delay > config->max_playout_delay) {
+    DVLOG(1) << "animated_playout_delay " << config->animated_playout_delay
+             << " is out of range";
+    return false;
+  }
   config->rtp_payload_type = params.payload.payload_type;
   config->min_bitrate = config->start_bitrate =
       params.payload.min_bitrate * kBitrateMultiplier;
   config->max_bitrate = params.payload.max_bitrate * kBitrateMultiplier;
-  if (config->min_bitrate > config->max_bitrate)
+  if (config->min_bitrate > config->max_bitrate) {
+    DVLOG(1) << "min_bitrate " << config->min_bitrate << " is larger than "
+             << "max_bitrate " << config->max_bitrate;
     return false;
+  }
   config->start_bitrate = config->min_bitrate;
   config->max_frame_rate = static_cast<int>(
       std::max(1.0, params.payload.max_frame_rate) + 0.5);
-  if (config->max_frame_rate > media::limits::kMaxFramesPerSecond)
+  if (config->max_frame_rate > media::limits::kMaxFramesPerSecond) {
+    DVLOG(1) << "max_frame_rate " << config->max_frame_rate << " is invalid";
     return false;
+  }
   if (params.payload.codec_name == kCodecNameVp8) {
     config->use_external_encoder = IsHardwareVP8EncodingSupported();
     config->codec = media::cast::CODEC_VIDEO_VP8;
@@ -236,6 +280,7 @@
     config->use_external_encoder = IsHardwareH264EncodingSupported();
     config->codec = media::cast::CODEC_VIDEO_H264;
   } else {
+    DVLOG(1) << "codec_name " << params.payload.codec_name << " is invalid";
     return false;
   }
   if (!config->use_external_encoder)
diff --git a/chrome/renderer/media/cast_rtp_stream.h b/chrome/renderer/media/cast_rtp_stream.h
index 8cb9897..88ec92a 100644
--- a/chrome/renderer/media/cast_rtp_stream.h
+++ b/chrome/renderer/media/cast_rtp_stream.h
@@ -13,6 +13,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "media/cast/cast_config.h"
+#include "media/cast/constants.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
 
 namespace base {
@@ -36,36 +38,40 @@
 // Defines the basic properties of a payload supported by cast transport.
 struct CastRtpPayloadParams {
   // RTP specific field that identifies the content type.
-  int payload_type;
+  int payload_type = media::cast::kDefaultRtpVideoPayloadType;
 
   // Maximum latency in milliseconds. Implemetation tries to keep latency
   // under this threshold.
-  int max_latency_ms;
+  int max_latency_ms = media::cast::kDefaultRtpMaxDelayMs;
 
   // Minimum latency.
   // Default value (0) means use max_latency_ms.
-  int min_latency_ms;
+  int min_latency_ms = 0;
+
+  // Starting latency on animated content.
+  // Default value (0) means use max_latency_ms.
+  int animated_latency_ms = 0;
 
   // RTP specific field to identify a stream.
-  int ssrc;
+  int ssrc = 1;
 
   // RTP specific field to idenfity the feedback stream.
-  int feedback_ssrc;
+  int feedback_ssrc = 2;
 
   // Update frequency of payload sample.
-  int clock_rate;
+  int clock_rate = media::cast::kVideoFrequency;
 
   // Maximum bitrate in kilobits per second.
-  int max_bitrate;
+  int max_bitrate = media::cast::kDefaultMaxVideoKbps;
 
   // Minimum bitrate in kilobits per second.
-  int min_bitrate;
+  int min_bitrate = media::cast::kDefaultMinVideoKbps;
 
   // Number of audio channels.
-  int channels;
+  int channels = 1;
 
   // The maximum frame rate.
-  double max_frame_rate;
+  double max_frame_rate = media::cast::kDefaultMaxFrameRate;
 
   // Name of the codec used.
   std::string codec_name;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 3670d55..4bb41f4 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -225,7 +225,17 @@
   }
 
   if (use_ash) {
-    public_deps += [ "//ash:test_support" ]
+    sources += [
+      "base/default_ash_event_generator_delegate.cc",
+      "base/default_ash_event_generator_delegate.h",
+    ]
+
+    public_deps += [
+      "//ash",
+      "//ash:test_support",
+      "//ui/aura",
+      "//ui/aura:test_support",
+    ]
   }
   if (toolkit_views) {
     public_deps += [ "//ui/views:test_support" ]
@@ -846,6 +856,7 @@
       "//ppapi/tests/test_page.css.mock-http-headers",
       "//testing/test_env.py",
       "//third_party/accessibility-audit/axs_testing.js",
+      "//third_party/chaijs/chai.js",
       "//third_party/mocha/mocha.js",
       "//third_party/pyftpdlib/",
       "//third_party/pywebsocket/",
@@ -1543,6 +1554,7 @@
     "//net/data/",
     "//net/tools/testserver/",
     "//third_party/accessibility-audit/axs_testing.js",
+    "//third_party/chaijs/chai.js",
     "//third_party/hunspell_dictionaries/",
     "//third_party/pyftpdlib/",
     "//third_party/pywebsocket/",
diff --git a/chrome/test/base/default_ash_event_generator_delegate.cc b/chrome/test/base/default_ash_event_generator_delegate.cc
new file mode 100644
index 0000000..26a909c
--- /dev/null
+++ b/chrome/test/base/default_ash_event_generator_delegate.cc
@@ -0,0 +1,53 @@
+// 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/test/base/default_ash_event_generator_delegate.h"
+
+#include "chrome/browser/ui/host_desktop.h"
+
+DefaultAshEventGeneratorDelegate*
+DefaultAshEventGeneratorDelegate::GetInstance() {
+  return base::Singleton<DefaultAshEventGeneratorDelegate>::get();
+}
+
+void DefaultAshEventGeneratorDelegate::SetContext(
+    ui::test::EventGenerator* owner,
+    gfx::NativeWindow root_window,
+    gfx::NativeWindow window) {
+  root_window_ = root_window;
+}
+
+aura::WindowTreeHost* DefaultAshEventGeneratorDelegate::GetHostAt(
+    const gfx::Point& point) const {
+  return root_window_->GetHost();
+}
+
+aura::client::ScreenPositionClient*
+DefaultAshEventGeneratorDelegate::GetScreenPositionClient(
+    const aura::Window* window) const {
+  return nullptr;
+}
+
+void DefaultAshEventGeneratorDelegate::DispatchKeyEventToIME(
+    ui::EventTarget* target,
+    ui::KeyEvent* event) {
+  // In Ash environment, the key event will be processed by event rewriters
+  // first and event will not be hanlded.
+  // Otherwise, use EventGeneratorDelegateAura::DispatchKeyEventToIME() to
+  // dispatch |event| to the input method.
+  if (chrome::GetActiveDesktop() != chrome::HOST_DESKTOP_TYPE_ASH) {
+    EventGeneratorDelegateAura::DispatchKeyEventToIME(target, event);
+  }
+}
+
+DefaultAshEventGeneratorDelegate::DefaultAshEventGeneratorDelegate()
+    : root_window_(nullptr) {
+  DCHECK(!ui::test::EventGenerator::default_delegate);
+  ui::test::EventGenerator::default_delegate = this;
+}
+
+DefaultAshEventGeneratorDelegate::~DefaultAshEventGeneratorDelegate() {
+  DCHECK_EQ(this, ui::test::EventGenerator::default_delegate);
+  ui::test::EventGenerator::default_delegate = nullptr;
+}
diff --git a/chrome/test/base/default_ash_event_generator_delegate.h b/chrome/test/base/default_ash_event_generator_delegate.h
new file mode 100644
index 0000000..54c543c3
--- /dev/null
+++ b/chrome/test/base/default_ash_event_generator_delegate.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 CHROME_TEST_BASE_DEFAULT_ASH_EVENT_GENERATOR_DELEGATE_H_
+#define CHROME_TEST_BASE_DEFAULT_ASH_EVENT_GENERATOR_DELEGATE_H_
+
+#include "ash/shell.h"
+#include "base/macros.h"
+#include "base/memory/singleton.h"
+#include "ui/aura/test/event_generator_delegate_aura.h"
+#include "ui/aura/window.h"
+
+class DefaultAshEventGeneratorDelegate
+    : public aura::test::EventGeneratorDelegateAura {
+ public:
+  static DefaultAshEventGeneratorDelegate* GetInstance();
+
+  // EventGeneratorDelegate:
+  void SetContext(ui::test::EventGenerator* owner,
+                  gfx::NativeWindow root_window,
+                  gfx::NativeWindow window) override;
+
+  aura::WindowTreeHost* GetHostAt(const gfx::Point& point) const override;
+
+  aura::client::ScreenPositionClient* GetScreenPositionClient(
+      const aura::Window* window) const override;
+
+  void DispatchKeyEventToIME(ui::EventTarget* target,
+                             ui::KeyEvent* event) override;
+
+ private:
+  friend struct base::DefaultSingletonTraits<DefaultAshEventGeneratorDelegate>;
+
+  DefaultAshEventGeneratorDelegate();
+
+  ~DefaultAshEventGeneratorDelegate() override;
+
+  aura::Window* root_window_;
+
+  DISALLOW_COPY_AND_ASSIGN(DefaultAshEventGeneratorDelegate);
+};
+
+#endif  // CHROME_TEST_BASE_DEFAULT_ASH_EVENT_GENERATOR_DELEGATE_H_
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc
index 14c145a..be1898c 100644
--- a/chrome/test/base/in_process_browser_test.cc
+++ b/chrome/test/base/in_process_browser_test.cc
@@ -83,6 +83,10 @@
 #include "chrome/browser/chromeos/input_method/input_method_configuration.h"
 #endif
 
+#if defined(USE_ASH)
+#include "chrome/test/base/default_ash_event_generator_delegate.h"
+#endif
+
 namespace {
 
 // Passed as value of kTestType.
@@ -196,6 +200,10 @@
 #if defined(OS_MACOSX)
   bundle_swizzler_.reset(new ScopedBundleSwizzlerMac);
 #endif
+
+#if defined(USE_ASH)
+  DefaultAshEventGeneratorDelegate::GetInstance();
+#endif
 }
 
 InProcessBrowserTest::~InProcessBrowserTest() {
diff --git a/chrome/test/base/javascript_browser_test.cc b/chrome/test/base/javascript_browser_test.cc
index 3eeb0e3a..022956d 100644
--- a/chrome/test/base/javascript_browser_test.cc
+++ b/chrome/test/base/javascript_browser_test.cc
@@ -16,6 +16,10 @@
         FILE_PATH_LITERAL("third_party/accessibility-audit/axs_testing.js");
 
 // static
+const base::FilePath::CharType JavaScriptBrowserTest::kChaiJSPath[] =
+    FILE_PATH_LITERAL("third_party/chaijs/chai.js");
+
+// static
 const base::FilePath::CharType JavaScriptBrowserTest::kMockJSPath[] =
     FILE_PATH_LITERAL("chrome/third_party/mock4js/mock4js.js");
 
@@ -53,6 +57,7 @@
   library_search_paths_.push_back(source_root_directory);
 
   AddLibrary(base::FilePath(kMockJSPath));
+  AddLibrary(base::FilePath(kChaiJSPath));
   AddLibrary(base::FilePath(kWebUILibraryJS));
 }
 
diff --git a/chrome/test/base/javascript_browser_test.h b/chrome/test/base/javascript_browser_test.h
index b04170c..7eb9c01f 100644
--- a/chrome/test/base/javascript_browser_test.h
+++ b/chrome/test/base/javascript_browser_test.h
@@ -14,6 +14,7 @@
 class JavaScriptBrowserTest : public InProcessBrowserTest {
  public:
   static const base::FilePath::CharType kA11yAuditLibraryJSPath[];
+  static const base::FilePath::CharType kChaiJSPath[];
   static const base::FilePath::CharType kMockJSPath[];
   static const base::FilePath::CharType kWebUILibraryJS[];
   static const base::FilePath::CharType kWebUITestFolder[];
diff --git a/chrome/test/base/v8_unit_test.cc b/chrome/test/base/v8_unit_test.cc
index 621c09a..9f52f06 100644
--- a/chrome/test/base/v8_unit_test.cc
+++ b/chrome/test/base/v8_unit_test.cc
@@ -151,6 +151,10 @@
                      .AppendASCII("mock4js.js"));
 
   AddLibrary(src_root.AppendASCII("third_party")
+                     .AppendASCII("chaijs")
+                     .AppendASCII("chai.js"));
+
+  AddLibrary(src_root.AppendASCII("third_party")
                      .AppendASCII("accessibility-audit")
                      .AppendASCII("axs_testing.js"));
 
diff --git a/chrome/test/chromedriver/js/call_function.js b/chrome/test/chromedriver/js/call_function.js
index 17a0ae5..bd8ec2d2 100644
--- a/chrome/test/chromedriver/js/call_function.js
+++ b/chrome/test/chromedriver/js/call_function.js
@@ -160,8 +160,17 @@
     }
 
     var obj = (typeof(value.length) == 'number') ? [] : {};
-    for (var prop in value)
-      obj[prop] = wrap(value[prop]);
+    for (var prop in value) {
+      if (typeof(value[prop]) === 'function') {
+        // For functions, no need for further wrapping.
+        var wrapped = {};
+        wrapped[ELEMENT_KEY] = getPageCache().storeItem(value[prop]);
+        obj[prop] = wrapped;
+        continue;
+      }
+
+      obj[prop] = wrap(value[prop])
+    }
     return obj;
   }
   return value;
@@ -181,8 +190,14 @@
       return cache.retrieveItem(value[ELEMENT_KEY]);
 
     var obj = (typeof(value.length) == 'number') ? [] : {};
-    for (var prop in value)
+    for (var prop in value) {
+      if (typeof(value[prop]) === 'function') {
+        obj[prop] = value[prop];
+        continue;
+      }
+
       obj[prop] = unwrap(value[prop], cache);
+    }
     return obj;
   }
   return value;
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 5d6dbaf..668de9a2 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -1200,6 +1200,13 @@
     self._driver.Load('http://invalid./')
     self.assertEquals('http://invalid./', self._driver.GetCurrentUrl())
 
+  def testReturningAFunctionInJavascript(self):
+    self._driver.Log(self.GetHttpUrlForFile(
+        '/chromedriver/circularly_self_reference_function.html'))
+    func = self.driver.ExecuteScript('return func;')
+    self.assertEquals(
+        1, self._driver.ExecuteScript('return arguments[0]();', func))
+
 
 class ChromeDriverAndroidTest(ChromeDriverBaseTest):
   """End to end tests for Android-specific tests."""
diff --git a/chrome/test/data/chromedriver/circularly_self_reference_function.html b/chrome/test/data/chromedriver/circularly_self_reference_function.html
new file mode 100644
index 0000000..963931e0
--- /dev/null
+++ b/chrome/test/data/chromedriver/circularly_self_reference_function.html
@@ -0,0 +1,6 @@
+<script>
+  var func = function() {
+    return 1;
+  };
+  func.referToSelf = func;
+</script>
diff --git a/chrome/test/data/extensions/api_test/service_worker/update/service_worker.pem b/chrome/test/data/extensions/api_test/service_worker/update/service_worker.pem
new file mode 100644
index 0000000..5b869cd6
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/service_worker/update/service_worker.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDbpb02/Z+wFB/1
+KlBXh55sJDq307K3BjsO1Ye591tcJyIZu/MzRE5Gbrpc47OdrmJtupcwicPLbaLh
+fciNU/ri87kXjnYLY6gKfmqJnjS0cNyS8El1qHLCYmp8VO1+0zYYScfvRb3R0twA
+o1OFWStCEN7DVGUDrCvA41dILMB/FzPV6Kvki73Gry1uvIwcO2du8vxoYD9tGsZu
+Jnjnz9nTtaZgckR+KWgkgfBxcXyA7ukoTkwqwLqtAwX3sgyFetHkU0em0jYqE7/J
+Z8zXVcn8K5W01PcTbH6rslZaM3ZOgpFjKldRzy/jqngFlnb+AqVBCkr/MTpCVzMl
+9IcUViFRAgMBAAECggEASjSjSTnEQlt6NHy4Keoihoxy3foCbb0IJMnVEenUjryV
+07Xgwxg3jaoJAirXWtU4YbPhMj/IyyheF+pD4CNYJmaKyL+Td+OSOQFeguHVEoTy
+sB3H450mMC/Jo/mZRviaVPhQOLEKISIou3pyVCG88JP8fmc7vVLkcUUdDsA3xHd1
+BC3zOIneWEjX3rHnNZEPZbhddXzXzQBFqre9S7o+c2zfGxV1Q3RicLc92EH2DEXy
+WiqN+ZIdybJpRMmbAG0NaR2zBcFdruB5Fb8nqGca4ScyueVbliBbU4L+TDXFYZTC
++IEJFgzST1VG35REwLVQaPT89LPXibCfRCHlJdunsQKBgQDyILfoaNiBJsYIjJIL
+hwSoUWDmBcmGbjHSLPbUibGwcg0OxFmRSAZKH/7goq6VhHXvKRNcyRfBvLPIJP0r
+nH9nGDG5809NcFaPdLHz0uY1J8Up9DolyQ3mMiv6qya921UeXOH8S4O6Mw9UnrBH
+MsRjiaPZ7pYZEPHTZYX5e11GRQKBgQDoO00wyYNb3TYufz3whfLUivywfRYCGxAw
+TyMV1ZKmPA3q8IGK6Ay74zdhWbr6hhM4r67VY1jadnbRy2mHnUiKEkQ3L+e9DVUV
+KDRVjEiaCpGA10EWvUmX4vUXlGjRkhTxSAaMRGt7p3oCkRmK28m7Gv4smMP2/Au+
+cBhsL3r1nQKBgBPo5taAkJUGKDCZxoSWJKbmki43+ZtJQmWC9wUBEZBtwG8fbDIL
+FyFPQjkch3iZ/Myetw3hJ0fyCWKC0CKe6scCcUxWGoZGn4eKU/u1suJaE9dgUsu6
+nZ75Ly6clkH0YCpv/tEtMHbGLhOKPPqNzSJWNhf8i3EiOJBmf77FCyV1AoGBANoV
+FmACXQEfs4nmo9wDbg56luGGFezUTVeQeXo/nf/N1aQTRxOS5qJqtc8N3LD2x4Ys
+NRreuMovBVXul6Nq6HwAu1639f9rTcMYhkzv+B3wXsOHYPBhwYKI93C1RdnIPTJ4
+WO3QMr9kfwd6C2qDC+ZRau+mZiDCgKTNz6GI1QdhAoGBAMjH3vPGr2CUJq7CwT39
+WLo0GPx+zWcpnqfcuVlDHzU+DiNFG11CwSxMp+BktBnTD6+2/4czY8s6a3T9jEJu
+KeM/KksWbNPoBPYYKJBEx5VkQJSyHXUn1wKFSHqqHBBoHqV64AxpzmNRBaOHvddm
+qNRSLE7MOy8oEKZahKAbq2U/
+-----END PRIVATE KEY-----
diff --git a/chrome/test/data/extensions/api_test/service_worker/update/v1/background.js b/chrome/test/data/extensions/api_test/service_worker/update/v1/background.js
new file mode 100644
index 0000000..2d1e013
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/service_worker/update/v1/background.js
@@ -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.
+
+var serviceWorkerPromise = new Promise(function(resolve, reject) {
+  navigator.serviceWorker.register('sw.js').then(function() {
+    return navigator.serviceWorker.ready;
+  }).then(function(registration) {
+    var sw = registration.active;
+    var channel = new MessageChannel();
+    channel.port1.onmessage = function(e) {
+      if (e.data == 'Pong from version 1') {
+        resolve(e.data);
+      } else {
+        reject(e.data);  // Fail fast.
+      }
+    };
+    sw.postMessage('ping', [channel.port2]);
+  }).catch(function(err) {
+    reject(err);
+  });
+});
+
+serviceWorkerPromise.then(function(message) {
+  chrome.test.sendMessage(message);
+}).catch(function(err) {
+  chrome.test.sendMessage('FAILURE_V1');
+});
diff --git a/chrome/test/data/extensions/api_test/service_worker/update/v1/manifest.json b/chrome/test/data/extensions/api_test/service_worker/update/v1/manifest.json
new file mode 100644
index 0000000..f9b4d27
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/service_worker/update/v1/manifest.json
@@ -0,0 +1,8 @@
+{
+  "name": "Service worker with extension update",
+  "version": "1.0",
+  "manifest_version": 2,
+  "background": {
+    "scripts": ["background.js"]
+  }
+}
diff --git a/chrome/test/data/extensions/api_test/service_worker/update/v1/sw.js b/chrome/test/data/extensions/api_test/service_worker/update/v1/sw.js
new file mode 100644
index 0000000..bd88370
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/service_worker/update/v1/sw.js
@@ -0,0 +1,7 @@
+// 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.
+
+this.onmessage = function(e) {
+  e.ports[0].postMessage('Pong from version 1');
+};
diff --git a/chrome/test/data/extensions/api_test/service_worker/update/v2/background.js b/chrome/test/data/extensions/api_test/service_worker/update/v2/background.js
new file mode 100644
index 0000000..8017de9
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/service_worker/update/v2/background.js
@@ -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.
+
+var controllerChangePromise = new Promise(function(resolve, reject) {
+  navigator.serviceWorker.oncontrollerchange = function(e) {
+    navigator.serviceWorker.ready.then(function(registration) {
+      resolve(registration.active);
+    }).catch(function(err) {
+      reject('oncontrollerchange failure');
+    });
+  };
+});
+
+controllerChangePromise.then(function(serviceWorker) {
+  var channel = new MessageChannel();
+  channel.port1.onmessage = function(e) {
+    chrome.test.log('Message received from SW: ' + e.data);
+    chrome.test.sendMessage(e.data);
+  };
+  serviceWorker.postMessage('ping', [channel.port2]);
+}).catch(function(err) {
+  console.log(err);
+  chrome.test.sendMessage('FAILURE_V2');
+});
diff --git a/chrome/test/data/extensions/api_test/service_worker/update/v2/manifest.json b/chrome/test/data/extensions/api_test/service_worker/update/v2/manifest.json
new file mode 100644
index 0000000..2e6b548
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/service_worker/update/v2/manifest.json
@@ -0,0 +1,8 @@
+{
+  "name": "Updated extension that uses service worker",
+  "version": "2.0",
+  "manifest_version": 2,
+  "background": {
+    "scripts": ["background.js"]
+  }
+}
diff --git a/chrome/test/data/extensions/api_test/service_worker/update/v2/sw.js b/chrome/test/data/extensions/api_test/service_worker/update/v2/sw.js
new file mode 100644
index 0000000..a33255c9
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/service_worker/update/v2/sw.js
@@ -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.
+
+this.onmessage = function(e) {
+  e.ports[0].postMessage('Pong from version 2');
+};
+
+this.oninstall = function(e) {
+  e.waitUntil(self.skipWaiting());
+};
diff --git a/chrome/test/data/extensions/app_list/Extensions/ebgmjfhpkngekpdlgfdbolkhfmofdfdf/1.0/main.js b/chrome/test/data/extensions/app_list/Extensions/ebgmjfhpkngekpdlgfdbolkhfmofdfdf/1.0/main.js
deleted file mode 100644
index af31f657..0000000
--- a/chrome/test/data/extensions/app_list/Extensions/ebgmjfhpkngekpdlgfdbolkhfmofdfdf/1.0/main.js
+++ /dev/null
@@ -1,5 +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.
-
-// Deliberately empty.
diff --git a/chrome/test/data/extensions/app_list/Extensions/ebgmjfhpkngekpdlgfdbolkhfmofdfdf/1.0/manifest.json b/chrome/test/data/extensions/app_list/Extensions/ebgmjfhpkngekpdlgfdbolkhfmofdfdf/1.0/manifest.json
deleted file mode 100644
index f4cfb3e8..0000000
--- a/chrome/test/data/extensions/app_list/Extensions/ebgmjfhpkngekpdlgfdbolkhfmofdfdf/1.0/manifest.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtd5jeTaSP38on5y28W8f5MV+F4mvYMx0kOJXp8M+EteL9x5TS3et5a7W1jnduIdGtH0Xc5WKhvUnN2nUmEqjzzdRYvzjpWrTr73oFreebqNhJP47D75HdbWZqf8iCQwVJDKxbQ6OzHG8xoWd1ksNtQGUBUhMQXOt7d4/36TbansJ5neRS2akXY8GRWkGHtRJENNy85IoeV8erZc6WTeTM/M2wK/V3j9do1RmueKBU4Dz3H8Ix5/t2mJSantOPedf2We08+7CadB32+wE90OjPcuO9itaU1lhTXiUZeISLdzZv2ybyiOglkzP+wY4dWlDsF+5/3FN7mjQuWg4vg+pgwIDAQAB",
-  "version": "1.0",
-  "name": "Ephemeral App",
-  "manifest_version": 2,
-  "app": {
-    "background": {
-      "scripts": [ "main.js" ]
-    }
-  }
-}
diff --git a/chrome/test/data/extensions/app_list/Preferences b/chrome/test/data/extensions/app_list/Preferences
index 5137d81..bb1de10 100644
--- a/chrome/test/data/extensions/app_list/Preferences
+++ b/chrome/test/data/extensions/app_list/Preferences
@@ -66,25 +66,6 @@
                 }
               }
             }
-         },
-         "ebgmjfhpkngekpdlgfdbolkhfmofdfdf": {
-            "location": 1,
-            "path": "ebgmjfhpkngekpdlgfdbolkhfmofdfdf/1.0",
-            "app_launcher_ordinal": "t",
-            "page_ordinal": "n",
-            "state": 1,
-            "install_time": "12968795380420751",
-            "ephemeral_app": true,
-            "manifest": {
-              "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtd5jeTaSP38on5y28W8f5MV+F4mvYMx0kOJXp8M+EteL9x5TS3et5a7W1jnduIdGtH0Xc5WKhvUnN2nUmEqjzzdRYvzjpWrTr73oFreebqNhJP47D75HdbWZqf8iCQwVJDKxbQ6OzHG8xoWd1ksNtQGUBUhMQXOt7d4/36TbansJ5neRS2akXY8GRWkGHtRJENNy85IoeV8erZc6WTeTM/M2wK/V3j9do1RmueKBU4Dz3H8Ix5/t2mJSantOPedf2We08+7CadB32+wE90OjPcuO9itaU1lhTXiUZeISLdzZv2ybyiOglkzP+wY4dWlDsF+5/3FN7mjQuWg4vg+pgwIDAQAB",
-              "version": "1.0",
-              "name": "Ephemeral App",
-              "app": {
-                "background": {
-                  "scripts": [ "main.js" ]
-                }
-              }
-            }
          }
       }
    }
diff --git a/chrome/test/data/extensions/permissions_increase/v2/background.html b/chrome/test/data/extensions/permissions_increase/v2/background.html
index 741876f2..b0d7464 100644
--- a/chrome/test/data/extensions/permissions_increase/v2/background.html
+++ b/chrome/test/data/extensions/permissions_increase/v2/background.html
@@ -1 +1,2 @@
 Dummy file.
+<script src="background.js"></script>
diff --git a/chrome/test/data/extensions/permissions_increase/v2/background.js b/chrome/test/data/extensions/permissions_increase/v2/background.js
new file mode 100644
index 0000000..7a8794a
--- /dev/null
+++ b/chrome/test/data/extensions/permissions_increase/v2/background.js
@@ -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.
+
+chrome.runtime.onInstalled.addListener(function(detail) {
+  if (detail.previousVersion === '1') {
+    chrome.test.sendMessage('v2.onInstalled');
+  } else {
+    chrome.test.sendMessage('FAILED');
+  }
+});
diff --git a/chrome/test/data/save_page/.gitattributes b/chrome/test/data/save_page/.gitattributes
new file mode 100644
index 0000000..e99e06b
--- /dev/null
+++ b/chrome/test/data/save_page/.gitattributes
@@ -0,0 +1,6 @@
+# Set the default behavior, in case people don't have core.autocrlf set.
+* text=auto
+
+# Preserve binary content of test files that exercise different encodings.
+encoding-*.htm binary
+
diff --git a/chrome/test/data/save_page/encoding-iso-8859-2.htm b/chrome/test/data/save_page/encoding-iso-8859-2.htm
new file mode 100644
index 0000000..e556d94
--- /dev/null
+++ b/chrome/test/data/save_page/encoding-iso-8859-2.htm
@@ -0,0 +1,16 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="iso-8859-2">
+    <title>
+      Test page for saving frames with weird encodings.
+    </title>
+  </head>
+  <body>
+    Test page for saving frames with weird encodings (iso-8859-2).
+    <br><br>
+    Exercising encoding with a sentence
+    that contains all special Polish characters:
+    iso-8859-2.htm: Za¿ó³æ gê¶l± ja¼ñ.
+  </body>
+</html>
diff --git a/chrome/test/data/save_page/encoding-utf16-be-bom.htm b/chrome/test/data/save_page/encoding-utf16-be-bom.htm
new file mode 100644
index 0000000..02f5bdb
--- /dev/null
+++ b/chrome/test/data/save_page/encoding-utf16-be-bom.htm
Binary files differ
diff --git a/chrome/test/data/save_page/encoding-utf16-be-nobom.htm b/chrome/test/data/save_page/encoding-utf16-be-nobom.htm
new file mode 100644
index 0000000..9977341
--- /dev/null
+++ b/chrome/test/data/save_page/encoding-utf16-be-nobom.htm
Binary files differ
diff --git a/chrome/test/data/save_page/encoding-utf16-be-nobom.htm.mock-http-headers b/chrome/test/data/save_page/encoding-utf16-be-nobom.htm.mock-http-headers
new file mode 100644
index 0000000..6edaef4
--- /dev/null
+++ b/chrome/test/data/save_page/encoding-utf16-be-nobom.htm.mock-http-headers
@@ -0,0 +1,4 @@
+HTTP/1.1 200 OK
+Connection: close
+Content-Length: 780
+Content-Type: text/html; charset=utf-16be
diff --git a/chrome/test/data/save_page/encoding-utf16-le-bom.htm b/chrome/test/data/save_page/encoding-utf16-le-bom.htm
new file mode 100644
index 0000000..cbf0a090
--- /dev/null
+++ b/chrome/test/data/save_page/encoding-utf16-le-bom.htm
Binary files differ
diff --git a/chrome/test/data/save_page/encoding-utf16-le-nobom.htm b/chrome/test/data/save_page/encoding-utf16-le-nobom.htm
new file mode 100644
index 0000000..00ff29c
--- /dev/null
+++ b/chrome/test/data/save_page/encoding-utf16-le-nobom.htm
Binary files differ
diff --git a/chrome/test/data/save_page/encoding-utf16-le-nobom.htm.mock-http-headers b/chrome/test/data/save_page/encoding-utf16-le-nobom.htm.mock-http-headers
new file mode 100644
index 0000000..7a909297
--- /dev/null
+++ b/chrome/test/data/save_page/encoding-utf16-le-nobom.htm.mock-http-headers
@@ -0,0 +1,4 @@
+HTTP/1.1 200 OK
+Connection: close
+Content-Length: 780
+Content-Type: text/html; charset=utf-16le
diff --git a/chrome/test/data/save_page/encoding-utf32.htm b/chrome/test/data/save_page/encoding-utf32.htm
new file mode 100644
index 0000000..a6372fe
--- /dev/null
+++ b/chrome/test/data/save_page/encoding-utf32.htm
Binary files differ
diff --git a/chrome/test/data/save_page/encoding-utf32.htm.mock-http-headers b/chrome/test/data/save_page/encoding-utf32.htm.mock-http-headers
new file mode 100644
index 0000000..ce97124
--- /dev/null
+++ b/chrome/test/data/save_page/encoding-utf32.htm.mock-http-headers
@@ -0,0 +1,4 @@
+HTTP/1.1 200 OK
+Connection: close
+Content-Length: 1332
+Content-Type: text/html; charset=utf-32
diff --git a/chrome/test/data/ssl/page_with_dynamic_unsafe_image.html b/chrome/test/data/ssl/page_with_dynamic_unsafe_image.html
new file mode 100644
index 0000000..d232531
--- /dev/null
+++ b/chrome/test/data/ssl/page_with_dynamic_unsafe_image.html
@@ -0,0 +1,13 @@
+<html>
+<head><title>Page with unsafe image loaded dynamically</title>
+<script>
+  var url = "https://REPLACE_WITH_HOST_AND_PORT/ssl/google_files/logo.gif";
+
+  function AddImage() {
+    var img = document.createElement("img");
+    img.src = url;
+    document.body.appendChild(img);
+  }
+</script>
+<body></body>
+</html>
diff --git a/chrome/test/data/ssl/page_with_unsafe_image.html b/chrome/test/data/ssl/page_with_unsafe_image.html
new file mode 100644
index 0000000..9136e377
--- /dev/null
+++ b/chrome/test/data/ssl/page_with_unsafe_image.html
@@ -0,0 +1,14 @@
+<html>
+<head><title>Page with unsafe image</title>
+<script>
+  function ImageWidth() {
+    return document.getElementById("bad_image").width;
+  }
+</script>
+</head>
+
+<body>
+This page contains an image which is served over an insecure HTTPS connection...<br>
+<img id="bad_image" src="https://REPLACE_WITH_HOST_AND_PORT/ssl/google_files/logo.gif"/>
+</body>
+</html>
diff --git a/chrome/test/data/viewsource/test.html b/chrome/test/data/viewsource/test.html
index a24361ce..9a21f704 100644
--- a/chrome/test/data/viewsource/test.html
+++ b/chrome/test/data/viewsource/test.html
@@ -7,5 +7,6 @@
 </script>
 </head>
 <body onload="setTitle();">
+<div id='bar'>a div</div>
 </body>
 </html>
diff --git a/chrome/test/data/webui/assertions.js b/chrome/test/data/webui/assertions.js
index f8d7f19..cd7bc9b 100644
--- a/chrome/test/data/webui/assertions.js
+++ b/chrome/test/data/webui/assertions.js
@@ -9,53 +9,38 @@
   browsePreload: DUMMY_URL,
 };
 
-function testTwoExpects() {
-  expectTrue(false);
-  expectTrue(0);
-}
-
 TEST_F('WebUIAssertionsTest', 'testTwoExpects', function() {
-  var result = runTestFunction('testTwoExpects', testTwoExpects, []);
+  var result = runTestFunction('testTwoExpects', function() {
+    expectTrue(false);
+    expectFalse(true);
+  }, []);
   resetTestState();
-
-  expectFalse(result[0]);
-  expectTrue(!!result[1].match(/expectTrue\(false\): false/));
-  expectTrue(!!result[1].match(/expectTrue\(0\): 0/));
+  assertFalse(result[0]);
+  assertNotEquals(-1, result[1].indexOf('expected false to be true'));
+  assertNotEquals(-1, result[1].indexOf('expected true to be false'));
 });
 
-function twoExpects() {
-  expectTrue(false, 'message1');
-  expectTrue(false, 'message2');
-}
-
-function testCallTestTwice() {
-  twoExpects();
-  twoExpects();
-}
-
-TEST_F('WebUIAssertionsTest', 'testCallTestTwice', function() {
-  var result = runTestFunction('testCallTestTwice', testCallTestTwice, []);
+TEST_F('WebUIAssertionsTest', 'testTwoIdenticalExpects', function() {
+  var result = runTestFunction('testTwoIdenticalExpects', function() {
+    expectTrue(false, 'message1');
+    expectTrue(false, 'message1');
+  }, []);
   resetTestState();
-
-  expectFalse(result[0]);
-  expectEquals(2, result[1].match(
-      /expectTrue\(false, 'message1'\): message1: false/g).length);
-  expectEquals(2, result[1].match(
-      /expectTrue\(false, 'message2'\): message2: false/g).length);
+  assertFalse(result[0]);
+  assertEquals(2, result[1].match(
+      /message1: expected false to be true/g).length);
 });
 
-function testConstructMessage() {
-  var message = 1 + ' ' + 2;
-  assertTrue(false, message);
-}
-
 TEST_F('WebUIAssertionsTest', 'testConstructedMessage', function() {
+  var message = 'myErrorMessage';
   var result = runTestFunction(
-      'testConstructMessage', testConstructMessage, []);
+      'testConstructMessage',
+      function() {
+        assertTrue(false, message);
+      }, []);
   resetTestState();
-
-  expectEquals(
-      1, result[1].match(/assertTrue\(false, message\): 1 2: false/g).length);
+  assertNotEquals(
+      -1, result[1].indexOf(message + ': expected false to be true'));
 });
 
 /**
diff --git a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
index 8a6001d..b07ba508 100644
--- a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
+++ b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
@@ -164,3 +164,25 @@
   extension_manager_tests.registerTests();
   mocha.grep(assert(extension_manager_tests.TestNames.ItemOrder)).run();
 });
+
+TEST_F('CrExtensionsBrowserTestWithMultipleExtensionTypesInstalled',
+       'ExtensionManagerExtensionSectionVisibilityTest', function() {
+  extension_manager_tests.registerTests();
+  mocha.grep(
+      assert(extension_manager_tests.TestNames.ExtensionSectionVisibility)).
+          run();
+});
+
+TEST_F('CrExtensionsBrowserTestWithMultipleExtensionTypesInstalled',
+       'ExtensionManagerAppSectionVisibilityTest', function() {
+  extension_manager_tests.registerTests();
+  mocha.grep(
+      assert(extension_manager_tests.TestNames.AppSectionVisibility)).run();
+});
+
+TEST_F('CrExtensionsBrowserTestWithMultipleExtensionTypesInstalled',
+       'ExtensionManagerWebsiteSectionVisibilityTest', function() {
+  extension_manager_tests.registerTests();
+  mocha.grep(
+      assert(extension_manager_tests.TestNames.WebsiteSectionVisibility)).run();
+});
diff --git a/chrome/test/data/webui/extensions/extension_manager_test.js b/chrome/test/data/webui/extensions/extension_manager_test.js
index 06732593..954e0136 100644
--- a/chrome/test/data/webui/extensions/extension_manager_test.js
+++ b/chrome/test/data/webui/extensions/extension_manager_test.js
@@ -8,8 +8,15 @@
   var TestNames = {
     SplitSections: 'split sections',
     ItemOrder: 'item order',
+    ExtensionSectionVisibility: 'extension section visibility',
+    AppSectionVisibility: 'app section visibility',
+    WebsiteSectionVisibility: 'website section visibility',
   };
 
+  function getDataByName(list, name) {
+    return assert(list.find(function(el) { return el.name == name; }));
+  }
+
   function registerTests() {
     suite('ExtensionManagerTest', function() {
       /** @type {extensions.Manager} */
@@ -48,12 +55,11 @@
       });
 
       test(assert(TestNames.ItemOrder), function() {
-        var service = extensions.Service.getInstance();
         expectEquals(0, manager.extensions.length);
 
         var alphaFromStore = extension_test_util.createExtensionInfo(
             {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)});
-        manager.addItem(alphaFromStore, service);
+        manager.addItem(alphaFromStore);
 
         expectEquals(1, manager.extensions.length);
         expectEquals(alphaFromStore.id, manager.extensions[0].id);
@@ -61,7 +67,7 @@
         // Unpacked extensions come first.
         var betaUnpacked = extension_test_util.createExtensionInfo(
             {location: 'UNPACKED', name: 'Beta', id: 'b'.repeat(32)});
-        manager.addItem(betaUnpacked, service);
+        manager.addItem(betaUnpacked);
 
         expectEquals(2, manager.extensions.length);
         expectEquals(betaUnpacked.id, manager.extensions[0].id);
@@ -70,7 +76,7 @@
         // 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);
+        manager.addItem(gammaUnpacked);
 
         expectEquals(3, manager.extensions.length);
         expectEquals(betaUnpacked.id, manager.extensions[0].id);
@@ -85,9 +91,9 @@
             {location: 'FROM_STORE', name: 'Aa', id: 'e'.repeat(32)});
         var aAFromStore = extension_test_util.createExtensionInfo(
             {location: 'FROM_STORE', name: 'aA', id: 'f'.repeat(32)});
-        manager.addItem(aaFromStore, service);
-        manager.addItem(AaFromStore, service);
-        manager.addItem(aAFromStore, service);
+        manager.addItem(aaFromStore);
+        manager.addItem(AaFromStore);
+        manager.addItem(aAFromStore);
 
         expectEquals(6, manager.extensions.length);
         expectEquals(betaUnpacked.id, manager.extensions[0].id);
@@ -97,6 +103,74 @@
         expectEquals(aAFromStore.id, manager.extensions[4].id);
         expectEquals(alphaFromStore.id, manager.extensions[5].id);
       });
+
+      test(assert(TestNames.ExtensionSectionVisibility), function() {
+        var testVisible = extension_test_util.testVisible.bind(null, manager);
+        var testSidebarVisible =
+             extension_test_util.testVisible.bind(null, manager.sidebar);
+
+        var extension = getDataByName(manager.extensions, 'My extension 1');
+
+        testVisible('#extensions-list', true);
+        testSidebarVisible('#sections-extensions', true);
+        manager.removeItem(extension);
+        Polymer.dom.flush();
+        testVisible('#extensions-list', false);
+        testSidebarVisible('#sections-extensions', false);
+
+        manager.addItem(extension);
+        Polymer.dom.flush();
+        testVisible('#extensions-list', true);
+        testSidebarVisible('#sections-extensions', true);
+      });
+
+      test(assert(TestNames.AppSectionVisibility), function() {
+        var testVisible = extension_test_util.testVisible.bind(null, manager);
+        var testSidebarVisible =
+             extension_test_util.testVisible.bind(null, manager.sidebar);
+        var platformApp =
+            getDataByName(manager.apps,
+                          'Platform App Test: minimal platform app');
+
+        testVisible('#apps-list', true);
+        testSidebarVisible('#sections-apps', true);
+        manager.removeItem(platformApp);
+        Polymer.dom.flush();
+        testVisible('#apps-list', false);
+        testSidebarVisible('#sections-apps', false);
+
+        manager.addItem(platformApp);
+        Polymer.dom.flush();
+        testVisible('#apps-list', true);
+        testSidebarVisible('#sections-apps', true);
+      });
+
+      test(assert(TestNames.WebsiteSectionVisibility), function() {
+        var testVisible = extension_test_util.testVisible.bind(null, manager);
+        var testSidebarVisible =
+             extension_test_util.testVisible.bind(null, manager.sidebar);
+
+        var hostedApp = getDataByName(manager.websites, 'hosted_app');
+        var packagedApp = getDataByName(manager.websites, 'Packaged App Test');
+
+        testVisible('#websites-list', true);
+        testSidebarVisible('#sections-websites', true);
+        expectEquals(2, manager.websites.length);
+        manager.removeItem(hostedApp);
+        Polymer.dom.flush();
+        expectEquals(1, manager.websites.length);
+        testVisible('#websites-list', true);
+        testSidebarVisible('#sections-websites', true);
+        manager.removeItem(packagedApp);
+        Polymer.dom.flush();
+        testVisible('#websites-list', false);
+        testSidebarVisible('#sections-websites', false);
+
+        manager.addItem(hostedApp);
+        Polymer.dom.flush();
+        testVisible('#websites-list', true);
+        testSidebarVisible('#sections-websites', true);
+      });
     });
   }
 
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 abffbc9..492594b 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
@@ -113,15 +113,15 @@
 
         // Initialize local variables.
         fakeCastModeList = [
-          new media_router.CastMode(0, 'Description 0', 'google.com'),
-          new media_router.CastMode(1, 'Description 1', null),
-          new media_router.CastMode(2, 'Description 2', null),
+          new media_router.CastMode(0x1, 'Description 0', 'google.com'),
+          new media_router.CastMode(0x2, 'Description 1', null),
+          new media_router.CastMode(0x4, 'Description 2', null),
         ];
 
         fakeCastModeListWithNonDefaultModesOnly = [
-          new media_router.CastMode(1, 'Description 1', null),
-          new media_router.CastMode(2, 'Description 2', null),
-          new media_router.CastMode(3, 'Description 3', null),
+          new media_router.CastMode(0x2, 'Description 1', null),
+          new media_router.CastMode(0x4, 'Description 2', null),
+          new media_router.CastMode(0x8, 'Description 3', null),
         ];
 
         fakeRouteList = [
@@ -134,18 +134,17 @@
           new media_router.Route('id 2', 'sink id 2', 'Title 2', 1, true),
         ];
 
-        // Note: These need to be in-order by name to prevent shuffling.
-        // Sorting of sinks by name is tested separately.
+        var castModeBitset = 0x2 | 0x4 | 0x8;
         fakeSinkList = [
           new media_router.Sink('sink id 1', 'Sink 1', null,
               media_router.SinkIconType.CAST,
-              media_router.SinkStatus.ACTIVE, [1, 2, 3]),
+              media_router.SinkStatus.ACTIVE, castModeBitset),
           new media_router.Sink('sink id 2', 'Sink 2', null,
               media_router.SinkIconType.CAST,
-              media_router.SinkStatus.ACTIVE, [1, 2, 3]),
+              media_router.SinkStatus.ACTIVE, castModeBitset),
           new media_router.Sink('sink id 3', 'Sink 3', null,
               media_router.SinkIconType.CAST,
-              media_router.SinkStatus.PENDING, [1, 2, 3]),
+              media_router.SinkStatus.PENDING, castModeBitset),
         ];
 
         fakeBlockingIssue = new media_router.Issue(
@@ -156,8 +155,7 @@
             'issue id 2', 'Issue Title 2', 'Issue Message 2', 0, 1,
             'route id 2', false, 1234);
 
-        container.initializeCastModes(
-            fakeCastModeList, fakeCastModeList[1].type);
+        container.castModeList = fakeCastModeList;
 
         // Allow for the media router container to be created and attached.
         setTimeout(done);
@@ -172,9 +170,15 @@
           var sinkList =
               container.$['sink-list'].querySelectorAll('paper-item');
           container.addEventListener('create-route', function(data) {
+            // Container is initially in auto mode since a cast mode has not
+            // been selected.
+            assertEquals(media_router.CastModeType.AUTO,
+                container.shownCastModeValue_);
             assertEquals(fakeSinkList[2].id, data.detail.sinkId);
-            assertEquals(container.selectedCastModeValue_,
-                data.detail.selectedCastModeValue);
+
+            // The preferred compatible cast mode on the sink is used, since
+            // the we did not choose a cast mode on the container.
+            assertEquals(0x2, data.detail.selectedCastModeValue);
             done();
           });
           // Tap on a sink without a route, which should fire a 'create-route'
@@ -240,7 +244,13 @@
       test('header text with no default cast modes', function(done) {
         assertEquals(loadTimeData.getString('selectCastModeHeader'),
             container.selectCastModeHeaderText_);
-        assertEquals(fakeCastModeList[1].description, container.headerText);
+
+        // The container is currently in auto cast mode, since we have not
+        // picked a cast mode explicitly, and the sinks is not compatible
+        // with exactly one cast mode.
+        assertEquals(media_router.AUTO_CAST_MODE.description,
+            container.headerText);
+        assertFalse(container.userHasSelectedCastMode_);
 
         container.castModeList = fakeCastModeListWithNonDefaultModesOnly;
         setTimeout(function() {
@@ -503,20 +513,83 @@
         });
       });
 
+      // Tests all sinks are always shown in auto mode, and that the mode will
+      // switch if the sinks support only 1 case mode.
+      test('sink list in auto mode', function(done) {
+        container.allSinks = fakeSinkList;
+        setTimeout(function() {
+          // Container is initially in auto mode since a cast mode has not been
+          // selected.
+          assertEquals(media_router.AUTO_CAST_MODE.description,
+              container.headerText);
+          assertEquals(media_router.CastModeType.AUTO,
+              container.shownCastModeValue_);
+          assertFalse(container.userHasSelectedCastMode_);
+          var sinkList =
+              container.$['sink-list'].querySelectorAll('paper-item');
+
+          // All sinks are shown in auto mode.
+          assertEquals(3, sinkList.length);
+
+          // When sink list changes to only 1 compatible cast mode, the mode is
+          // switched, and all sinks are shown.
+          container.allSinks = [
+            new media_router.Sink('sink id 10', 'Sink 10', null,
+                media_router.SinkIconType.CAST,
+                media_router.SinkStatus.ACTIVE, 0x4),
+            new media_router.Sink('sink id 20', 'Sink 20', null,
+                media_router.SinkIconType.CAST,
+                media_router.SinkStatus.ACTIVE, 0x4),
+            new media_router.Sink('sink id 30', 'Sink 30', null,
+                media_router.SinkIconType.CAST,
+                media_router.SinkStatus.PENDING, 0x4),
+          ];
+
+          setTimeout(function() {
+            assertEquals(fakeCastModeList[2].description, container.headerText);
+            assertEquals(fakeCastModeList[2].type,
+                container.shownCastModeValue_);
+            assertFalse(container.userHasSelectedCastMode_);
+
+            var sinkList =
+                container.$['sink-list'].querySelectorAll('paper-item');
+            assertEquals(3, sinkList.length);
+
+            // When compatible cast modes size is no longer exactly 1, switch
+            // back to auto mode, and all sinks are shown.
+            container.allSinks = fakeSinkList;
+            setTimeout(function() {
+              assertEquals(media_router.AUTO_CAST_MODE.description,
+                  container.headerText);
+              assertEquals(media_router.CastModeType.AUTO,
+                  container.shownCastModeValue_);
+              assertFalse(container.userHasSelectedCastMode_);
+              var sinkList =
+                  container.$['sink-list'].querySelectorAll('paper-item');
+
+              // All sinks are shown in auto mode.
+              assertEquals(3, sinkList.length);
+
+              done();
+            });
+          });
+        });
+      });
+
       // Tests that the sink list does not contain any sinks that are not
-      // compatible with the current cast mode and are not associated with a
+      // compatible with the selected cast mode and are not associated with a
       // route.
-      test('sink list filtering based on initial cast mode', function(done) {
+      test('sink list in user selected cast mode', function(done) {
         var newSinks = [
           new media_router.Sink('sink id 10', 'Sink 10', null,
               media_router.SinkIconType.CAST,
-              media_router.SinkStatus.ACTIVE, [2, 3]),
+              media_router.SinkStatus.ACTIVE, 0x4 | 0x8),
           new media_router.Sink('sink id 20', 'Sink 20', null,
               media_router.SinkIconType.CAST,
-              media_router.SinkStatus.ACTIVE, [1, 2, 3]),
+              media_router.SinkStatus.ACTIVE, 0x2 | 0x4 | 0x8),
           new media_router.Sink('sink id 30', 'Sink 30', null,
               media_router.SinkIconType.CAST,
-              media_router.SinkStatus.PENDING, [2, 3]),
+              media_router.SinkStatus.PENDING, 0x4 | 0x8),
         ];
 
         container.allSinks = newSinks;
@@ -528,23 +601,126 @@
           var sinkList =
               container.$['sink-list'].querySelectorAll('paper-item');
 
-          // newSinks[0] got filtered out since it is not compatible with cast
-          // mode 1.
-          // 'Sink 20' should be on the list because it contains the selected
-          // cast mode. (sinkList[0] = newSinks[1])
-          // 'Sink 30' should be on the list because it has a route.
-          // (sinkList[1] = newSinks[2])
-          assertEquals(2, sinkList.length);
-          checkElementText(newSinks[1].name, sinkList[0]);
+          // Since we haven't selected a cast mode, we don't filter sinks.
+          assertEquals(3, sinkList.length);
 
-          // |sinkList[1]| contains route title in addition to sink name.
-          assertTrue(sinkList[1].textContent.trim().startsWith(
-              newSinks[2].name.trim()));
+          // Cast mode 1 is selected, and the sink list is filtered.
+          var castModeList =
+              container.$['cast-mode-list'].querySelectorAll('paper-item');
+          MockInteractions.tap(castModeList[1]);
+          assertEquals(fakeCastModeList[1].description, container.headerText);
+          assertEquals(fakeCastModeList[1].type, container.shownCastModeValue_);
 
+          setTimeout(function() {
+            var sinkList =
+                container.$['sink-list'].querySelectorAll('paper-item');
+
+            // newSinks[0] got filtered out since it is not compatible with cast
+            // mode 1.
+            // 'Sink 20' should be on the list because it contains the selected
+            // cast mode. (sinkList[0] = newSinks[1])
+            // 'Sink 30' should be on the list because it has a route.
+            // (sinkList[1] = newSinks[2])
+            assertEquals(2, sinkList.length);
+            checkElementText(newSinks[1].name, sinkList[0]);
+
+            // |sinkList[1]| contains route title in addition to sink name.
+            assertTrue(sinkList[1].textContent.trim().startsWith(
+                newSinks[2].name.trim()));
+
+            // Cast mode is not switched back even if there are no sinks
+            // compatible with selected cast mode, because we explicitly
+            // selected that cast mode.
+            container.allSinks = [];
+            setTimeout(function() {
+              assertEquals(fakeCastModeList[1].description,
+                  container.headerText);
+              assertEquals(fakeCastModeList[1].type,
+                  container.shownCastModeValue_);
+              var sinkList =
+                  container.$['sink-list'].querySelectorAll('paper-item');
+              assertEquals(0, sinkList.length);
+              done();
+            });
+          });
+        });
+      });
+
+      // Container remains in auto mode even if the cast mode list changed.
+      test('cast mode list updated in auto mode', function(done) {
+        assertEquals(media_router.AUTO_CAST_MODE.description,
+            container.headerText);
+        assertEquals(media_router.CastModeType.AUTO,
+            container.shownCastModeValue_);
+        assertFalse(container.userHasSelectedCastMode_);
+
+        container.castModeList = fakeCastModeList.slice(1);
+        setTimeout(function() {
+          assertEquals(media_router.AUTO_CAST_MODE.description,
+              container.headerText);
+          assertEquals(media_router.CastModeType.AUTO,
+              container.shownCastModeValue_);
+          assertFalse(container.userHasSelectedCastMode_);
           done();
         });
       });
 
+      // If the container is not in auto mode, and the mode it is currently in
+      // no longer exists in the list of cast modes, then switch back to auto
+      // mode.
+      test('cast mode list updated in selected cast mode', function(done) {
+        assertEquals(media_router.AUTO_CAST_MODE.description,
+            container.headerText);
+        assertEquals(media_router.CastModeType.AUTO,
+            container.shownCastModeValue_);
+        assertFalse(container.userHasSelectedCastMode_);
+
+        var castModeList =
+              container.$['cast-mode-list'].querySelectorAll('paper-item');
+        MockInteractions.tap(castModeList[0]);
+        setTimeout(function() {
+          assertEquals(fakeCastModeList[0].description, container.headerText);
+          assertEquals(fakeCastModeList[0].type, container.shownCastModeValue_);
+          assertTrue(container.userHasSelectedCastMode_);
+          container.castModeList = fakeCastModeList.slice(1);
+          setTimeout(function() {
+            assertEquals(media_router.AUTO_CAST_MODE.description,
+                container.headerText);
+            assertEquals(media_router.CastModeType.AUTO,
+                container.shownCastModeValue_);
+            assertFalse(container.userHasSelectedCastMode_);
+            done();
+          });
+        });
+      });
+
+      test('creating route with selected cast mode', function(done) {
+        container.allSinks = fakeSinkList;
+
+        // Select cast mode 2.
+        var castModeList =
+            container.$['cast-mode-list'].querySelectorAll('paper-item');
+        MockInteractions.tap(castModeList[1]);
+        assertEquals(fakeCastModeList[1].description, container.headerText);
+        setTimeout(function() {
+          var sinkList =
+              container.$['sink-list'].querySelectorAll('paper-item');
+          container.addEventListener('create-route', function(data) {
+            assertEquals(fakeSinkList[2].id, data.detail.sinkId);
+            // Cast mode 2 is used, since we selected it explicitly.
+            assertEquals(fakeCastModeList[1].type,
+                         data.detail.selectedCastModeValue);
+            done();
+          });
+          // All sinks are compatible with cast mode 2.
+          assertEquals(fakeSinkList.length, sinkList.length);
+          // Tap on a sink without a route, which should fire a 'create-route'
+          // event.
+          MockInteractions.tap(sinkList[2]);
+        });
+
+      });
+
       // Tests that after a different cast mode is selected, the sink list will
       // change based on the sinks compatibility with the new cast mode.
       test('changing cast mode changes sink list', function(done) {
@@ -573,61 +749,6 @@
           });
          });
       });
-
-      // Tests that sinks provided in some random order will be sorted by name
-      // when shown to the user.
-      test('sinks are shown sorted by name', function(done) {
-        var outOfOrderSinks = [
-          new media_router.Sink('6543', 'Sleepy', null,
-              media_router.SinkIconType.CAST,
-              media_router.SinkStatus.ACTIVE, [1]),
-          new media_router.Sink('543', 'Happy', null,
-              media_router.SinkIconType.CAST,
-              media_router.SinkStatus.ACTIVE, [1]),
-          new media_router.Sink('43', 'Bashful', null,
-              media_router.SinkIconType.CAST,
-              media_router.SinkStatus.ACTIVE, [1]),
-          new media_router.Sink('2', 'George', null,
-              media_router.SinkIconType.CAST_AUDIO,
-              media_router.SinkStatus.ACTIVE, [1]),
-          new media_router.Sink('1', 'George', null,
-              media_router.SinkIconType.CAST,
-              media_router.SinkStatus.ACTIVE, [1]),
-          new media_router.Sink('3', 'George', null,
-              media_router.SinkIconType.HANGOUT,
-              media_router.SinkStatus.ACTIVE, [1]),
-        ];
-
-        container.allSinks = outOfOrderSinks;
-
-        setTimeout(function() {
-          var sinkList =
-              container.$['sink-list'].querySelectorAll('paper-item');
-
-          assertEquals(6, sinkList.length);
-          checkElementText('Bashful', sinkList[0]);
-          checkElementText('George', sinkList[1]);
-          checkElementText('George', sinkList[2]);
-          checkElementText('George', sinkList[3]);
-          checkElementText('Happy', sinkList[4]);
-          checkElementText('Sleepy', sinkList[5]);
-
-          // There are three George's, so check that the first has id '1', the
-          // second has id '2', and the third has id '3'.  The icons are used to
-          // determine which is which.
-          assertEquals(
-              container.computeSinkIcon_(outOfOrderSinks[4]),
-              sinkList[1].querySelector('iron-icon').icon);
-          assertEquals(
-              container.computeSinkIcon_(outOfOrderSinks[3]),
-              sinkList[2].querySelector('iron-icon').icon);
-          assertEquals(
-              container.computeSinkIcon_(outOfOrderSinks[5]),
-              sinkList[3].querySelector('iron-icon').icon);
-
-          done();
-        });
-      });
     });
   }
 
diff --git a/chrome/test/data/webui/settings/main_page_browsertest.js b/chrome/test/data/webui/settings/main_page_browsertest.js
index a829820..8fd9a5e1 100644
--- a/chrome/test/data/webui/settings/main_page_browsertest.js
+++ b/chrome/test/data/webui/settings/main_page_browsertest.js
@@ -39,7 +39,7 @@
     test('basic pages', function() {
       var page = self.getPage('basic');
       expectTrue(!!self.getSection(page, 'appearance'));
-      expectTrue(!!self.getSection(page, 'on-startup'));
+      expectTrue(!!self.getSection(page, 'onStartup'));
       expectTrue(!!self.getSection(page, 'search'));
       if (!cr.isChromeOS) {
         expectTrue(!!self.getSection(page, 'people'));
diff --git a/chrome/test/data/webui/test_api.js b/chrome/test/data/webui/test_api.js
index 4c2243ed..b04dbb3 100644
--- a/chrome/test/data/webui/test_api.js
+++ b/chrome/test/data/webui/test_api.js
@@ -731,101 +731,6 @@
   }
 
   /**
-   * Provides a mechanism for assert* and expect* methods to fetch the signature
-   * of their caller. Assert* methods should |registerCall| and expect* methods
-   * should set |isExpect| and |expectName| properties to indicate that the
-   * interesting caller is one more level up the stack.
-   */
-  function CallHelper() {
-    this.__proto__ = CallHelper.prototype;
-  }
-
-  CallHelper.prototype = {
-    /**
-     * Holds the mapping of (callerCallerString, callerName) -> count of times
-     * called.
-     * @type {Object<string, Object<string, number>>}
-     */
-    counts_: {},
-
-    /**
-     * This information about the caller is needed from most of the following
-     * routines.
-     * @param {Function} caller the caller of the assert* routine.
-     * @return {{callerName: string, callercallerString: string}} stackInfo
-     * @private
-     */
-    getCallerInfo_: function(caller) {
-      var callerName = caller.name;
-      var callerCaller = caller.caller;
-      if (callerCaller['isExpect']) {
-        callerName = callerCaller.expectName;
-        callerCaller = callerCaller.caller;
-      }
-      var callerCallerString = callerCaller.toString();
-      return {
-        callerName: callerName,
-        callerCallerString: callerCallerString,
-      };
-    },
-
-    /**
-     * Register a call to an assertion class.
-     */
-    registerCall: function() {
-      var stackInfo = this.getCallerInfo_(arguments.callee.caller);
-      if (!(stackInfo.callerCallerString in this.counts_))
-        this.counts_[stackInfo.callerCallerString] = {};
-      if (!(stackInfo.callerName in this.counts_[stackInfo.callerCallerString]))
-        this.counts_[stackInfo.callerCallerString][stackInfo.callerName] = 0;
-      ++this.counts_[stackInfo.callerCallerString][stackInfo.callerName];
-    },
-
-    /**
-     * Get the call signature of this instance of the caller's call to this
-     * function.
-     * @param {Function} caller The caller of the assert* routine.
-     * @return {String} Call signature.
-     * @private
-     */
-    getCall_: function(caller) {
-      var stackInfo = this.getCallerInfo_(caller);
-      var count =
-          this.counts_[stackInfo.callerCallerString][stackInfo.callerName];
-
-      // Allow pattern to match multiple lines for text wrapping.
-      var callerRegExp =
-          new RegExp(stackInfo.callerName + '\\((.|\\n|\\r)*?\\);', 'g');
-
-      // Find all matches allowing wrap around such as when a helper function
-      // calls assert/expect calls and that helper function is called multiple
-      // times.
-      var matches = stackInfo.callerCallerString.match(callerRegExp);
-      var match = matches[(count - 1) % matches.length];
-
-      // Chop off the trailing ';'.
-      return match.substring(0, match.length-1);
-    },
-
-    /**
-     * Returns the text of the call signature and any |message|.
-     * @param {string=} message Addtional message text from caller.
-     */
-    getCallMessage: function(message) {
-      var callMessage = this.getCall_(arguments.callee.caller);
-      if (message)
-        callMessage += ': ' + message;
-      return callMessage;
-    },
-  };
-
-  /**
-   * Help register calls for better error reporting.
-   * @type {CallHelper}
-   */
-  var helper = new CallHelper();
-
-  /**
    * true when testDone has been called.
    * @type {boolean}
    */
@@ -924,136 +829,91 @@
 
   // Asserts.
   // Use the following assertions to verify a condition within a test.
-  // If assertion fails, throw an Error with information pertinent to the test.
 
   /**
-   * When |test| !== true, aborts the current test.
-   * @param {boolean} test The predicate to check against |expected|.
-   * @param {string=} message The message to include in the Error thrown.
-   * @throws {Error} upon failure.
+   * @param {boolean} value The value to check.
+   * @param {string=} opt_message Additional error message.
+   * @throws {Error}
    */
-  function assertTrue(test, message) {
-    helper.registerCall();
-    if (test !== true)
-      throw new Error(
-          'Test Error ' + helper.getCallMessage(message) + ': ' + test);
+  function assertTrue(value, opt_message) {
+    chai.assert.isTrue(value, opt_message);
   }
 
   /**
-   * When |test| !== false, aborts the current test.
-   * @param {boolean} test The predicate to check against |expected|.
-   * @param {string=} message The message to include in the Error thrown.
-   * @throws {Error} upon failure.
+   * @param {boolean} value The value to check.
+   * @param {string=} opt_message Additional error message.
+   * @throws {Error}
    */
-  function assertFalse(test, message) {
-    helper.registerCall();
-    if (test !== false)
-      throw new Error(
-          'Test Error ' + helper.getCallMessage(message) + ': ' + test);
+  function assertFalse(value, opt_message) {
+    chai.assert.isFalse(value, opt_message);
   }
 
   /**
-   * When |val1| < |val2|, aborts the current test.
-   * @param {number} val1 The number expected to be >= |val2|.
-   * @param {number} val2 The number expected to be < |val1|.
-   * @param {string=} message The message to include in the Error thrown.
+   * @param {number} value1 The first operand.
+   * @param {number} value2 The second operand.
+   * @param {string=} opt_message Additional error message.
+   * @throws {Error}
    */
-  function assertGE(val1, val2, message) {
-    helper.registerCall();
-    if (val1 < val2) {
-      throw new Error(
-          'Test Error ' + helper.getCallMessage(message) + val1 + '<' + val2);
-    }
+  function assertGE(value1, value2, opt_message) {
+    chai.expect(value1).to.be.at.least(value2, opt_message);
   }
 
   /**
-   * When |val1| <= |val2|, aborts the current test.
-   * @param {number} val1 The number expected to be > |val2|.
-   * @param {number} val2 The number expected to be <= |val1|.
-   * @param {string=} message The message to include in the Error thrown.
+   * @param {number} value1 The first operand.
+   * @param {number} value2 The second operand.
+   * @param {string=} opt_message Additional error message.
+   * @throws {Error}
    */
-  function assertGT(val1, val2, message) {
-    helper.registerCall();
-    if (val1 <= val2) {
-      throw new Error(
-          'Test Error ' + helper.getCallMessage(message) + val1 + '<=' + val2);
-    }
+  function assertGT(value1, value2, opt_message) {
+    chai.assert.isAbove(value1, value2, opt_message);
   }
 
   /**
-   * When |expected| !== |actual|, aborts the current test.
-   * @param {*} expected The expected value of |actual|.
-   * @param {*} actual The predicate to check against |expected|.
-   * @param {string=} message The message to include in the Error thrown.
-   * @throws {Error} upon failure.
+   * @param {*} expected The expected value.
+   * @param {*} actual The actual value.
+   * @param {string=} opt_message Additional error message.
+   * @throws {Error}
    */
-  function assertEquals(expected, actual, message) {
-    helper.registerCall();
-    if (expected != actual) {
-      throw new Error(
-          'Test Error ' + helper.getCallMessage(message) +
-          '\nActual: ' + actual + '\nExpected: ' + expected);
-    }
-    if (typeof expected !== typeof actual) {
-      throw new Error(
-          'Test Error (type mismatch) ' + helper.getCallMessage(message) +
-          '\nActual Type: ' + typeof actual +
-          '\nExpected Type:' + typeof expected);
-    }
+  function assertEquals(expected, actual, opt_message) {
+    chai.assert.strictEqual(actual, expected, opt_message);
   }
 
   /**
-   * When |val1| > |val2|, aborts the current test.
-   * @param {number} val1 The number expected to be <= |val2|.
-   * @param {number} val2 The number expected to be > |val1|.
-   * @param {string=} message The message to include in the Error thrown.
+   * @param {number} value1 The first operand.
+   * @param {number} value2 The second operand.
+   * @param {string=} opt_message Additional error message.
+   * @throws {Error}
    */
-  function assertLE(val1, val2, message) {
-    helper.registerCall();
-    if (val1 > val2) {
-      throw new Error(
-          'Test Error ' + helper.getCallMessage(message) + val1 + '>' + val2);
-    }
+  function assertLE(value1, value2, opt_message) {
+    chai.expect(value1).to.be.at.most(value2, opt_message);
   }
 
   /**
-   * When |val1| >= |val2|, aborts the current test.
-   * @param {number} val1 The number expected to be < |val2|.
-   * @param {number} val2 The number expected to be >= |val1|.
-   * @param {string=} message The message to include in the Error thrown.
+   * @param {number} value1 The first operand.
+   * @param {number} value2 The second operand.
+   * @param {string=} opt_message Additional error message.
+   * @throws {Error}
    */
-  function assertLT(val1, val2, message) {
-    helper.registerCall();
-    if (val1 >= val2) {
-      throw new Error(
-          'Test Error ' + helper.getCallMessage(message) + val1 + '>=' + val2);
-    }
+  function assertLT(value1, value2, opt_message) {
+    chai.assert.isBelow(value1, value2, opt_message);
   }
 
   /**
-   * When |notExpected| === |actual|, aborts the current test.
-   * @param {*} notExpected The expected value of |actual|.
-   * @param {*} actual The predicate to check against |notExpected|.
-   * @param {string=} message The message to include in the Error thrown.
-   * @throws {Error} upon failure.
+   * @param {*} expected The expected value.
+   * @param {*} actual The actual value.
+   * @param {string=} opt_message Additional error message.
+   * @throws {Error}
    */
-  function assertNotEquals(notExpected, actual, message) {
-    helper.registerCall();
-    if (notExpected === actual) {
-      throw new Error(
-          'Test Error ' + helper.getCallMessage(message) +
-          '\nActual: ' + actual + '\nnotExpected: ' + notExpected);
-    }
+  function assertNotEquals(expected, actual, opt_message) {
+    chai.assert.notStrictEqual(actual, expected, opt_message);
   }
 
   /**
-   * Always aborts the current test.
-   * @param {string=} message The message to include in the Error thrown.
-   * @throws {Error} always.
+   * @param {string=} opt_message Additional error message.
+   * @throws {Error}
    */
-  function assertNotReached(message) {
-    helper.registerCall();
-    throw new Error(helper.getCallMessage(message));
+  function assertNotReached(opt_message) {
+    chai.assert.fail(null, null, opt_message);
   }
 
   /**
@@ -1100,7 +960,6 @@
    * @param {Array=} opt_results Array to fill with results, if desired.
    */
   function assertAccessibilityOk(opt_results) {
-    helper.registerCall();
     var a11yResults = opt_results || [];
     var auditConfig = currentTestCase.fixture.accessibilityAuditConfig;
     if (!runAccessibilityAudit(a11yResults, auditConfig))
@@ -1119,7 +978,7 @@
    * @see runTestFunction
    */
   function createExpect(assertFunc) {
-    var expectFunc = function() {
+    return function() {
       try {
         assertFunc.apply(null, arguments);
       } catch (e) {
@@ -1128,9 +987,6 @@
       }
       return true;
     };
-    expectFunc.isExpect = true;
-    expectFunc.expectName = assertFunc.name.replace(/^assert/, 'expect');
-    return expectFunc;
   }
 
   /**
@@ -1789,35 +1645,62 @@
     return new MatchToString(expectedValue);
   }
 
+  /**
+   * Exports assertion methods. All assertion methods delegate to the chai.js
+   * assertion library.
+   */
+  function exportChaiAsserts() {
+    exports.assertTrue = assertTrue;
+    exports.assertFalse = assertFalse;
+    exports.assertGE = assertGE;
+    exports.assertGT = assertGT;
+    exports.assertEquals = assertEquals;
+    exports.assertLE = assertLE;
+    exports.assertLT = assertLT;
+    exports.assertNotEquals = assertNotEquals;
+    exports.assertNotReached = assertNotReached;
+  }
+
+  /**
+   * Exports expect methods. 'expect*' methods allow tests to run until the end
+   * even in the presence of failures.
+   */
+  function exportExpects() {
+    exports.expectTrue = createExpect(assertTrue);
+    exports.expectFalse = createExpect(assertFalse);
+    exports.expectGE = createExpect(assertGE);
+    exports.expectGT = createExpect(assertGT);
+    exports.expectEquals = createExpect(assertEquals);
+    exports.expectLE = createExpect(assertLE);
+    exports.expectLT = createExpect(assertLT);
+    exports.expectNotEquals = createExpect(assertNotEquals);
+    exports.expectNotReached = createExpect(assertNotReached);
+    exports.expectAccessibilityOk = createExpect(assertAccessibilityOk);
+  }
+
+  /**
+   * Exports methods related to Mock4JS mocking.
+   */
+  function exportMock4JsHelpers() {
+    exports.callFunction = callFunction;
+    exports.callFunctionWithSavedArgs = callFunctionWithSavedArgs;
+    exports.callGlobalWithSavedArgs = callGlobalWithSavedArgs;
+    exports.eqJSON = eqJSON;
+    exports.eqToString = eqToString;
+    exports.invokeCallback = invokeCallback;
+    exports.SaveMockArguments = SaveMockArguments;
+
+    // Import the Mock4JS helpers.
+    Mock4JS.addMockSupport(exports);
+  }
+
   // Exports.
   testing.Test = Test;
   exports.testDone = testDone;
-  exports.assertTrue = assertTrue;
-  exports.assertFalse = assertFalse;
-  exports.assertGE = assertGE;
-  exports.assertGT = assertGT;
-  exports.assertEquals = assertEquals;
-  exports.assertLE = assertLE;
-  exports.assertLT = assertLT;
-  exports.assertNotEquals = assertNotEquals;
-  exports.assertNotReached = assertNotReached;
+  exportChaiAsserts();
   exports.assertAccessibilityOk = assertAccessibilityOk;
-  exports.callFunction = callFunction;
-  exports.callFunctionWithSavedArgs = callFunctionWithSavedArgs;
-  exports.callGlobalWithSavedArgs = callGlobalWithSavedArgs;
-  exports.eqJSON = eqJSON;
-  exports.eqToString = eqToString;
-  exports.expectTrue = createExpect(assertTrue);
-  exports.expectFalse = createExpect(assertFalse);
-  exports.expectGE = createExpect(assertGE);
-  exports.expectGT = createExpect(assertGT);
-  exports.expectEquals = createExpect(assertEquals);
-  exports.expectLE = createExpect(assertLE);
-  exports.expectLT = createExpect(assertLT);
-  exports.expectNotEquals = createExpect(assertNotEquals);
-  exports.expectNotReached = createExpect(assertNotReached);
-  exports.expectAccessibilityOk = createExpect(assertAccessibilityOk);
-  exports.invokeCallback = invokeCallback;
+  exportExpects();
+  exportMock4JsHelpers();
   exports.preloadJavascriptLibraries = preloadJavascriptLibraries;
   exports.registerMessageCallback = registerMessageCallback;
   exports.registerMockGlobals = registerMockGlobals;
@@ -1828,7 +1711,6 @@
   exports.runAllActionsAsync = runAllActionsAsync;
   exports.runTest = runTest;
   exports.runTestFunction = runTestFunction;
-  exports.SaveMockArguments = SaveMockArguments;
   exports.DUMMY_URL = DUMMY_URL;
   exports.TEST = TEST;
   exports.TEST_F = TEST_F;
@@ -1836,7 +1718,4 @@
   exports.GEN = GEN;
   exports.GEN_INCLUDE = GEN_INCLUDE;
   exports.WhenTestDone = WhenTestDone;
-
-  // Import the Mock4JS helpers.
-  Mock4JS.addMockSupport(exports);
 })(this);
diff --git a/chrome/unit_tests.isolate b/chrome/unit_tests.isolate
index e67d527e..4146ee9 100644
--- a/chrome/unit_tests.isolate
+++ b/chrome/unit_tests.isolate
@@ -54,6 +54,7 @@
           '../google_apis/test/data/',
           '../net/data/',
           '../third_party/accessibility-audit/axs_testing.js',
+          '../third_party/chaijs/chai.js',
           '../third_party/hunspell_dictionaries/',
           '../third_party/zlib/google/test/data/',
           '../tools/metrics/histograms/histograms.xml',
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc
index 043d2ee..4d72acf 100644
--- a/chrome/utility/chrome_content_utility_client.cc
+++ b/chrome/utility/chrome_content_utility_client.cc
@@ -126,7 +126,7 @@
 #endif
 
 #if defined(ENABLE_PRINT_PREVIEW) || defined(OS_WIN)
-  handlers_.push_back(new PrintingHandler());
+  handlers_.push_back(new printing::PrintingHandler());
 #endif
 
 #if defined(ENABLE_MDNS)
diff --git a/chrome/utility/printing_handler.cc b/chrome/utility/printing_handler.cc
index 9e282ad..43e39080 100644
--- a/chrome/utility/printing_handler.cc
+++ b/chrome/utility/printing_handler.cc
@@ -5,9 +5,6 @@
 #include "chrome/utility/printing_handler.h"
 
 #include "base/files/file_util.h"
-#include "base/lazy_instance.h"
-#include "base/path_service.h"
-#include "base/scoped_native_library.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_utility_printing_messages.h"
 #include "chrome/utility/cloud_print/bitmap_image.h"
@@ -27,6 +24,8 @@
 #include "printing/backend/print_backend.h"
 #endif
 
+namespace printing {
+
 namespace {
 
 bool Send(IPC::Message* message) {
@@ -70,7 +69,7 @@
 #if defined(OS_WIN)
 void PrintingHandler::OnRenderPDFPagesToMetafile(
     IPC::PlatformFileForTransit pdf_transit,
-    const printing::PdfRenderSettings& settings) {
+    const PdfRenderSettings& settings) {
   pdf_rendering_settings_ = settings;
   base::File pdf_file = IPC::PlatformFileForTransitToFile(pdf_transit);
   int page_count = LoadPDF(pdf_file.Pass());
@@ -98,8 +97,8 @@
 #if defined(ENABLE_PRINT_PREVIEW)
 void PrintingHandler::OnRenderPDFPagesToPWGRaster(
     IPC::PlatformFileForTransit pdf_transit,
-    const printing::PdfRenderSettings& settings,
-    const printing::PwgRasterSettings& bitmap_settings,
+    const PdfRenderSettings& settings,
+    const PwgRasterSettings& bitmap_settings,
     IPC::PlatformFileForTransit bitmap_transit) {
   base::File pdf = IPC::PlatformFileForTransitToFile(pdf_transit);
   base::File bitmap = IPC::PlatformFileForTransitToFile(bitmap_transit);
@@ -125,8 +124,8 @@
     return 0;
 
   int total_page_count = 0;
-  if (!chrome_pdf::GetPDFDocInfo(
-          &pdf_data_.front(), pdf_data_.size(), &total_page_count, NULL)) {
+  if (!chrome_pdf::GetPDFDocInfo(&pdf_data_.front(), pdf_data_.size(),
+                                 &total_page_count, nullptr)) {
     return 0;
   }
   return total_page_count;
@@ -135,7 +134,7 @@
 bool PrintingHandler::RenderPdfPageToMetafile(int page_number,
                                               base::File output_file,
                                               float* scale_factor) {
-  printing::Emf metafile;
+  Emf metafile;
   metafile.Init();
 
   // We need to scale down DC to fit an entire page into DC available area.
@@ -181,8 +180,8 @@
 #if defined(ENABLE_PRINT_PREVIEW)
 bool PrintingHandler::RenderPDFPagesToPWGRaster(
     base::File pdf_file,
-    const printing::PdfRenderSettings& settings,
-    const printing::PwgRasterSettings& bitmap_settings,
+    const PdfRenderSettings& settings,
+    const PwgRasterSettings& bitmap_settings,
     base::File bitmap_file) {
   bool autoupdate = true;
   base::File::Info info;
@@ -196,8 +195,8 @@
     return false;
 
   int total_page_count = 0;
-  if (!chrome_pdf::GetPDFDocInfo(data.data(), data_size,
-                                 &total_page_count, NULL)) {
+  if (!chrome_pdf::GetPDFDocInfo(data.data(), data_size, &total_page_count,
+                                 nullptr)) {
     return false;
   }
 
@@ -236,16 +235,16 @@
     // Transform odd pages.
     if (page_number % 2) {
       switch (bitmap_settings.odd_page_transform) {
-        case printing::TRANSFORM_NORMAL:
+        case TRANSFORM_NORMAL:
           break;
-        case printing::TRANSFORM_ROTATE_180:
+        case TRANSFORM_ROTATE_180:
           header_info.flipx = true;
           header_info.flipy = true;
           break;
-        case printing::TRANSFORM_FLIP_HORIZONTAL:
+        case TRANSFORM_FLIP_HORIZONTAL:
           header_info.flipx = true;
           break;
-        case printing::TRANSFORM_FLIP_VERTICAL:
+        case TRANSFORM_FLIP_VERTICAL:
           header_info.flipy = true;
           break;
       }
@@ -269,9 +268,9 @@
 
 void PrintingHandler::OnGetPrinterCapsAndDefaults(
     const std::string& printer_name) {
-  scoped_refptr<printing::PrintBackend> print_backend =
-      printing::PrintBackend::CreateInstance(NULL);
-  printing::PrinterCapsAndDefaults printer_info;
+  scoped_refptr<PrintBackend> print_backend =
+      PrintBackend::CreateInstance(nullptr);
+  PrinterCapsAndDefaults printer_info;
 
   crash_keys::ScopedPrinterInfo crash_key(
       print_backend->GetPrinterDriverInfo(printer_name));
@@ -288,9 +287,9 @@
 
 void PrintingHandler::OnGetPrinterSemanticCapsAndDefaults(
     const std::string& printer_name) {
-  scoped_refptr<printing::PrintBackend> print_backend =
-      printing::PrintBackend::CreateInstance(NULL);
-  printing::PrinterSemanticCapsAndDefaults printer_info;
+  scoped_refptr<PrintBackend> print_backend =
+      PrintBackend::CreateInstance(nullptr);
+  PrinterSemanticCapsAndDefaults printer_info;
 
   crash_keys::ScopedPrinterInfo crash_key(
       print_backend->GetPrinterDriverInfo(printer_name));
@@ -306,3 +305,5 @@
   ReleaseProcessIfNeeded();
 }
 #endif  // ENABLE_PRINT_PREVIEW
+
+}  // namespace printing
diff --git a/chrome/utility/printing_handler.h b/chrome/utility/printing_handler.h
index 341a358..3f866565 100644
--- a/chrome/utility/printing_handler.h
+++ b/chrome/utility/printing_handler.h
@@ -16,10 +16,10 @@
 #endif
 
 namespace printing {
+
 class PdfRenderSettings;
 struct PwgRasterSettings;
 struct PageRange;
-}
 
 // Dispatches IPCs for printing.
 class PrintingHandler : public UtilityMessageHandler {
@@ -34,18 +34,17 @@
   // IPC message handlers.
 #if defined(OS_WIN)
   void OnRenderPDFPagesToMetafile(IPC::PlatformFileForTransit pdf_transit,
-                                  const printing::PdfRenderSettings& settings);
+                                  const PdfRenderSettings& settings);
   void OnRenderPDFPagesToMetafileGetPage(
       int page_number,
       IPC::PlatformFileForTransit output_file);
   void OnRenderPDFPagesToMetafileStop();
 #endif  // OS_WIN
 #if defined(ENABLE_PRINT_PREVIEW)
-  void OnRenderPDFPagesToPWGRaster(
-      IPC::PlatformFileForTransit pdf_transit,
-      const printing::PdfRenderSettings& settings,
-      const printing::PwgRasterSettings& bitmap_settings,
-      IPC::PlatformFileForTransit bitmap_transit);
+  void OnRenderPDFPagesToPWGRaster(IPC::PlatformFileForTransit pdf_transit,
+                                   const PdfRenderSettings& settings,
+                                   const PwgRasterSettings& bitmap_settings,
+                                   IPC::PlatformFileForTransit bitmap_transit);
 #endif  // ENABLE_PRINT_PREVIEW
 
 #if defined(OS_WIN)
@@ -55,11 +54,10 @@
                                float* scale_factor);
 #endif  // OS_WIN
 #if defined(ENABLE_PRINT_PREVIEW)
-  bool RenderPDFPagesToPWGRaster(
-      base::File pdf_file,
-      const printing::PdfRenderSettings& settings,
-      const printing::PwgRasterSettings& bitmap_settings,
-      base::File bitmap_file);
+  bool RenderPDFPagesToPWGRaster(base::File pdf_file,
+                                 const PdfRenderSettings& settings,
+                                 const PwgRasterSettings& bitmap_settings,
+                                 base::File bitmap_file);
 
   void OnGetPrinterCapsAndDefaults(const std::string& printer_name);
   void OnGetPrinterSemanticCapsAndDefaults(const std::string& printer_name);
@@ -67,10 +65,12 @@
 
 #if defined(OS_WIN)
   std::vector<char> pdf_data_;
-  printing::PdfRenderSettings pdf_rendering_settings_;
+  PdfRenderSettings pdf_rendering_settings_;
 #endif
 
   DISALLOW_COPY_AND_ASSIGN(PrintingHandler);
 };
 
+}  // namespace printing
+
 #endif  // CHROME_UTILITY_PRINTING_HANDLER_H_
diff --git a/chrome_elf/blacklist/blacklist.cc b/chrome_elf/blacklist/blacklist.cc
index 616c793..77aff7b 100644
--- a/chrome_elf/blacklist/blacklist.cc
+++ b/chrome_elf/blacklist/blacklist.cc
@@ -243,7 +243,9 @@
 }
 
 int GetBlacklistIndex(const wchar_t* dll_name) {
-  for (int i = 0; i < kTroublesomeDllsMaxCount && g_troublesome_dlls[i]; ++i) {
+  for (int i = 0;
+       i < static_cast<int>(kTroublesomeDllsMaxCount) && g_troublesome_dlls[i];
+       ++i) {
     if (_wcsicmp(dll_name, g_troublesome_dlls[i]) == 0)
       return i;
   }
@@ -253,7 +255,7 @@
 bool AddDllToBlacklist(const wchar_t* dll_name) {
   int blacklist_size = BlacklistSize();
   // We need to leave one space at the end for the null pointer.
-  if (blacklist_size + 1 >= kTroublesomeDllsMaxCount)
+  if (blacklist_size + 1 >= static_cast<int>(kTroublesomeDllsMaxCount))
     return false;
   for (int i = 0; i < blacklist_size; ++i) {
     if (!_wcsicmp(g_troublesome_dlls[i], dll_name))
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn
index 03205ce9..bc1a8a0 100644
--- a/chromecast/BUILD.gn
+++ b/chromecast/BUILD.gn
@@ -108,7 +108,9 @@
       "//chromecast/media:cast_media_unittests",
     ]
 
-    filters += [ "cast_shell_browser_test --no-sandbox --enable-local-file-accesses --enable-cma-media-pipeline --ozone-platform=cast" ]
+    # --enable-local-file-accesses => to load sample media files
+    # --test-launcher-jobs=1 => so internal code can bind to port
+    filters += [ "cast_shell_browser_test --no-sandbox --enable-local-file-accesses --enable-cma-media-pipeline --ozone-platform=cast --test-launcher-jobs=1" ]
   }
 
   if (!disable_display) {
diff --git a/chromecast/app/BUILD.gn b/chromecast/app/BUILD.gn
index ba591b6..4388d89 100644
--- a/chromecast/app/BUILD.gn
+++ b/chromecast/app/BUILD.gn
@@ -55,6 +55,7 @@
     "//base",
     "//base/test:run_all_unittests",
     "//base/test:test_support",
+    "//chromecast/base:test_support",
     "//chromecast/crash",
     "//chromecast/crash:test_support",
     "//testing/gtest",
diff --git a/chromecast/app/linux/cast_crash_reporter_client_unittest.cc b/chromecast/app/linux/cast_crash_reporter_client_unittest.cc
index adcfd26..9dc408b 100644
--- a/chromecast/app/linux/cast_crash_reporter_client_unittest.cc
+++ b/chromecast/app/linux/cast_crash_reporter_client_unittest.cc
@@ -8,11 +8,13 @@
 #include "base/bind.h"
 #include "base/files/file.h"
 #include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_vector.h"
 #include "base/test/scoped_path_override.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "chromecast/app/linux/cast_crash_reporter_client.h"
+#include "chromecast/base/scoped_temp_file.h"
 #include "chromecast/crash/app_state_tracker.h"
 #include "chromecast/crash/linux/crash_testing_utils.h"
 #include "chromecast/crash/linux/crash_util.h"
@@ -48,10 +50,10 @@
 
   // testing::Test implementation:
   void SetUp() override {
-    // Set up a temporary directory which will be used as our fake home dir.
-    ASSERT_TRUE(base::CreateNewTempDirectory("", &fake_home_dir_));
+    // Override the $HOME path.
+    ASSERT_TRUE(fake_home_dir_.CreateUniqueTempDir());
     home_override_.reset(
-        new base::ScopedPathOverride(base::DIR_HOME, fake_home_dir_));
+        new base::ScopedPathOverride(base::DIR_HOME, home_path()));
 
     // "Launch" YouTube.
     AppStateTracker::SetLastLaunchedApp("youtube");
@@ -65,12 +67,8 @@
     AppStateTracker::SetLastLaunchedApp("netflix");
     // Netflix crashed.
 
-    // A minidump file is created.
-    base::CreateTemporaryFile(&minidump_path_);
-    base::File minidump(minidump_path_,
-                        base::File::FLAG_OPEN | base::File::FLAG_APPEND);
-    minidump.Write(0, kFakeMinidumpContents, sizeof(kFakeMinidumpContents) - 1);
-    minidump.Close();
+    // A minidump file is written.
+    minidump_.Write(kFakeMinidumpContents);
   }
 
   void TearDown() override {
@@ -78,13 +76,13 @@
     base::ThreadRestrictions::SetIOAllowed(true);
 
     // Assert that the original file has been moved.
-    ASSERT_FALSE(base::PathExists(minidump_path_));
+    ASSERT_FALSE(base::PathExists(minidump_path()));
 
     // Assert that the file has been moved to "minidumps", with the expected
     // contents.
     std::string contents;
     base::FilePath new_minidump =
-        fake_home_dir_.Append("minidumps").Append(minidump_path_.BaseName());
+        home_path().Append("minidumps").Append(minidump_path().BaseName());
     ASSERT_TRUE(base::PathExists(new_minidump));
     ASSERT_TRUE(base::ReadFileToString(new_minidump, &contents));
     ASSERT_EQ(kFakeMinidumpContents, contents);
@@ -98,7 +96,7 @@
 
     // Assert that the lockfile has logged the correct information.
     base::FilePath lockfile =
-        fake_home_dir_.Append("minidumps").Append("lockfile");
+        home_path().Append("minidumps").Append("lockfile");
     ASSERT_TRUE(base::PathExists(lockfile));
     ScopedVector<DumpInfo> dumps;
     ASSERT_TRUE(FetchDumps(lockfile.value(), &dumps));
@@ -113,12 +111,15 @@
     EXPECT_EQ("netflix", dump_info.params().last_app_name);
   }
 
-  const base::FilePath& minidump_path() { return minidump_path_; }
+  base::FilePath minidump_path() { return minidump_.path(); }
+  base::FilePath home_path() { return fake_home_dir_.path(); }
 
  private:
-  base::FilePath fake_home_dir_;
-  base::FilePath minidump_path_;
+  base::ScopedTempDir fake_home_dir_;
+  ScopedTempFile minidump_;
   scoped_ptr<base::ScopedPathOverride> home_override_;
+
+  DISALLOW_COPY_AND_ASSIGN(CastCrashReporterClientTest);
 };
 
 #if ENABLE_THREAD_RESTRICTIONS
diff --git a/chromecast/base/BUILD.gn b/chromecast/base/BUILD.gn
index 7ec6e603..e34b903a 100644
--- a/chromecast/base/BUILD.gn
+++ b/chromecast/base/BUILD.gn
@@ -6,6 +6,7 @@
 import("//chromecast/chromecast.gni")
 import("//testing/test.gni")
 
+# GYP target: chromecast.gyp:cast_base
 source_set("base") {
   sources = [
     "android/dumpstate_writer.cc",
@@ -47,6 +48,20 @@
   ]
 }
 
+# GYP target: n/a
+source_set("test_support") {
+  sources = [
+    "scoped_temp_file.cc",
+    "scoped_temp_file.h",
+  ]
+
+  public_deps = [
+    ":base",
+    "//base",
+  ]
+}
+
+# GYP target: chromecast_tests.gypi:cast_base_unittests
 test("cast_base_unittests") {
   sources = [
     "device_capabilities_impl_unittest.cc",
@@ -58,8 +73,7 @@
   ]
 
   deps = [
-    ":base",
-    "//base",
+    ":test_support",
     "//base/test:run_all_unittests",
     "//base/test:test_support",
     "//testing/gmock",
diff --git a/chromecast/base/error_codes_unittest.cc b/chromecast/base/error_codes_unittest.cc
index 293d895..ef9c192 100644
--- a/chromecast/base/error_codes_unittest.cc
+++ b/chromecast/base/error_codes_unittest.cc
@@ -5,6 +5,7 @@
 #include "base/base_paths.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/test/scoped_path_override.h"
 #include "chromecast/base/error_codes.h"
@@ -19,12 +20,15 @@
 
   void SetUp() override {
     // Set up a temporary directory which will be used as our fake home dir.
-    ASSERT_TRUE(base::CreateNewTempDirectory("", &fake_home_dir_));
+    ASSERT_TRUE(fake_home_dir_.CreateUniqueTempDir());
     path_override_.reset(
-        new base::ScopedPathOverride(base::DIR_HOME, fake_home_dir_));
+        new base::ScopedPathOverride(base::DIR_HOME, fake_home_dir_.path()));
   }
 
-  base::FilePath fake_home_dir_;
+  base::FilePath home_path() const { return fake_home_dir_.path(); }
+
+ private:
+  base::ScopedTempDir fake_home_dir_;
   scoped_ptr<base::ScopedPathOverride> path_override_;
 };
 
@@ -36,29 +40,29 @@
   ASSERT_TRUE(SetInitialErrorCode(NO_ERROR));
 
   // File should not be written.
-  ASSERT_FALSE(base::PathExists(fake_home_dir_.Append("initial_error")));
+  ASSERT_FALSE(base::PathExists(home_path().Append("initial_error")));
   EXPECT_EQ(NO_ERROR, GetInitialErrorCode());
 }
 
 TEST_F(ErrorCodesTest, SetInitialErrorCodeSucceedsWithValidErrors) {
   // Write initial error and read it from the file.
   EXPECT_TRUE(SetInitialErrorCode(ERROR_WEB_CONTENT_RENDER_VIEW_GONE));
-  EXPECT_TRUE(base::PathExists(fake_home_dir_.Append("initial_error")));
+  EXPECT_TRUE(base::PathExists(home_path().Append("initial_error")));
   EXPECT_EQ(ERROR_WEB_CONTENT_RENDER_VIEW_GONE, GetInitialErrorCode());
 
   // File should be updated with most recent error.
   EXPECT_TRUE(SetInitialErrorCode(ERROR_UNKNOWN));
-  EXPECT_TRUE(base::PathExists(fake_home_dir_.Append("initial_error")));
+  EXPECT_TRUE(base::PathExists(home_path().Append("initial_error")));
   EXPECT_EQ(ERROR_UNKNOWN, GetInitialErrorCode());
 
   // File should be updated with most recent error.
   EXPECT_TRUE(SetInitialErrorCode(ERROR_WEB_CONTENT_NAME_NOT_RESOLVED));
-  EXPECT_TRUE(base::PathExists(fake_home_dir_.Append("initial_error")));
+  EXPECT_TRUE(base::PathExists(home_path().Append("initial_error")));
   EXPECT_EQ(ERROR_WEB_CONTENT_NAME_NOT_RESOLVED, GetInitialErrorCode());
 
   // File should be removed after writing NO_ERROR.
   EXPECT_TRUE(SetInitialErrorCode(NO_ERROR));
-  EXPECT_FALSE(base::PathExists(fake_home_dir_.Append("initial_error")));
+  EXPECT_FALSE(base::PathExists(home_path().Append("initial_error")));
   EXPECT_EQ(NO_ERROR, GetInitialErrorCode());
 }
 
diff --git a/chromecast/base/scoped_temp_file.cc b/chromecast/base/scoped_temp_file.cc
new file mode 100644
index 0000000..44309e4d6
--- /dev/null
+++ b/chromecast/base/scoped_temp_file.cc
@@ -0,0 +1,38 @@
+// 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 "chromecast/base/scoped_temp_file.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+
+namespace chromecast {
+
+ScopedTempFile::ScopedTempFile() {
+  CHECK(base::CreateTemporaryFile(&path_));
+}
+
+ScopedTempFile::~ScopedTempFile() {
+  if (FileExists()) {
+    // Since this is a file, set the -rf flag to false.
+    CHECK(base::DeleteFile(path_, false));
+  }
+}
+
+bool ScopedTempFile::FileExists() const {
+  return base::PathExists(path_);
+}
+
+int ScopedTempFile::Write(const std::string& str) {
+  CHECK(FileExists());
+  return base::WriteFile(path_, str.c_str(), str.size());
+}
+
+std::string ScopedTempFile::Read() const {
+  CHECK(FileExists());
+  std::string result;
+  CHECK(ReadFileToString(path_, &result));
+  return result;
+}
+
+}  // namespace chromecast
diff --git a/chromecast/base/scoped_temp_file.h b/chromecast/base/scoped_temp_file.h
new file mode 100644
index 0000000..57703e59
--- /dev/null
+++ b/chromecast/base/scoped_temp_file.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 CHROMECAST_BASE_SCOPED_TEMP_FILE_H_
+#define CHROMECAST_BASE_SCOPED_TEMP_FILE_H_
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+
+namespace chromecast {
+
+// Creates a temporary file that is deleted when this object is destroyed,
+// unless the underlying file has been moved or deleted.
+// Warning: This class uses CHECKs, and should only be used for testing.
+class ScopedTempFile {
+ public:
+  ScopedTempFile();
+  ~ScopedTempFile();
+
+  // Return the path to the temporary file. Note that if the underlying file has
+  // been moved or deleted, this will still return the original path.
+  base::FilePath path() const { return path_; }
+
+  // Returns true if the underlying file exists, false otherwise. This will
+  // return false, for example, if the file has been moved or deleted.
+  bool FileExists() const;
+
+  // Write the contents of |str| to the file. Return the number of characters
+  // written, or -1 on error. CHECKs that FileExists() returns true.
+  int Write(const std::string& str);
+
+  // Read the file and return the contents. CHECKs that FileExists() returns
+  // true.
+  std::string Read() const;
+
+ private:
+  base::FilePath path_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedTempFile);
+};
+
+}  // namespace chromecast
+
+#endif  // CHROMECAST_BASE_SCOPED_TEMP_FILE_H_
diff --git a/chromecast/base/serializers_unittest.cc b/chromecast/base/serializers_unittest.cc
index d2d29ed6..5724b4b0 100644
--- a/chromecast/base/serializers_unittest.cc
+++ b/chromecast/base/serializers_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "base/files/file_util.h"
 #include "base/values.h"
+#include "chromecast/base/scoped_temp_file.h"
 #include "chromecast/base/serializers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -24,7 +25,6 @@
 const char kPoorlyFormedJsonString[] = "{\"key\":";
 const char kTestKey[] = "test_key";
 const char kTestValue[] = "test_value";
-const char kTempfileName[] = "temp";
 
 }  // namespace
 
@@ -76,73 +76,40 @@
   EXPECT_TRUE(new_value->Equals(&orig_value));
 }
 
-class ScopedTempFile {
- public:
-  ScopedTempFile() {
-    // Create a temporary file
-    base::CreateNewTempDirectory("", &dir_);
-    file_ = dir_.Append(kTempfileName);
-  }
-
-  ~ScopedTempFile() {
-    // Remove the temp directory.
-    base::DeleteFile(dir_, true);
-  }
-
-  const base::FilePath& file() const { return file_; }
-  const base::FilePath& dir() const { return dir_; }
-
-  std::size_t Write(const char* str) {
-    return static_cast<std::size_t>(base::WriteFile(file_, str, strlen(str)));
-  }
-
-  std::string Read() {
-    std::string result;
-    ReadFileToString(file_, &result);
-    return result;
-  }
-
- private:
-  base::FilePath file_;
-  base::FilePath dir_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedTempFile);
-};
-
 TEST(DeserializeJsonFromFile, NoFile) {
-  ScopedTempFile temp;
-
-  ASSERT_TRUE(base::IsDirectoryEmpty(temp.dir()));
-  scoped_ptr<base::Value> value = DeserializeJsonFromFile(temp.file());
+  scoped_ptr<base::Value> value =
+      DeserializeJsonFromFile(base::FilePath("/file/does/not/exist.json"));
   EXPECT_EQ(nullptr, value.get());
 }
 
 TEST(DeserializeJsonFromFile, EmptyString) {
   ScopedTempFile temp;
-  EXPECT_EQ(strlen(""), temp.Write(""));
-  scoped_ptr<base::Value> value = DeserializeJsonFromFile(temp.file());
+  EXPECT_EQ(static_cast<int>(strlen("")), temp.Write(""));
+  scoped_ptr<base::Value> value = DeserializeJsonFromFile(temp.path());
   EXPECT_EQ(nullptr, value.get());
 }
 
 TEST(DeserializeJsonFromFile, EmptyJsonObject) {
   ScopedTempFile temp;
-  EXPECT_EQ(strlen(kEmptyJsonString), temp.Write(kEmptyJsonString));
-  scoped_ptr<base::Value> value = DeserializeJsonFromFile(temp.file());
+  EXPECT_EQ(static_cast<int>(strlen(kEmptyJsonString)),
+            temp.Write(kEmptyJsonString));
+  scoped_ptr<base::Value> value = DeserializeJsonFromFile(temp.path());
   EXPECT_NE(nullptr, value.get());
 }
 
 TEST(DeserializeJsonFromFile, ProperJsonObject) {
   ScopedTempFile temp;
-  EXPECT_EQ(strlen(kProperJsonString), temp.Write(kProperJsonString));
-  scoped_ptr<base::Value> value = DeserializeJsonFromFile(temp.file());
+  EXPECT_EQ(static_cast<int>(strlen(kProperJsonString)),
+            temp.Write(kProperJsonString));
+  scoped_ptr<base::Value> value = DeserializeJsonFromFile(temp.path());
   EXPECT_NE(nullptr, value.get());
 }
 
 TEST(DeserializeJsonFromFile, PoorlyFormedJsonObject) {
   ScopedTempFile temp;
-  EXPECT_EQ(strlen(kPoorlyFormedJsonString),
+  EXPECT_EQ(static_cast<int>(strlen(kPoorlyFormedJsonString)),
             temp.Write(kPoorlyFormedJsonString));
-  scoped_ptr<base::Value> value = DeserializeJsonFromFile(temp.file());
+  scoped_ptr<base::Value> value = DeserializeJsonFromFile(temp.path());
   EXPECT_EQ(nullptr, value.get());
 }
 
@@ -150,7 +117,7 @@
   ScopedTempFile temp;
 
   base::BinaryValue value(scoped_ptr<char[]>(new char[12]), 12);
-  ASSERT_FALSE(SerializeJsonToFile(temp.file(), value));
+  ASSERT_FALSE(SerializeJsonToFile(temp.path(), value));
   std::string str(temp.Read());
   EXPECT_TRUE(str.empty());
 }
@@ -159,7 +126,7 @@
   ScopedTempFile temp;
 
   base::DictionaryValue value;
-  ASSERT_TRUE(SerializeJsonToFile(temp.file(), value));
+  ASSERT_TRUE(SerializeJsonToFile(temp.path(), value));
   std::string str(temp.Read());
   ASSERT_FALSE(str.empty());
   EXPECT_EQ(kEmptyJsonFileString, str);
@@ -170,11 +137,11 @@
 
   base::DictionaryValue orig_value;
   orig_value.SetString(kTestKey, kTestValue);
-  ASSERT_TRUE(SerializeJsonToFile(temp.file(), orig_value));
+  ASSERT_TRUE(SerializeJsonToFile(temp.path(), orig_value));
   std::string str(temp.Read());
   ASSERT_FALSE(str.empty());
 
-  scoped_ptr<base::Value> new_value = DeserializeJsonFromFile(temp.file());
+  scoped_ptr<base::Value> new_value = DeserializeJsonFromFile(temp.path());
   ASSERT_NE(nullptr, new_value.get());
   EXPECT_TRUE(new_value->Equals(&orig_value));
 }
diff --git a/chromecast/browser/cast_content_window.cc b/chromecast/browser/cast_content_window.cc
index aa3d683..1cdb8cf 100644
--- a/chromecast/browser/cast_content_window.cc
+++ b/chromecast/browser/cast_content_window.cc
@@ -122,11 +122,11 @@
   metrics::CastMetricsHelper::GetInstance()->LogTimeToFirstPaint();
 }
 
-void CastContentWindow::MediaPaused() {
+void CastContentWindow::MediaStoppedPlaying(const MediaPlayerId& id) {
   metrics::CastMetricsHelper::GetInstance()->LogMediaPause();
 }
 
-void CastContentWindow::MediaStartedPlaying() {
+void CastContentWindow::MediaStartedPlaying(const MediaPlayerId& id) {
   metrics::CastMetricsHelper::GetInstance()->LogMediaPlay();
 }
 
diff --git a/chromecast/browser/cast_content_window.h b/chromecast/browser/cast_content_window.h
index 1fa6e1f..b0b8cc9 100644
--- a/chromecast/browser/cast_content_window.h
+++ b/chromecast/browser/cast_content_window.h
@@ -46,8 +46,8 @@
 
   // content::WebContentsObserver implementation:
   void DidFirstVisuallyNonEmptyPaint() override;
-  void MediaPaused() override;
-  void MediaStartedPlaying() override;
+  void MediaStoppedPlaying(const MediaPlayerId& id) override;
+  void MediaStartedPlaying(const MediaPlayerId& id) override;
   void RenderViewCreated(content::RenderViewHost* render_view_host) override;
 
  private:
diff --git a/chromecast/browser/cast_resource_dispatcher_host_delegate.cc b/chromecast/browser/cast_resource_dispatcher_host_delegate.cc
index 9a935fb3..ff9faa2 100644
--- a/chromecast/browser/cast_resource_dispatcher_host_delegate.cc
+++ b/chromecast/browser/cast_resource_dispatcher_host_delegate.cc
@@ -8,13 +8,14 @@
 #include "chromecast/net/connectivity_checker.h"
 #include "net/base/net_errors.h"
 #include "net/url_request/url_request.h"
+#include "net/url_request/url_request_status.h"
 
 namespace chromecast {
 namespace shell {
 
 void CastResourceDispatcherHostDelegate::RequestComplete(
     net::URLRequest* url_request) {
-  if (!url_request->status().is_success()) {
+  if (url_request->status().status() == net::URLRequestStatus::FAILED) {
     LOG(ERROR) << "Failed to load resource " << url_request->url()
                << "; status:" << url_request->status().status() << ", error:"
                << net::ErrorToShortString(url_request->status().error());
diff --git a/chromecast/browser/metrics/cast_metrics_service_client.cc b/chromecast/browser/metrics/cast_metrics_service_client.cc
index 8ad37a6..e9c4dce 100644
--- a/chromecast/browser/metrics/cast_metrics_service_client.cc
+++ b/chromecast/browser/metrics/cast_metrics_service_client.cc
@@ -211,9 +211,13 @@
   version_string.append("-K");
   version_string.append(base::IntToString(build_number));
 
-  int is_official_build =
+  const ::metrics::SystemProfileProto::Channel channel = GetChannel();
+  CHECK(!CAST_IS_DEBUG_BUILD() ||
+        channel != ::metrics::SystemProfileProto::CHANNEL_STABLE);
+  const bool is_official_build =
       build_number > 0 &&
-      GetChannel() != ::metrics::SystemProfileProto::CHANNEL_UNKNOWN;
+      !CAST_IS_DEBUG_BUILD() &&
+      channel != ::metrics::SystemProfileProto::CHANNEL_UNKNOWN;
   if (!is_official_build)
     version_string.append("-devel");
 
diff --git a/chromecast/chromecast.gyp b/chromecast/chromecast.gyp
index 87988e61..12373064 100644
--- a/chromecast/chromecast.gyp
+++ b/chromecast/chromecast.gyp
@@ -111,6 +111,8 @@
         'base/pref_names.h',
         'base/process_utils.cc',
         'base/process_utils.h',
+        'base/scoped_temp_file.cc',
+        'base/scoped_temp_file.h',
         'base/serializers.cc',
         'base/serializers.h',
         'base/system_time_change_notifier.cc',
diff --git a/chromecast/chromecast_tests.gypi b/chromecast/chromecast_tests.gypi
index 31b69e2..c889bbc8 100644
--- a/chromecast/chromecast_tests.gypi
+++ b/chromecast/chromecast_tests.gypi
@@ -180,7 +180,9 @@
           ],
           'variables': {
             'filters': [
-              'cast_shell_browser_test --no-sandbox --enable-local-file-accesses --enable-cma-media-pipeline --ozone-platform=cast',
+              # --enable-local-file-accesses => to load sample media files
+              # --test-launcher-jobs=1 => so internal code can bind to port
+              'cast_shell_browser_test --no-sandbox --enable-local-file-accesses --enable-cma-media-pipeline --ozone-platform=cast --test-launcher-jobs=1',
             ],
           },
         }],
diff --git a/chromecast/crash/BUILD.gn b/chromecast/crash/BUILD.gn
index b32fdfd8..888619df 100644
--- a/chromecast/crash/BUILD.gn
+++ b/chromecast/crash/BUILD.gn
@@ -65,6 +65,7 @@
       "//base/test:run_all_unittests",
       "//base/test:test_support",
       "//breakpad:client",
+      "//chromecast/base:test_support",
       "//testing/gmock",
       "//testing/gtest",
     ]
diff --git a/chromecast/crash/cast_crashdump_uploader_unittest.cc b/chromecast/crash/cast_crashdump_uploader_unittest.cc
index f88cce848..b17df389 100644
--- a/chromecast/crash/cast_crashdump_uploader_unittest.cc
+++ b/chromecast/crash/cast_crashdump_uploader_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/files/file_util.h"
 #include "breakpad/src/common/linux/libcurl_wrapper.h"
+#include "chromecast/base/scoped_temp_file.h"
 #include "chromecast/crash/cast_crashdump_uploader.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -54,11 +55,10 @@
   testing::StrictMock<MockLibcurlWrapper> m;
 
   // Create a temporary file.
-  base::FilePath temp;
-  ASSERT_TRUE(base::CreateTemporaryFile(&temp));
+  ScopedTempFile minidump;
 
   EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true));
-  EXPECT_CALL(m, AddFile(temp.value(), _)).WillOnce(Return(true));
+  EXPECT_CALL(m, AddFile(minidump.path().value(), _)).WillOnce(Return(true));
   EXPECT_CALL(m, SendRequest("http://foo.com", _, _, _, _)).Times(1).WillOnce(
       Return(true));
 
@@ -68,7 +68,7 @@
   data.guid = "AAA-BBB";
   data.email = "test@test.com";
   data.comments = "none";
-  data.minidump_pathname = temp.value();
+  data.minidump_pathname = minidump.path().value();
   data.crash_server = "http://foo.com";
   CastCrashdumpUploader uploader(data, &m);
 
@@ -97,8 +97,7 @@
   testing::StrictMock<MockLibcurlWrapper> m;
 
   // Create a temporary file.
-  base::FilePath temp;
-  ASSERT_TRUE(base::CreateTemporaryFile(&temp));
+  ScopedTempFile minidump;
 
   // Has all the require fields for a crashdump.
   CastCrashdumpData data;
@@ -107,7 +106,7 @@
   data.guid = "AAA-BBB";
   data.email = "test@test.com";
   data.comments = "none";
-  data.minidump_pathname = temp.value();
+  data.minidump_pathname = minidump.path().value();
   data.crash_server = "http://foo.com";
 
   // Test with empty product name.
@@ -135,11 +134,10 @@
   testing::StrictMock<MockLibcurlWrapper> m;
 
   // Create a temporary file.
-  base::FilePath minidump;
-  ASSERT_TRUE(base::CreateTemporaryFile(&minidump));
+  ScopedTempFile minidump;
 
   EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true));
-  EXPECT_CALL(m, AddFile(minidump.value(), _)).WillOnce(Return(true));
+  EXPECT_CALL(m, AddFile(minidump.path().value(), _)).WillOnce(Return(true));
 
   CastCrashdumpData data;
   data.product = "foobar";
@@ -147,7 +145,7 @@
   data.guid = "AAA-BBB";
   data.email = "test@test.com";
   data.comments = "none";
-  data.minidump_pathname = minidump.value();
+  data.minidump_pathname = minidump.path().value();
   data.crash_server = "http://foo.com";
   CastCrashdumpUploader uploader(data, &m);
 
@@ -160,16 +158,14 @@
   testing::StrictMock<MockLibcurlWrapper> m;
 
   // Create a temporary file.
-  base::FilePath minidump;
-  ASSERT_TRUE(base::CreateTemporaryFile(&minidump));
+  ScopedTempFile minidump;
 
   // Create a valid attachment.
-  base::FilePath attachment;
-  ASSERT_TRUE(base::CreateTemporaryFile(&attachment));
+  ScopedTempFile attachment;
 
   EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true));
-  EXPECT_CALL(m, AddFile(minidump.value(), _)).WillOnce(Return(true));
-  EXPECT_CALL(m, AddFile(attachment.value(), _)).WillOnce(Return(true));
+  EXPECT_CALL(m, AddFile(minidump.path().value(), _)).WillOnce(Return(true));
+  EXPECT_CALL(m, AddFile(attachment.path().value(), _)).WillOnce(Return(true));
   EXPECT_CALL(m, SendRequest(_, _, _, _, _)).Times(1).WillOnce(Return(true));
 
   CastCrashdumpData data;
@@ -178,12 +174,12 @@
   data.guid = "AAA-BBB";
   data.email = "test@test.com";
   data.comments = "none";
-  data.minidump_pathname = minidump.value();
+  data.minidump_pathname = minidump.path().value();
   data.crash_server = "http://foo.com";
   CastCrashdumpUploader uploader(data, &m);
 
-  // Add a file that does not exist as an attachment.
-  uploader.AddAttachment("label", attachment.value());
+  // Add a valid file as an attachment.
+  uploader.AddAttachment("label", attachment.path().value());
   ASSERT_TRUE(uploader.Upload(nullptr));
 }
 
diff --git a/chromecast/crash/linux/dummy_minidump_generator_unittest.cc b/chromecast/crash/linux/dummy_minidump_generator_unittest.cc
index d70ea761..567d9e2 100644
--- a/chromecast/crash/linux/dummy_minidump_generator_unittest.cc
+++ b/chromecast/crash/linux/dummy_minidump_generator_unittest.cc
@@ -5,7 +5,9 @@
 #include <string>
 
 #include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
 #include "base/rand_util.h"
+#include "chromecast/base/scoped_temp_file.h"
 #include "chromecast/crash/linux/dummy_minidump_generator.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -13,34 +15,34 @@
 
 TEST(DummyMinidumpGeneratorTest, GenerateFailsWithInvalidPath) {
   // Create directory in which to put minidump.
-  base::FilePath minidump_dir;
-  ASSERT_TRUE(base::CreateNewTempDirectory("", &minidump_dir));
+  base::ScopedTempDir minidump_dir;
+  ASSERT_TRUE(minidump_dir.CreateUniqueTempDir());
 
   // Attempt to generate a minidump from an invalid path.
   DummyMinidumpGenerator generator("/path/does/not/exist/minidump.dmp");
-  ASSERT_FALSE(generator.Generate(minidump_dir.Append("minidump.dmp").value()));
+  ASSERT_FALSE(
+      generator.Generate(minidump_dir.path().Append("minidump.dmp").value()));
 }
 
 TEST(DummyMinidumpGeneratorTest, GenerateSucceedsWithSmallSource) {
   // Create directory in which to put minidump.
-  base::FilePath minidump_dir;
-  ASSERT_TRUE(base::CreateNewTempDirectory("", &minidump_dir));
+  base::ScopedTempDir minidump_dir;
+  ASSERT_TRUE(minidump_dir.CreateUniqueTempDir());
 
   // Create a fake minidump file.
-  base::FilePath fake_minidump;
-  ASSERT_TRUE(base::CreateTemporaryFile(&fake_minidump));
+  ScopedTempFile fake_minidump;
   const std::string data("Test contents of the minidump file.\n");
   ASSERT_EQ(static_cast<int>(data.size()),
-            base::WriteFile(fake_minidump, data.c_str(), data.size()));
+            base::WriteFile(fake_minidump.path(), data.c_str(), data.size()));
 
-  DummyMinidumpGenerator generator(fake_minidump.value());
-  base::FilePath new_minidump = minidump_dir.Append("minidump.dmp");
+  DummyMinidumpGenerator generator(fake_minidump.path().value());
+  base::FilePath new_minidump = minidump_dir.path().Append("minidump.dmp");
   EXPECT_TRUE(generator.Generate(new_minidump.value()));
 
   // Original file should not exist, and new file should contain original
   // contents.
   std::string copied_data;
-  EXPECT_FALSE(base::PathExists(fake_minidump));
+  EXPECT_FALSE(base::PathExists(fake_minidump.path()));
   ASSERT_TRUE(base::PathExists(new_minidump));
   EXPECT_TRUE(base::ReadFileToString(new_minidump, &copied_data));
   EXPECT_EQ(data, copied_data);
@@ -48,27 +50,26 @@
 
 TEST(DummyMinidumpGeneratorTest, GenerateSucceedsWithLargeSource) {
   // Create directory in which to put minidump.
-  base::FilePath minidump_dir;
-  ASSERT_TRUE(base::CreateNewTempDirectory("", &minidump_dir));
+  base::ScopedTempDir minidump_dir;
+  ASSERT_TRUE(minidump_dir.CreateUniqueTempDir());
 
   // Create a large fake minidump file.
-  base::FilePath fake_minidump;
-  ASSERT_TRUE(base::CreateTemporaryFile(&fake_minidump));
+  ScopedTempFile fake_minidump;
   size_t str_len = 32768 * 10 + 1;
   const std::string data = base::RandBytesAsString(str_len);
 
   // Write the string to the file.
   ASSERT_EQ(static_cast<int>(data.size()),
-            base::WriteFile(fake_minidump, data.c_str(), data.size()));
+            base::WriteFile(fake_minidump.path(), data.c_str(), data.size()));
 
-  base::FilePath new_minidump = minidump_dir.Append("minidump.dmp");
-  DummyMinidumpGenerator generator(fake_minidump.value());
+  base::FilePath new_minidump = minidump_dir.path().Append("minidump.dmp");
+  DummyMinidumpGenerator generator(fake_minidump.path().value());
   ASSERT_TRUE(generator.Generate(new_minidump.value()));
 
   // Original file should not exist, and new file should contain original
   // contents.
   std::string copied_data;
-  EXPECT_FALSE(base::PathExists(fake_minidump));
+  EXPECT_FALSE(base::PathExists(fake_minidump.path()));
   ASSERT_TRUE(base::PathExists(new_minidump));
   EXPECT_TRUE(base::ReadFileToString(new_minidump, &copied_data));
   EXPECT_EQ(data, copied_data);
diff --git a/chromecast/crash/linux/minidump_writer_unittest.cc b/chromecast/crash/linux/minidump_writer_unittest.cc
index ffb6eae1..f9156f8 100644
--- a/chromecast/crash/linux/minidump_writer_unittest.cc
+++ b/chromecast/crash/linux/minidump_writer_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/files/file_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/test/scoped_path_override.h"
+#include "chromecast/base/scoped_temp_file.h"
 #include "chromecast/crash/linux/crash_testing_utils.h"
 #include "chromecast/crash/linux/dump_info.h"
 #include "chromecast/crash/linux/minidump_generator.h"
@@ -46,10 +47,11 @@
 
   void SetUp() override {
     // Set up a temporary directory which will be used as our fake home dir.
-    base::FilePath fake_home_dir;
-    ASSERT_TRUE(base::CreateNewTempDirectory("", &fake_home_dir));
-    home_.reset(new base::ScopedPathOverride(base::DIR_HOME, fake_home_dir));
-    minidump_dir_ = fake_home_dir.Append(kMinidumpSubdir);
+    ASSERT_TRUE(fake_home_dir_.CreateUniqueTempDir());
+    home_.reset(
+        new base::ScopedPathOverride(base::DIR_HOME, fake_home_dir_.path()));
+
+    minidump_dir_ = fake_home_dir_.path().Append(kMinidumpSubdir);
     dumplog_file_ = minidump_dir_.Append(kDumplogFile);
     lockfile_path_ = minidump_dir_.Append(kLockfileName);
     metadata_path_ = minidump_dir_.Append(kMetadataName);
@@ -72,6 +74,7 @@
   base::FilePath metadata_path_;
 
  private:
+  base::ScopedTempDir fake_home_dir_;
   scoped_ptr<base::ScopedPathOverride> home_;
 
   DISALLOW_COPY_AND_ASSIGN(MinidumpWriterTest);
diff --git a/chromecast/crash/linux/synchronized_minidump_manager_unittest.cc b/chromecast/crash/linux/synchronized_minidump_manager_unittest.cc
index 4d526be27..2987cff 100644
--- a/chromecast/crash/linux/synchronized_minidump_manager_unittest.cc
+++ b/chromecast/crash/linux/synchronized_minidump_manager_unittest.cc
@@ -16,12 +16,14 @@
 #include "base/bind.h"
 #include "base/files/file.h"
 #include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/process/launch.h"
 #include "base/test/scoped_path_override.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread.h"
+#include "chromecast/base/scoped_temp_file.h"
 #include "chromecast/crash/linux/crash_testing_utils.h"
 #include "chromecast/crash/linux/dump_info.h"
 #include "chromecast/crash/linux/synchronized_minidump_manager.h"
@@ -137,10 +139,11 @@
 
   void SetUp() override {
     // Set up a temporary directory which will be used as our fake home dir.
-    ASSERT_TRUE(base::CreateNewTempDirectory("", &fake_home_dir_));
+    ASSERT_TRUE(fake_home_dir_.CreateUniqueTempDir());
     path_override_.reset(
-        new base::ScopedPathOverride(base::DIR_HOME, fake_home_dir_));
-    minidump_dir_ = fake_home_dir_.Append(kMinidumpSubdir);
+        new base::ScopedPathOverride(base::DIR_HOME, fake_home_dir_.path()));
+
+    minidump_dir_ = fake_home_dir_.path().Append(kMinidumpSubdir);
     lockfile_ = minidump_dir_.Append(kLockfileName);
     metadata_ = minidump_dir_.Append(kMetadataName);
 
@@ -154,19 +157,13 @@
     ASSERT_TRUE(lockfile.IsValid());
   }
 
-  void TearDown() override {
-    // Remove the temp directory.
-    path_override_.reset();
-    ASSERT_TRUE(base::DeleteFile(fake_home_dir_, true));
-  }
-
  protected:
-  base::FilePath fake_home_dir_;  // Path to the test home directory.
   base::FilePath minidump_dir_;   // Path the the minidump directory.
   base::FilePath lockfile_;       // Path to the lockfile in |minidump_dir_|.
   base::FilePath metadata_;       // Path to the metadata in |minidump_dir_|.
 
  private:
+  base::ScopedTempDir fake_home_dir_;
   scoped_ptr<base::ScopedPathOverride> path_override_;
 };
 
diff --git a/chromecast/media/audio/cast_audio_output_stream.cc b/chromecast/media/audio/cast_audio_output_stream.cc
index 3d1419ae..d6fab420 100644
--- a/chromecast/media/audio/cast_audio_output_stream.cc
+++ b/chromecast/media/audio/cast_audio_output_stream.cc
@@ -29,13 +29,14 @@
 MediaPipelineBackend::AudioDecoder* InitializeBackend(
     const ::media::AudioParameters& audio_params,
     MediaPipelineBackend* backend,
-    MediaPipelineBackend::Delegate* delegate) {
+    MediaPipelineBackend::Decoder::Delegate* delegate) {
   DCHECK(backend);
   DCHECK(delegate);
 
   MediaPipelineBackend::AudioDecoder* decoder = backend->CreateAudioDecoder();
   if (!decoder)
     return nullptr;
+  decoder->SetDelegate(delegate);
 
   AudioConfig audio_config;
   audio_config.codec = kCodecPCM;
@@ -48,7 +49,7 @@
   if (!decoder->SetConfig(audio_config))
     return nullptr;
 
-  if (!backend->Initialize(delegate))
+  if (!backend->Initialize())
     return nullptr;
 
   return decoder;
@@ -60,9 +61,10 @@
 // media thread (media::MediaMessageLoop::GetTaskRunner).
 // It can be created and destroyed on any thread, but all other member functions
 // must be called on a single thread.
-class CastAudioOutputStream::Backend : public MediaPipelineBackend::Delegate {
+class CastAudioOutputStream::Backend
+    : public MediaPipelineBackend::Decoder::Delegate {
  public:
-  typedef base::Callback<void(bool)> PushBufferCompletionCallback;
+  using PushBufferCompletionCallback = base::Callback<void(bool)>;
 
   Backend(const ::media::AudioParameters& audio_params)
       : audio_params_(audio_params),
@@ -137,10 +139,9 @@
     backend_buffer_ = decoder_buffer;
 
     completion_cb_ = completion_cb;
-    MediaPipelineBackend::BufferStatus status =
-        decoder_->PushBuffer(backend_buffer_.get());
+    BufferStatus status = decoder_->PushBuffer(backend_buffer_.get());
     if (status != MediaPipelineBackend::kBufferPending)
-      OnPushBufferComplete(decoder_, status);
+      OnPushBufferComplete(status);
   }
 
   void SetVolume(double volume) {
@@ -149,13 +150,8 @@
     decoder_->SetVolume(volume);
   }
 
-  // MediaPipelineBackend::Delegate implementation
-  void OnVideoResolutionChanged(MediaPipelineBackend::VideoDecoder* decoder,
-                                const Size& size) override {}
-
-  void OnPushBufferComplete(
-      MediaPipelineBackend::Decoder* decoder,
-      MediaPipelineBackend::BufferStatus status) override {
+  // MediaPipelineBackend::Decoder::Delegate implementation
+  void OnPushBufferComplete(BufferStatus status) override {
     DCHECK(thread_checker_.CalledOnValidThread());
     DCHECK_NE(status, MediaPipelineBackend::kBufferPending);
 
@@ -167,18 +163,20 @@
         .Run(status == MediaPipelineBackend::kBufferSuccess);
   }
 
-  void OnEndOfStream(MediaPipelineBackend::Decoder* decoder) override {}
+  void OnEndOfStream() override {}
 
-  void OnDecoderError(MediaPipelineBackend::Decoder* decoder) override {
+  void OnDecoderError() override {
     error_ = true;
     if (!completion_cb_.is_null())
-      OnPushBufferComplete(decoder_, MediaPipelineBackend::kBufferFailed);
+      OnPushBufferComplete(MediaPipelineBackend::kBufferFailed);
   }
 
   void OnKeyStatusChanged(const std::string& key_id,
                           CastKeyStatus key_status,
                           uint32_t system_code) override {}
 
+  void OnVideoResolutionChanged(const Size& size) override {}
+
   base::WeakPtr<CastAudioOutputStream::Backend> GetWeakPtr() {
     return weak_factory_.GetWeakPtr();
   }
diff --git a/chromecast/media/audio/cast_audio_output_stream_unittest.cc b/chromecast/media/audio/cast_audio_output_stream_unittest.cc
index 6d2f734..35d5955 100644
--- a/chromecast/media/audio/cast_audio_output_stream_unittest.cc
+++ b/chromecast/media/audio/cast_audio_output_stream_unittest.cc
@@ -46,7 +46,11 @@
         delegate_(nullptr) {}
   ~FakeAudioDecoder() override {}
 
-  // MediaPipelineBackend::AudioDecoder overrides.
+  // MediaPipelineBackend::AudioDecoder implementation:
+  void SetDelegate(Delegate* delegate) override {
+    DCHECK(delegate);
+    delegate_ = delegate;
+  }
   BufferStatus PushBuffer(CastDecoderBuffer* buffer) override {
     last_buffer_ = buffer;
     ++pushed_buffer_count_;
@@ -61,7 +65,7 @@
         return MediaPipelineBackend::kBufferFailed;
       case PIPELINE_STATUS_ASYNC_ERROR:
         pending_push_ = true;
-        delegate_->OnDecoderError(this);
+        delegate_->OnDecoderError();
         return MediaPipelineBackend::kBufferPending;
       default:
         NOTREACHED();
@@ -84,16 +88,12 @@
   void set_pipeline_status(PipelineStatus status) {
     if (status == PIPELINE_STATUS_OK && pending_push_) {
       pending_push_ = false;
-      delegate_->OnPushBufferComplete(this,
-                                      MediaPipelineBackend::kBufferSuccess);
+      delegate_->OnPushBufferComplete(MediaPipelineBackend::kBufferSuccess);
     }
     pipeline_status_ = status;
   }
   unsigned pushed_buffer_count() const { return pushed_buffer_count_; }
   CastDecoderBuffer* last_buffer() { return last_buffer_; }
-  void set_delegate(MediaPipelineBackend::Delegate* delegate) {
-    delegate_ = delegate;
-  }
 
  private:
   AudioConfig config_;
@@ -103,7 +103,7 @@
   bool pending_push_;
   int pushed_buffer_count_;
   CastDecoderBuffer* last_buffer_;
-  MediaPipelineBackend::Delegate* delegate_;
+  Delegate* delegate_;
 };
 
 class FakeMediaPipelineBackend : public MediaPipelineBackend {
@@ -124,10 +124,7 @@
     return nullptr;
   }
 
-  bool Initialize(Delegate* delegate) override {
-    audio_decoder_->set_delegate(delegate);
-    return true;
-  }
+  bool Initialize() override { return true; }
   bool Start(int64_t start_pts) override {
     EXPECT_EQ(kStateStopped, state_);
     state_ = kStateRunning;
diff --git a/chromecast/media/cma/backend/audio_decoder_default.cc b/chromecast/media/cma/backend/audio_decoder_default.cc
index 119ea0b..28887ba 100644
--- a/chromecast/media/cma/backend/audio_decoder_default.cc
+++ b/chromecast/media/cma/backend/audio_decoder_default.cc
@@ -10,22 +10,21 @@
 namespace chromecast {
 namespace media {
 
-AudioDecoderDefault::AudioDecoderDefault() : delegate_(nullptr) {
-}
+AudioDecoderDefault::AudioDecoderDefault() : delegate_(nullptr) {}
 
-AudioDecoderDefault::~AudioDecoderDefault() {
-}
+AudioDecoderDefault::~AudioDecoderDefault() {}
 
-void AudioDecoderDefault::Initialize(MediaPipelineBackend::Delegate* delegate) {
+void AudioDecoderDefault::SetDelegate(Delegate* delegate) {
   DCHECK(delegate);
   delegate_ = delegate;
 }
 
 MediaPipelineBackend::BufferStatus AudioDecoderDefault::PushBuffer(
     CastDecoderBuffer* buffer) {
+  DCHECK(delegate_);
   DCHECK(buffer);
   if (buffer->end_of_stream())
-    delegate_->OnEndOfStream(this);
+    delegate_->OnEndOfStream();
   return MediaPipelineBackend::kBufferSuccess;
 }
 
diff --git a/chromecast/media/cma/backend/audio_decoder_default.h b/chromecast/media/cma/backend/audio_decoder_default.h
index 5f1dd44..75e0dec 100644
--- a/chromecast/media/cma/backend/audio_decoder_default.h
+++ b/chromecast/media/cma/backend/audio_decoder_default.h
@@ -16,9 +16,8 @@
   AudioDecoderDefault();
   ~AudioDecoderDefault() override;
 
-  void Initialize(MediaPipelineBackend::Delegate* delegate);
-
   // MediaPipelineBackend::AudioDecoder implementation:
+  void SetDelegate(Delegate* delegate) override;
   MediaPipelineBackend::BufferStatus PushBuffer(
       CastDecoderBuffer* buffer) override;
   void GetStatistics(Statistics* statistics) override;
@@ -27,7 +26,7 @@
   RenderingDelay GetRenderingDelay() override;
 
  private:
-  MediaPipelineBackend::Delegate* delegate_;
+  Delegate* delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(AudioDecoderDefault);
 };
diff --git a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
index 8512370..bd89fd2 100644
--- a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
+++ b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
@@ -36,6 +36,8 @@
 namespace chromecast {
 namespace media {
 
+class AudioVideoPipelineDeviceTest;
+
 namespace {
 
 const base::TimeDelta kMonitorLoopDelay = base::TimeDelta::FromMilliseconds(20);
@@ -50,10 +52,52 @@
   return file_path;
 }
 
+class BufferFeeder : public MediaPipelineBackend::Decoder::Delegate {
+ public:
+  ~BufferFeeder() override {}
+
+  static scoped_ptr<BufferFeeder> LoadAudio(MediaPipelineBackend* backend,
+                                            const std::string& filename,
+                                            const base::Closure& eos_cb);
+  static scoped_ptr<BufferFeeder> LoadVideo(MediaPipelineBackend* backend,
+                                            const std::string& filename,
+                                            bool raw_h264,
+                                            const base::Closure& eos_cb);
+
+  bool eos() const { return eos_; }
+
+  void Initialize(MediaPipelineBackend::Decoder* decoder,
+                  const BufferList& buffers);
+  void Start();
+
+  // MediaPipelineBackend::Decoder::Delegate implementation:
+  void OnPushBufferComplete(MediaPipelineBackend::BufferStatus status) override;
+  void OnEndOfStream() override;
+  void OnDecoderError() override { ASSERT_TRUE(false); }
+  void OnKeyStatusChanged(const std::string& key_id,
+                          CastKeyStatus key_status,
+                          uint32_t system_code) override {
+    ASSERT_TRUE(false);
+  }
+  void OnVideoResolutionChanged(const Size& size) override {}
+
+ private:
+  explicit BufferFeeder(const base::Closure& eos_cb);
+  void FeedBuffer();
+
+  base::Closure eos_cb_;
+  bool feeding_completed_;
+  bool eos_;
+  MediaPipelineBackend::Decoder* decoder_;
+  BufferList buffers_;
+  scoped_refptr<DecoderBufferBase> pending_buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(BufferFeeder);
+};
+
 }  // namespace
 
-class AudioVideoPipelineDeviceTest : public testing::Test,
-                                     public MediaPipelineBackend::Delegate {
+class AudioVideoPipelineDeviceTest : public testing::Test {
  public:
   struct PauseInfo {
     PauseInfo() {}
@@ -91,35 +135,19 @@
   void AddPause(base::TimeDelta delay, base::TimeDelta length);
 
   void Start();
-
-  // MediaPipelineBackend::Delegate implementation:
-  void OnVideoResolutionChanged(MediaPipelineBackend::VideoDecoder* decoder,
-                                const Size& size) override {}
-  void OnPushBufferComplete(MediaPipelineBackend::Decoder* decoder,
-                            MediaPipelineBackend::BufferStatus status) override;
-  void OnEndOfStream(MediaPipelineBackend::Decoder* decoder) override;
-  void OnDecoderError(MediaPipelineBackend::Decoder* decoder) override;
-  void OnKeyStatusChanged(const std::string& key_id,
-                          CastKeyStatus key_status,
-                          uint32_t system_code) override;
+  void OnEndOfStream();
 
  private:
   void Initialize();
 
-  void LoadAudioStream(const std::string& filename);
-  void LoadVideoStream(const std::string& filename, bool raw_h264);
-
-  void FeedAudioBuffer();
-  void FeedVideoBuffer();
-
   void MonitorLoop();
 
   void OnPauseCompleted();
 
   scoped_ptr<TaskRunnerImpl> task_runner_;
   scoped_ptr<MediaPipelineBackend> backend_;
-  scoped_refptr<DecoderBufferBase> backend_audio_buffer_;
-  scoped_refptr<DecoderBufferBase> backend_video_buffer_;
+  scoped_ptr<BufferFeeder> audio_feeder_;
+  scoped_ptr<BufferFeeder> video_feeder_;
 
   // Current media time.
   base::TimeDelta pause_time_;
@@ -128,28 +156,140 @@
   std::vector<PauseInfo> pause_pattern_;
   int pause_pattern_idx_;
 
-  BufferList audio_buffers_;
-  BufferList video_buffers_;
-
-  MediaPipelineBackend::AudioDecoder* audio_decoder_;
-  MediaPipelineBackend::VideoDecoder* video_decoder_;
-  bool audio_feeding_completed_;
-  bool video_feeding_completed_;
-
   DISALLOW_COPY_AND_ASSIGN(AudioVideoPipelineDeviceTest);
 };
 
-AudioVideoPipelineDeviceTest::AudioVideoPipelineDeviceTest()
-    : pause_pattern_(),
-      audio_decoder_(nullptr),
-      video_decoder_(nullptr),
-      audio_feeding_completed_(true),
-      video_feeding_completed_(true) {
+namespace {
+
+BufferFeeder::BufferFeeder(const base::Closure& eos_cb)
+    : eos_cb_(eos_cb), feeding_completed_(false), eos_(false) {
+  CHECK(!eos_cb_.is_null());
 }
 
-AudioVideoPipelineDeviceTest::~AudioVideoPipelineDeviceTest() {
+void BufferFeeder::Initialize(MediaPipelineBackend::Decoder* decoder,
+                              const BufferList& buffers) {
+  CHECK(decoder);
+  decoder_ = decoder;
+  decoder_->SetDelegate(this);
+  buffers_ = buffers;
+  buffers_.push_back(scoped_refptr<DecoderBufferBase>(
+      new DecoderBufferAdapter(::media::DecoderBuffer::CreateEOSBuffer())));
 }
 
+void BufferFeeder::Start() {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&BufferFeeder::FeedBuffer, base::Unretained(this)));
+}
+
+void BufferFeeder::FeedBuffer() {
+  // Possibly feed one buffer.
+  CHECK(!buffers_.empty());
+  if (feeding_completed_)
+    return;
+
+  pending_buffer_ = buffers_.front();
+  BufferStatus status = decoder_->PushBuffer(pending_buffer_.get());
+  EXPECT_NE(status, MediaPipelineBackend::kBufferFailed);
+  buffers_.pop_front();
+
+  // Feeding is done, just wait for the end of stream callback.
+  if (pending_buffer_->end_of_stream() || buffers_.empty()) {
+    if (buffers_.empty() && !pending_buffer_->end_of_stream())
+      LOG(WARNING) << "Stream emptied without feeding EOS frame";
+
+    feeding_completed_ = true;
+    return;
+  }
+
+  if (status == MediaPipelineBackend::kBufferPending)
+    return;
+
+  OnPushBufferComplete(MediaPipelineBackend::kBufferSuccess);
+}
+
+void BufferFeeder::OnEndOfStream() {
+  eos_ = true;
+  eos_cb_.Run();
+}
+
+void BufferFeeder::OnPushBufferComplete(BufferStatus status) {
+  EXPECT_NE(status, MediaPipelineBackend::kBufferFailed);
+  if (feeding_completed_)
+    return;
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&BufferFeeder::FeedBuffer, base::Unretained(this)));
+}
+
+// static
+scoped_ptr<BufferFeeder> BufferFeeder::LoadAudio(MediaPipelineBackend* backend,
+                                                 const std::string& filename,
+                                                 const base::Closure& eos_cb) {
+  CHECK(backend);
+  base::FilePath file_path = GetTestDataFilePath(filename);
+  DemuxResult demux_result = FFmpegDemuxForTest(file_path, true /* audio */);
+
+  MediaPipelineBackend::AudioDecoder* decoder = backend->CreateAudioDecoder();
+  CHECK(decoder);
+
+  bool success = decoder->SetConfig(DecoderConfigAdapter::ToCastAudioConfig(
+      kPrimary, demux_result.audio_config));
+  CHECK(success);
+
+  VLOG(2) << "Got " << demux_result.frames.size() << " audio input frames";
+  scoped_ptr<BufferFeeder> feeder(new BufferFeeder(eos_cb));
+  feeder->Initialize(decoder, demux_result.frames);
+  return feeder;
+}
+
+// static
+scoped_ptr<BufferFeeder> BufferFeeder::LoadVideo(MediaPipelineBackend* backend,
+                                                 const std::string& filename,
+                                                 bool raw_h264,
+                                                 const base::Closure& eos_cb) {
+  CHECK(backend);
+
+  VideoConfig video_config;
+  BufferList buffers;
+  if (raw_h264) {
+    base::FilePath file_path = GetTestDataFilePath(filename);
+    base::MemoryMappedFile video_stream;
+    CHECK(video_stream.Initialize(file_path)) << "Couldn't open stream file: "
+                                              << file_path.MaybeAsASCII();
+    buffers = H264SegmenterForTest(video_stream.data(), video_stream.length());
+
+    // TODO(erickung): Either pull data from stream or make caller specify value
+    video_config.codec = kCodecH264;
+    video_config.profile = kH264Main;
+    video_config.additional_config = NULL;
+    video_config.is_encrypted = false;
+  } else {
+    base::FilePath file_path = GetTestDataFilePath(filename);
+    DemuxResult demux_result = FFmpegDemuxForTest(file_path, false /* audio */);
+    buffers = demux_result.frames;
+    video_config = DecoderConfigAdapter::ToCastVideoConfig(
+        kPrimary, demux_result.video_config);
+  }
+
+  MediaPipelineBackend::VideoDecoder* decoder = backend->CreateVideoDecoder();
+  CHECK(decoder);
+
+  bool success = decoder->SetConfig(video_config);
+  CHECK(success);
+
+  VLOG(2) << "Got " << buffers.size() << " video input frames";
+  scoped_ptr<BufferFeeder> feeder(new BufferFeeder(eos_cb));
+  feeder->Initialize(decoder, buffers);
+  return feeder;
+}
+
+}  // namespace
+
+AudioVideoPipelineDeviceTest::AudioVideoPipelineDeviceTest()
+    : pause_pattern_() {}
+
+AudioVideoPipelineDeviceTest::~AudioVideoPipelineDeviceTest() {}
+
 void AudioVideoPipelineDeviceTest::AddPause(base::TimeDelta delay,
                                             base::TimeDelta length) {
   pause_pattern_.push_back(PauseInfo(delay, length));
@@ -163,8 +303,11 @@
 void AudioVideoPipelineDeviceTest::ConfigureForAudioOnly(
     const std::string& filename) {
   Initialize();
-  LoadAudioStream(filename);
-  bool success = backend_->Initialize(this);
+  audio_feeder_ = BufferFeeder::LoadAudio(
+      backend_.get(), filename,
+      base::Bind(&AudioVideoPipelineDeviceTest::OnEndOfStream,
+                 base::Unretained(this)));
+  bool success = backend_->Initialize();
   ASSERT_TRUE(success);
 }
 
@@ -172,151 +315,34 @@
     const std::string& filename,
     bool raw_h264) {
   Initialize();
-  LoadVideoStream(filename, raw_h264);
-  bool success = backend_->Initialize(this);
+  video_feeder_ = BufferFeeder::LoadVideo(
+      backend_.get(), filename, raw_h264,
+      base::Bind(&AudioVideoPipelineDeviceTest::OnEndOfStream,
+                 base::Unretained(this)));
+  bool success = backend_->Initialize();
   ASSERT_TRUE(success);
 }
 
 void AudioVideoPipelineDeviceTest::ConfigureForFile(
     const std::string& filename) {
   Initialize();
-  LoadVideoStream(filename, false /* raw_h264 */);
-  LoadAudioStream(filename);
-  bool success = backend_->Initialize(this);
+  base::Closure eos_cb = base::Bind(
+      &AudioVideoPipelineDeviceTest::OnEndOfStream, base::Unretained(this));
+  video_feeder_ = BufferFeeder::LoadVideo(backend_.get(), filename,
+                                          false /* raw_h264 */, eos_cb);
+  audio_feeder_ = BufferFeeder::LoadAudio(backend_.get(), filename, eos_cb);
+  bool success = backend_->Initialize();
   ASSERT_TRUE(success);
 }
 
-void AudioVideoPipelineDeviceTest::LoadAudioStream(
-    const std::string& filename) {
-  base::FilePath file_path = GetTestDataFilePath(filename);
-  DemuxResult demux_result = FFmpegDemuxForTest(file_path, true /* audio */);
-
-  audio_buffers_ = demux_result.frames;
-  audio_decoder_ = backend_->CreateAudioDecoder();
-  audio_feeding_completed_ = false;
-
-  bool success =
-      audio_decoder_->SetConfig(DecoderConfigAdapter::ToCastAudioConfig(
-          kPrimary, demux_result.audio_config));
-  ASSERT_TRUE(success);
-
-  VLOG(2) << "Got " << audio_buffers_.size() << " audio input frames";
-
-  audio_buffers_.push_back(scoped_refptr<DecoderBufferBase>(
-      new DecoderBufferAdapter(::media::DecoderBuffer::CreateEOSBuffer())));
-}
-
-void AudioVideoPipelineDeviceTest::LoadVideoStream(const std::string& filename,
-                                                   bool raw_h264) {
-  VideoConfig video_config;
-
-  if (raw_h264) {
-    base::FilePath file_path = GetTestDataFilePath(filename);
-    base::MemoryMappedFile video_stream;
-    ASSERT_TRUE(video_stream.Initialize(file_path))
-        << "Couldn't open stream file: " << file_path.MaybeAsASCII();
-    video_buffers_ =
-        H264SegmenterForTest(video_stream.data(), video_stream.length());
-
-    // TODO(erickung): Either pull data from stream or make caller specify value
-    video_config.codec = kCodecH264;
-    video_config.profile = kH264Main;
-    video_config.additional_config = NULL;
-    video_config.is_encrypted = false;
-  } else {
-    base::FilePath file_path = GetTestDataFilePath(filename);
-    DemuxResult demux_result = FFmpegDemuxForTest(file_path,
-                                                  /*audio*/ false);
-    video_buffers_ = demux_result.frames;
-    video_config = DecoderConfigAdapter::ToCastVideoConfig(
-        kPrimary, demux_result.video_config);
-  }
-
-  video_decoder_ = backend_->CreateVideoDecoder();
-  video_feeding_completed_ = false;
-  bool success = video_decoder_->SetConfig(video_config);
-  ASSERT_TRUE(success);
-
-  VLOG(2) << "Got " << video_buffers_.size() << " video input frames";
-
-  video_buffers_.push_back(scoped_refptr<DecoderBufferBase>(
-      new DecoderBufferAdapter(::media::DecoderBuffer::CreateEOSBuffer())));
-}
-
-void AudioVideoPipelineDeviceTest::FeedAudioBuffer() {
-  // Possibly feed one frame
-  DCHECK(!audio_buffers_.empty());
-  if (audio_feeding_completed_)
-    return;
-
-  backend_audio_buffer_ = audio_buffers_.front();
-
-  MediaPipelineBackend::BufferStatus status =
-      audio_decoder_->PushBuffer(backend_audio_buffer_.get());
-  EXPECT_NE(status, MediaPipelineBackend::kBufferFailed);
-  audio_buffers_.pop_front();
-
-  // Feeding is done, just wait for the end of stream callback.
-  if (backend_audio_buffer_->end_of_stream() || audio_buffers_.empty()) {
-    if (audio_buffers_.empty() && !backend_audio_buffer_->end_of_stream()) {
-      LOG(WARNING) << "Stream emptied without feeding EOS frame";
-    }
-
-    audio_feeding_completed_ = true;
-    return;
-  }
-
-  if (status == MediaPipelineBackend::kBufferPending)
-    return;
-
-  OnPushBufferComplete(audio_decoder_, MediaPipelineBackend::kBufferSuccess);
-}
-
-void AudioVideoPipelineDeviceTest::FeedVideoBuffer() {
-  // Possibly feed one frame
-  DCHECK(!video_buffers_.empty());
-  if (video_feeding_completed_)
-    return;
-
-  backend_video_buffer_ = video_buffers_.front();
-
-  MediaPipelineBackend::BufferStatus status =
-      video_decoder_->PushBuffer(backend_video_buffer_.get());
-  EXPECT_NE(status, MediaPipelineBackend::kBufferFailed);
-  video_buffers_.pop_front();
-
-  // Feeding is done, just wait for the end of stream callback.
-  if (backend_video_buffer_->end_of_stream() || video_buffers_.empty()) {
-    if (video_buffers_.empty() && !backend_video_buffer_->end_of_stream()) {
-      LOG(WARNING) << "Stream emptied without feeding EOS frame";
-    }
-
-    video_feeding_completed_ = true;
-    return;
-  }
-
-  if (status == MediaPipelineBackend::kBufferPending)
-    return;
-
-  OnPushBufferComplete(video_decoder_, MediaPipelineBackend::kBufferSuccess);
-}
-
 void AudioVideoPipelineDeviceTest::Start() {
   pause_time_ = base::TimeDelta();
   pause_pattern_idx_ = 0;
 
-  if (audio_decoder_) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::Bind(&AudioVideoPipelineDeviceTest::FeedAudioBuffer,
-                   base::Unretained(this)));
-  }
-  if (video_decoder_) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::Bind(&AudioVideoPipelineDeviceTest::FeedVideoBuffer,
-                   base::Unretained(this)));
-  }
+  if (audio_feeder_)
+    audio_feeder_->Start();
+  if (video_feeder_)
+    video_feeder_->Start();
 
   backend_->Start(0);
 
@@ -325,59 +351,18 @@
                             base::Unretained(this)));
 }
 
-void AudioVideoPipelineDeviceTest::OnEndOfStream(
-    MediaPipelineBackend::Decoder* decoder) {
-
-  if (decoder == audio_decoder_)
-    audio_decoder_ = nullptr;
-  else if (decoder == video_decoder_)
-    video_decoder_ = nullptr;
-
-  if (!audio_decoder_ && !video_decoder_) {
+void AudioVideoPipelineDeviceTest::OnEndOfStream() {
+  if ((!audio_feeder_ || audio_feeder_->eos()) &&
+      (!video_feeder_ || video_feeder_->eos())) {
     bool success = backend_->Stop();
     ASSERT_TRUE(success);
     base::MessageLoop::current()->QuitWhenIdle();
   }
 }
 
-void AudioVideoPipelineDeviceTest::OnDecoderError(
-    MediaPipelineBackend::Decoder* decoder) {
-  ASSERT_TRUE(false);
-}
-
-void AudioVideoPipelineDeviceTest::OnKeyStatusChanged(const std::string& key_id,
-                                                      CastKeyStatus key_status,
-                                                      uint32_t system_code) {
-  ASSERT_TRUE(false);
-}
-
-void AudioVideoPipelineDeviceTest::OnPushBufferComplete(
-    MediaPipelineBackend::Decoder* decoder,
-    MediaPipelineBackend::BufferStatus status) {
-  EXPECT_NE(status, MediaPipelineBackend::kBufferFailed);
-
-  if (decoder == audio_decoder_) {
-    if (audio_feeding_completed_)
-      return;
-
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::Bind(&AudioVideoPipelineDeviceTest::FeedAudioBuffer,
-                   base::Unretained(this)));
-  } else if (decoder == video_decoder_) {
-    if (video_feeding_completed_)
-      return;
-
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::Bind(&AudioVideoPipelineDeviceTest::FeedVideoBuffer,
-                   base::Unretained(this)));
-  }
-}
-
 void AudioVideoPipelineDeviceTest::MonitorLoop() {
   // Backend is stopped, no need to monitor the loop any more.
-  if (audio_decoder_ == nullptr && video_decoder_ == nullptr)
+  if (!audio_feeder_ && !video_feeder_)
     return;
 
   base::TimeDelta media_time =
@@ -438,7 +423,7 @@
   task_runner_.reset(new TaskRunnerImpl());
   MediaPipelineDeviceParams params(task_runner_.get());
   backend_.reset(CastMediaShlib::CreateMediaPipelineBackend(params));
-  DCHECK(backend_);
+  CHECK(backend_);
 }
 
 TEST_F(AudioVideoPipelineDeviceTest, Mp3Playback) {
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_default.cc b/chromecast/media/cma/backend/media_pipeline_backend_default.cc
index 4f93f86..5ad1260 100644
--- a/chromecast/media/cma/backend/media_pipeline_backend_default.cc
+++ b/chromecast/media/cma/backend/media_pipeline_backend_default.cc
@@ -32,12 +32,7 @@
   return video_decoder_.get();
 }
 
-bool MediaPipelineBackendDefault::Initialize(Delegate* delegate) {
-  DCHECK(delegate);
-  if (audio_decoder_)
-    audio_decoder_->Initialize(delegate);
-  if (video_decoder_)
-    video_decoder_->Initialize(delegate);
+bool MediaPipelineBackendDefault::Initialize() {
   return true;
 }
 
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_default.h b/chromecast/media/cma/backend/media_pipeline_backend_default.h
index 59fb36c..9fb1611 100644
--- a/chromecast/media/cma/backend/media_pipeline_backend_default.h
+++ b/chromecast/media/cma/backend/media_pipeline_backend_default.h
@@ -24,7 +24,7 @@
   // MediaPipelineBackend implementation:
   AudioDecoder* CreateAudioDecoder() override;
   VideoDecoder* CreateVideoDecoder() override;
-  bool Initialize(Delegate* delegate) override;
+  bool Initialize() override;
   bool Start(int64_t start_pts) override;
   bool Stop() override;
   bool Pause() override;
diff --git a/chromecast/media/cma/backend/video_decoder_default.cc b/chromecast/media/cma/backend/video_decoder_default.cc
index 143dc79..257332e 100644
--- a/chromecast/media/cma/backend/video_decoder_default.cc
+++ b/chromecast/media/cma/backend/video_decoder_default.cc
@@ -10,22 +10,21 @@
 namespace chromecast {
 namespace media {
 
-VideoDecoderDefault::VideoDecoderDefault() : delegate_(nullptr) {
-}
+VideoDecoderDefault::VideoDecoderDefault() : delegate_(nullptr) {}
 
-VideoDecoderDefault::~VideoDecoderDefault() {
-}
+VideoDecoderDefault::~VideoDecoderDefault() {}
 
-void VideoDecoderDefault::Initialize(MediaPipelineBackend::Delegate* delegate) {
+void VideoDecoderDefault::SetDelegate(Delegate* delegate) {
   DCHECK(delegate);
   delegate_ = delegate;
 }
 
 MediaPipelineBackend::BufferStatus VideoDecoderDefault::PushBuffer(
     CastDecoderBuffer* buffer) {
+  DCHECK(delegate_);
   DCHECK(buffer);
   if (buffer->end_of_stream())
-    delegate_->OnEndOfStream(this);
+    delegate_->OnEndOfStream();
   return MediaPipelineBackend::kBufferSuccess;
 }
 
diff --git a/chromecast/media/cma/backend/video_decoder_default.h b/chromecast/media/cma/backend/video_decoder_default.h
index 25128ef..5b71edd7 100644
--- a/chromecast/media/cma/backend/video_decoder_default.h
+++ b/chromecast/media/cma/backend/video_decoder_default.h
@@ -16,16 +16,15 @@
   VideoDecoderDefault();
   ~VideoDecoderDefault() override;
 
-  void Initialize(MediaPipelineBackend::Delegate* delegate);
-
   // MediaPipelineBackend::VideoDecoder implementation:
+  void SetDelegate(Delegate* delegate) override;
   MediaPipelineBackend::BufferStatus PushBuffer(
       CastDecoderBuffer* buffer) override;
   void GetStatistics(Statistics* statistics) override;
   bool SetConfig(const VideoConfig& config) override;
 
  private:
-  MediaPipelineBackend::Delegate* delegate_;
+  Delegate* delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(VideoDecoderDefault);
 };
diff --git a/chromecast/media/cma/pipeline/audio_pipeline_impl.cc b/chromecast/media/cma/pipeline/audio_pipeline_impl.cc
index 39fe92a..5aa3c1a06 100644
--- a/chromecast/media/cma/pipeline/audio_pipeline_impl.cc
+++ b/chromecast/media/cma/pipeline/audio_pipeline_impl.cc
@@ -9,7 +9,6 @@
 #include "chromecast/media/cma/base/cma_logging.h"
 #include "chromecast/media/cma/base/coded_frame_provider.h"
 #include "chromecast/media/cma/base/decoder_config_adapter.h"
-#include "chromecast/media/cma/pipeline/av_pipeline_impl.h"
 #include "chromecast/public/media/decoder_config.h"
 #include "media/base/audio_decoder_config.h"
 
@@ -23,125 +22,36 @@
 AudioPipelineImpl::AudioPipelineImpl(
     MediaPipelineBackend::AudioDecoder* decoder,
     const AvPipelineClient& client)
-    : decoder_(decoder), audio_client_(client), weak_factory_(this) {
-  av_pipeline_impl_.reset(new AvPipelineImpl(
-      decoder_,
-      base::Bind(&AudioPipelineImpl::OnUpdateConfig, base::Unretained(this))));
-  weak_this_ = weak_factory_.GetWeakPtr();
+    : AvPipelineImpl(decoder, client), audio_decoder_(decoder) {
+  DCHECK(audio_decoder_);
 }
 
 AudioPipelineImpl::~AudioPipelineImpl() {
 }
 
-void AudioPipelineImpl::SetCodedFrameProvider(
-    scoped_ptr<CodedFrameProvider> frame_provider) {
-  av_pipeline_impl_->SetCodedFrameProvider(
-      frame_provider.Pass(), kAppAudioBufferSize, kMaxAudioFrameSize);
-}
-
-bool AudioPipelineImpl::StartPlayingFrom(
-    base::TimeDelta time,
-    const scoped_refptr<BufferingState>& buffering_state) {
-  CMALOG(kLogControl) << __FUNCTION__ << " t0=" << time.InMilliseconds();
-
-  // Reset the pipeline statistics.
-  previous_stats_ = ::media::PipelineStatistics();
-
-  // Start playing.
-  if (av_pipeline_impl_->GetState() == AvPipelineImpl::kError)
-    return false;
-  DCHECK_EQ(av_pipeline_impl_->GetState(), AvPipelineImpl::kFlushed);
-
-  if (!av_pipeline_impl_->StartPlayingFrom(time, buffering_state)) {
-    av_pipeline_impl_->TransitionToState(AvPipelineImpl::kError);
-    return false;
-  }
-  av_pipeline_impl_->TransitionToState(AvPipelineImpl::kPlaying);
-
-  return true;
-}
-
-bool AudioPipelineImpl::StartFlush() {
-  CMALOG(kLogControl) << __FUNCTION__;
-  if (av_pipeline_impl_->GetState() == AvPipelineImpl::kError) {
-    return false;
-  }
-  DCHECK_EQ(av_pipeline_impl_->GetState(), AvPipelineImpl::kPlaying);
-  av_pipeline_impl_->TransitionToState(AvPipelineImpl::kFlushing);
-  return true;
-}
-
-void AudioPipelineImpl::Flush(const ::media::PipelineStatusCB& status_cb) {
-  CMALOG(kLogControl) << __FUNCTION__;
-  DCHECK_EQ(av_pipeline_impl_->GetState(), AvPipelineImpl::kFlushing);
-  av_pipeline_impl_->Flush(
-      base::Bind(&AudioPipelineImpl::OnFlushDone, weak_this_, status_cb));
-}
-
-void AudioPipelineImpl::BackendStopped() {
-  CMALOG(kLogControl) << __FUNCTION__;
-  av_pipeline_impl_->BackendStopped();
-}
-
-void AudioPipelineImpl::OnFlushDone(
-    const ::media::PipelineStatusCB& status_cb) {
-  CMALOG(kLogControl) << __FUNCTION__;
-  if (av_pipeline_impl_->GetState() == AvPipelineImpl::kError) {
-    status_cb.Run(::media::PIPELINE_ERROR_ABORT);
-    return;
-  }
-  av_pipeline_impl_->TransitionToState(AvPipelineImpl::kFlushed);
-  status_cb.Run(::media::PIPELINE_OK);
-}
-
-void AudioPipelineImpl::Stop() {
-  CMALOG(kLogControl) << __FUNCTION__;
-  av_pipeline_impl_->Stop();
-  av_pipeline_impl_->TransitionToState(AvPipelineImpl::kStopped);
-}
-
-void AudioPipelineImpl::SetCdm(BrowserCdmCast* media_keys) {
-  av_pipeline_impl_->SetCdm(media_keys);
-}
-
 void AudioPipelineImpl::Initialize(
     const ::media::AudioDecoderConfig& audio_config,
     scoped_ptr<CodedFrameProvider> frame_provider,
     const ::media::PipelineStatusCB& status_cb) {
   CMALOG(kLogControl) << __FUNCTION__ << " "
                       << audio_config.AsHumanReadableString();
-  if (frame_provider)
-    SetCodedFrameProvider(frame_provider.Pass());
+  if (frame_provider) {
+    SetCodedFrameProvider(frame_provider.Pass(), kAppAudioBufferSize,
+                          kMaxAudioFrameSize);
+  }
 
   DCHECK(audio_config.IsValidConfig());
-  if (!decoder_->SetConfig(
+  if (!audio_decoder_->SetConfig(
           DecoderConfigAdapter::ToCastAudioConfig(kPrimary, audio_config))) {
     status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED);
     return;
   }
-  av_pipeline_impl_->TransitionToState(AvPipelineImpl::kFlushed);
+  TransitionToState(kFlushed);
   status_cb.Run(::media::PIPELINE_OK);
 }
 
 void AudioPipelineImpl::SetVolume(float volume) {
-  decoder_->SetVolume(volume);
-}
-
-void AudioPipelineImpl::OnBufferPushed(
-    MediaPipelineBackend::BufferStatus status) {
-  av_pipeline_impl_->OnBufferPushed(status);
-}
-
-void AudioPipelineImpl::OnEndOfStream() {
-  if (!audio_client_.eos_cb.is_null())
-    audio_client_.eos_cb.Run();
-}
-
-void AudioPipelineImpl::OnError() {
-  if (!audio_client_.playback_error_cb.is_null()) {
-    audio_client_.playback_error_cb.Run(
-        ::media::PIPELINE_ERROR_COULD_NOT_RENDER);
-  }
+  audio_decoder_->SetVolume(volume);
 }
 
 void AudioPipelineImpl::OnUpdateConfig(
@@ -152,19 +62,19 @@
     CMALOG(kLogControl) << __FUNCTION__ << " id:" << id << " "
                         << audio_config.AsHumanReadableString();
 
-    bool success = decoder_->SetConfig(
+    bool success = audio_decoder_->SetConfig(
         DecoderConfigAdapter::ToCastAudioConfig(id, audio_config));
-    if (!success && !audio_client_.playback_error_cb.is_null())
-      audio_client_.playback_error_cb.Run(::media::PIPELINE_ERROR_DECODE);
+    if (!success && !client().playback_error_cb.is_null())
+      client().playback_error_cb.Run(::media::PIPELINE_ERROR_DECODE);
   }
 }
 
 void AudioPipelineImpl::UpdateStatistics() {
-  if (audio_client_.statistics_cb.is_null())
+  if (client().statistics_cb.is_null())
     return;
 
   MediaPipelineBackend::Decoder::Statistics device_stats;
-  decoder_->GetStatistics(&device_stats);
+  audio_decoder_->GetStatistics(&device_stats);
 
   ::media::PipelineStatistics current_stats;
   current_stats.audio_bytes_decoded = device_stats.decoded_bytes;
@@ -175,7 +85,7 @@
 
   previous_stats_ = current_stats;
 
-  audio_client_.statistics_cb.Run(delta_stats);
+  client().statistics_cb.Run(delta_stats);
 }
 
 }  // namespace media
diff --git a/chromecast/media/cma/pipeline/audio_pipeline_impl.h b/chromecast/media/cma/pipeline/audio_pipeline_impl.h
index 4e6193d..b7e5a765 100644
--- a/chromecast/media/cma/pipeline/audio_pipeline_impl.h
+++ b/chromecast/media/cma/pipeline/audio_pipeline_impl.h
@@ -5,14 +5,15 @@
 #ifndef CHROMECAST_MEDIA_CMA_BASE_AUDIO_PIPELINE_IMPL_H_
 #define CHROMECAST_MEDIA_CMA_BASE_AUDIO_PIPELINE_IMPL_H_
 
-#include "base/callback.h"
+#include <vector>
+
 #include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
+#include "base/memory/scoped_ptr.h"
 #include "chromecast/media/cma/pipeline/av_pipeline_client.h"
+#include "chromecast/media/cma/pipeline/av_pipeline_impl.h"
 #include "chromecast/public/media/media_pipeline_backend.h"
 #include "chromecast/public/media/stream_id.h"
+#include "media/base/pipeline_status.h"
 
 namespace media {
 class AudioDecoderConfig;
@@ -21,59 +22,31 @@
 
 namespace chromecast {
 namespace media {
-class AvPipelineImpl;
-class BrowserCdmCast;
-class BufferingState;
 class CodedFrameProvider;
 
-class AudioPipelineImpl {
+class AudioPipelineImpl : public AvPipelineImpl {
  public:
   AudioPipelineImpl(MediaPipelineBackend::AudioDecoder* decoder,
                     const AvPipelineClient& client);
-  ~AudioPipelineImpl();
+  ~AudioPipelineImpl() override;
 
-  // Input port of the pipeline.
-  void SetCodedFrameProvider(scoped_ptr<CodedFrameProvider> frame_provider);
-
-  // Provide the CDM to use to decrypt samples.
-  void SetCdm(BrowserCdmCast* media_keys);
-
-  // Functions to control the state of the audio pipeline.
   void Initialize(
       const ::media::AudioDecoderConfig& config,
       scoped_ptr<CodedFrameProvider> frame_provider,
       const ::media::PipelineStatusCB& status_cb);
-  bool StartPlayingFrom(base::TimeDelta time,
-                        const scoped_refptr<BufferingState>& buffering_state);
-  bool StartFlush();
-  void Flush(const ::media::PipelineStatusCB& status_cb);
-  void BackendStopped();
-  void Stop();
-
-  // Update the playback statistics for this audio stream.
-  void UpdateStatistics();
 
   void SetVolume(float volume);
 
-  void OnBufferPushed(MediaPipelineBackend::BufferStatus status);
-  void OnEndOfStream();
-  void OnError();
+  // AvPipelineImpl implementation:
+  void UpdateStatistics() override;
 
  private:
-  void OnFlushDone(const ::media::PipelineStatusCB& status_cb);
+  // AvPipelineImpl implementation:
   void OnUpdateConfig(StreamId id,
                       const ::media::AudioDecoderConfig& audio_config,
-                      const ::media::VideoDecoderConfig& video_config);
+                      const ::media::VideoDecoderConfig& video_config) override;
 
-  MediaPipelineBackend::AudioDecoder* decoder_;
-
-  scoped_ptr<AvPipelineImpl> av_pipeline_impl_;
-  AvPipelineClient audio_client_;
-
-  ::media::PipelineStatistics previous_stats_;
-
-  base::WeakPtr<AudioPipelineImpl> weak_this_;
-  base::WeakPtrFactory<AudioPipelineImpl> weak_factory_;
+  MediaPipelineBackend::AudioDecoder* const audio_decoder_;
 
   DISALLOW_COPY_AND_ASSIGN(AudioPipelineImpl);
 };
diff --git a/chromecast/media/cma/pipeline/av_pipeline_impl.cc b/chromecast/media/cma/pipeline/av_pipeline_impl.cc
index 0d7a5bc0..906ca48 100644
--- a/chromecast/media/cma/pipeline/av_pipeline_impl.cc
+++ b/chromecast/media/cma/pipeline/av_pipeline_impl.cc
@@ -33,9 +33,9 @@
 }  // namespace
 
 AvPipelineImpl::AvPipelineImpl(MediaPipelineBackend::Decoder* decoder,
-                               const UpdateConfigCB& update_config_cb)
-    : update_config_cb_(update_config_cb),
-      decoder_(decoder),
+                               const AvPipelineClient& client)
+    : decoder_(decoder),
+      client_(client),
       state_(kUninitialized),
       buffered_time_(::media::kNoTimestamp()),
       playable_buffered_time_(::media::kNoTimestamp()),
@@ -47,6 +47,7 @@
       media_keys_callback_id_(kNoCallbackId),
       weak_factory_(this) {
   DCHECK(decoder_);
+  decoder_->SetDelegate(this);
   weak_this_ = weak_factory_.GetWeakPtr();
   thread_checker_.DetachFromThread();
 }
@@ -89,7 +90,16 @@
 bool AvPipelineImpl::StartPlayingFrom(
     base::TimeDelta time,
     const scoped_refptr<BufferingState>& buffering_state) {
+  CMALOG(kLogControl) << __FUNCTION__ << " t0=" << time.InMilliseconds();
   DCHECK(thread_checker_.CalledOnValidThread());
+
+  // Reset the pipeline statistics.
+  previous_stats_ = ::media::PipelineStatistics();
+
+  if (state_ == kError) {
+    CMALOG(kLogControl) << __FUNCTION__ << " called while in error state";
+    return false;
+  }
   DCHECK_EQ(state_, kFlushed);
 
   // Buffering related initialization.
@@ -103,10 +113,21 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_));
 
+  TransitionToState(kPlaying);
   return true;
 }
 
-void AvPipelineImpl::Flush(const base::Closure& done_cb) {
+bool AvPipelineImpl::StartFlush() {
+  CMALOG(kLogControl) << __FUNCTION__;
+  if (state_ == kError)
+    return false;
+  DCHECK_EQ(state_, kPlaying);
+  TransitionToState(kFlushing);
+  return true;
+}
+
+void AvPipelineImpl::Flush(const ::media::PipelineStatusCB& status_cb) {
+  CMALOG(kLogControl) << __FUNCTION__;
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK_EQ(state_, kFlushing);
 
@@ -115,25 +136,35 @@
   buffered_time_ = ::media::kNoTimestamp();
   playable_buffered_time_ = ::media::kNoTimestamp();
   non_playable_frames_.clear();
-  frame_provider_->Flush(done_cb);
+  frame_provider_->Flush(
+      base::Bind(&AvPipelineImpl::OnFlushDone, weak_this_, status_cb));
 }
 
 void AvPipelineImpl::BackendStopped() {
+  CMALOG(kLogControl) << __FUNCTION__;
   DCHECK(thread_checker_.CalledOnValidThread());
 
   // Note: returning to idle state aborts any pending frame push.
   pushed_buffer_ = nullptr;
 }
 
+void AvPipelineImpl::OnFlushDone(const ::media::PipelineStatusCB& status_cb) {
+  CMALOG(kLogControl) << __FUNCTION__;
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (state_ == kError) {
+    status_cb.Run(::media::PIPELINE_ERROR_ABORT);
+    return;
+  }
+  TransitionToState(kFlushed);
+  status_cb.Run(::media::PIPELINE_OK);
+}
+
 void AvPipelineImpl::Stop() {
   DCHECK(thread_checker_.CalledOnValidThread());
-
-  // Stop can be called from any state.
-  if (state_ == kUninitialized || state_ == kStopped)
-    return;
-
+  CMALOG(kLogControl) << __FUNCTION__;
   // Stop feeding the pipeline.
   enable_feeding_ = false;
+  TransitionToState(kStopped);
 }
 
 void AvPipelineImpl::SetCdm(BrowserCdmCast* media_keys) {
@@ -173,7 +204,7 @@
     return;
 
   if (audio_config.IsValidConfig() || video_config.IsValidConfig())
-    update_config_cb_.Run(buffer->stream_id(), audio_config, video_config);
+    OnUpdateConfig(buffer->stream_id(), audio_config, video_config);
 
   pending_buffer_ = buffer;
   ProcessPendingBuffer();
@@ -247,10 +278,10 @@
       decoder_->PushBuffer(pushed_buffer_.get());
 
   if (status != MediaPipelineBackend::kBufferPending)
-    OnBufferPushed(status);
+    OnPushBufferComplete(status);
 }
 
-void AvPipelineImpl::OnBufferPushed(MediaPipelineBackend::BufferStatus status) {
+void AvPipelineImpl::OnPushBufferComplete(BufferStatus status) {
   DCHECK(thread_checker_.CalledOnValidThread());
   pushed_buffer_ = nullptr;
   if (status == MediaPipelineBackend::kBufferFailed) {
@@ -263,6 +294,28 @@
       FROM_HERE, base::Bind(&AvPipelineImpl::ProcessPendingBuffer, weak_this_));
 }
 
+void AvPipelineImpl::OnEndOfStream() {
+  if (!client_.eos_cb.is_null())
+    client_.eos_cb.Run();
+}
+
+void AvPipelineImpl::OnDecoderError() {
+  if (!client_.playback_error_cb.is_null())
+    client_.playback_error_cb.Run(::media::PIPELINE_ERROR_COULD_NOT_RENDER);
+}
+
+void AvPipelineImpl::OnKeyStatusChanged(const std::string& key_id,
+                                        CastKeyStatus key_status,
+                                        uint32_t system_code) {
+  CMALOG(kLogControl) << __FUNCTION__;
+  DCHECK(media_keys_);
+  media_keys_->SetKeyStatus(key_id, key_status, system_code);
+}
+
+void AvPipelineImpl::OnVideoResolutionChanged(const Size& size) {
+  // Ignored here; VideoPipelineImpl overrides this method.
+}
+
 void AvPipelineImpl::OnCdmStateChanged() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
diff --git a/chromecast/media/cma/pipeline/av_pipeline_impl.h b/chromecast/media/cma/pipeline/av_pipeline_impl.h
index 28a885b4..5769636 100644
--- a/chromecast/media/cma/pipeline/av_pipeline_impl.h
+++ b/chromecast/media/cma/pipeline/av_pipeline_impl.h
@@ -10,10 +10,13 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
+#include "chromecast/media/cma/pipeline/av_pipeline_client.h"
 #include "chromecast/public/media/media_pipeline_backend.h"
 #include "chromecast/public/media/stream_id.h"
+#include "media/base/pipeline_status.h"
 
 namespace media {
 class AudioDecoderConfig;
@@ -28,8 +31,30 @@
 class CodedFrameProvider;
 class DecoderBufferBase;
 
-class AvPipelineImpl {
+class AvPipelineImpl : MediaPipelineBackend::Decoder::Delegate {
  public:
+  AvPipelineImpl(MediaPipelineBackend::Decoder* decoder,
+                 const AvPipelineClient& client);
+  ~AvPipelineImpl() override;
+
+  void SetCdm(BrowserCdmCast* media_keys);
+
+  // Setup the pipeline and ensure samples are available for the given media
+  // time, then start rendering samples.
+  bool StartPlayingFrom(base::TimeDelta time,
+                        const scoped_refptr<BufferingState>& buffering_state);
+
+  bool StartFlush();
+  void Flush(const ::media::PipelineStatusCB& status_cb);
+  // Resets any pending buffers after the backend has been stopped.
+  void BackendStopped();
+
+  // Tear down the pipeline and release the hardware resources.
+  void Stop();
+
+  virtual void UpdateStatistics() = 0;
+
+ protected:
   // Pipeline states.
   enum State {
     kUninitialized,
@@ -40,43 +65,34 @@
     kError,
   };
 
-  typedef base::Callback<
-      void(StreamId id,
-           const ::media::AudioDecoderConfig&,
-           const ::media::VideoDecoderConfig&)> UpdateConfigCB;
+  State state() const { return state_; }
+  const AvPipelineClient& client() const { return client_; }
 
-  AvPipelineImpl(MediaPipelineBackend::Decoder* decoder,
-                 const UpdateConfigCB& update_config_cb);
-  ~AvPipelineImpl();
+  virtual void OnUpdateConfig(
+      StreamId id,
+      const ::media::AudioDecoderConfig& audio_config,
+      const ::media::VideoDecoderConfig& video_config) = 0;
 
-  // Setting the frame provider or the client must be done in the
-  // |kUninitialized| state.
+  void TransitionToState(State state);
+  // Setting the frame provider must be done in the |kUninitialized| state.
   void SetCodedFrameProvider(scoped_ptr<CodedFrameProvider> frame_provider,
                              size_t max_buffer_size,
                              size_t max_frame_size);
 
-  // Setup the pipeline and ensure samples are available for the given media
-  // time, then start rendering samples.
-  bool StartPlayingFrom(base::TimeDelta time,
-                        const scoped_refptr<BufferingState>& buffering_state);
-
-  // Flush any remaining samples in the pipeline.
-  // Invoke |done_cb| when flush is completed.
-  void Flush(const base::Closure& done_cb);
-  // Resets any pending buffers after the backend has been stopped.
-  void BackendStopped();
-
-  // Tear down the pipeline and release the hardware resources.
-  void Stop();
-
-  State GetState() const { return state_; }
-  void TransitionToState(State state);
-
-  void SetCdm(BrowserCdmCast* media_keys);
-
-  void OnBufferPushed(MediaPipelineBackend::BufferStatus status);
+  ::media::PipelineStatistics previous_stats_;
 
  private:
+  void OnFlushDone(const ::media::PipelineStatusCB& status_cb);
+
+  // MediaPipelineBackend::Decoder::Delegate implementation:
+  void OnPushBufferComplete(BufferStatus status) override;
+  void OnEndOfStream() override;
+  void OnDecoderError() override;
+  void OnKeyStatusChanged(const std::string& key_id,
+                          CastKeyStatus key_status,
+                          uint32_t system_code) override;
+  void OnVideoResolutionChanged(const Size& size) override;
+
   // Callback invoked when the CDM state has changed in a way that might
   // impact media playback.
   void OnCdmStateChange();
@@ -106,10 +122,8 @@
 
   base::ThreadChecker thread_checker_;
 
-  UpdateConfigCB update_config_cb_;
-
-  // Backends.
-  MediaPipelineBackend::Decoder* decoder_;
+  MediaPipelineBackend::Decoder* const decoder_;
+  const AvPipelineClient client_;
 
   // AV pipeline state.
   State state_;
diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.cc b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
index 4be7402..a74ea2fca 100644
--- a/chromecast/media/cma/pipeline/media_pipeline_impl.cc
+++ b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
@@ -122,48 +122,6 @@
   // One possibility would be a GetCdmByIdCB that's passed in.
 }
 
-void MediaPipelineImpl::OnVideoResolutionChanged(
-    MediaPipelineBackend::VideoDecoder* decoder,
-    const Size& size) {
-  DCHECK(decoder == video_decoder_);
-  video_pipeline_->OnNaturalSizeChanged(size);
-}
-
-void MediaPipelineImpl::OnPushBufferComplete(
-    MediaPipelineBackend::Decoder* decoder,
-    MediaPipelineBackend::BufferStatus status) {
-  if (decoder == audio_decoder_) {
-    audio_pipeline_->OnBufferPushed(status);
-  } else if (decoder == video_decoder_) {
-    video_pipeline_->OnBufferPushed(status);
-  }
-}
-
-void MediaPipelineImpl::OnEndOfStream(MediaPipelineBackend::Decoder* decoder) {
-  if (decoder == audio_decoder_) {
-    audio_pipeline_->OnEndOfStream();
-  } else if (decoder == video_decoder_) {
-    video_pipeline_->OnEndOfStream();
-  }
-}
-
-void MediaPipelineImpl::OnDecoderError(MediaPipelineBackend::Decoder* decoder) {
-  if (decoder == audio_decoder_) {
-    audio_pipeline_->OnError();
-  } else if (decoder == video_decoder_) {
-    video_pipeline_->OnError();
-  }
-}
-
-void MediaPipelineImpl::OnKeyStatusChanged(const std::string& key_id,
-                                           CastKeyStatus key_status,
-                                           uint32_t system_code) {
-  CMALOG(kLogControl) << __FUNCTION__;
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(cdm_);
-  cdm_->SetKeyStatus(key_id, key_status, system_code);
-}
-
 void MediaPipelineImpl::SetCdm(BrowserCdmCast* cdm) {
   CMALOG(kLogControl) << __FUNCTION__;
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -222,7 +180,7 @@
 
   // Lazy initialise
   if (!backend_initialized_) {
-    backend_initialized_ = media_pipeline_backend_->Initialize(this);
+    backend_initialized_ = media_pipeline_backend_->Initialize();
     if (!backend_initialized_) {
       OnError(::media::PIPELINE_ERROR_ABORT);
       return;
diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.h b/chromecast/media/cma/pipeline/media_pipeline_impl.h
index 87611df..34a687d 100644
--- a/chromecast/media/cma/pipeline/media_pipeline_impl.h
+++ b/chromecast/media/cma/pipeline/media_pipeline_impl.h
@@ -31,10 +31,10 @@
 class CodedFrameProvider;
 class VideoPipelineImpl;
 
-class MediaPipelineImpl : public MediaPipelineBackend::Delegate {
+class MediaPipelineImpl {
  public:
   MediaPipelineImpl();
-  ~MediaPipelineImpl() override;
+  ~MediaPipelineImpl();
 
   // Initialize the media pipeline: the pipeline is configured based on
   // |load_type|.
@@ -44,17 +44,6 @@
   void SetClient(const MediaPipelineClient& client);
   void SetCdm(int cdm_id);
 
-  // MediaPipelineBackendDelegate implementation:
-  void OnVideoResolutionChanged(MediaPipelineBackend::VideoDecoder* decoder,
-                                const Size& size) override;
-  void OnPushBufferComplete(MediaPipelineBackend::Decoder* decoder,
-                            MediaPipelineBackend::BufferStatus status) override;
-  void OnEndOfStream(MediaPipelineBackend::Decoder* decoder) override;
-  void OnDecoderError(MediaPipelineBackend::Decoder* decoder) override;
-  void OnKeyStatusChanged(const std::string& key_id,
-                          CastKeyStatus key_status,
-                          uint32_t system_code) override;
-
   void InitializeAudio(const ::media::AudioDecoderConfig& config,
                        const AvPipelineClient& client,
                        scoped_ptr<CodedFrameProvider> frame_provider,
diff --git a/chromecast/media/cma/pipeline/video_pipeline_impl.cc b/chromecast/media/cma/pipeline/video_pipeline_impl.cc
index d94ea52..61ec7dd 100644
--- a/chromecast/media/cma/pipeline/video_pipeline_impl.cc
+++ b/chromecast/media/cma/pipeline/video_pipeline_impl.cc
@@ -5,6 +5,7 @@
 #include "chromecast/media/cma/pipeline/video_pipeline_impl.h"
 
 #include "base/bind.h"
+#include "chromecast/media/cdm/browser_cdm_cast.h"
 #include "chromecast/media/cma/base/buffering_defs.h"
 #include "chromecast/media/cma/base/cma_logging.h"
 #include "chromecast/media/cma/base/coded_frame_provider.h"
@@ -22,108 +23,17 @@
 }
 
 VideoPipelineImpl::VideoPipelineImpl(
-    MediaPipelineBackend::VideoDecoder* video_decoder,
+    MediaPipelineBackend::VideoDecoder* decoder,
     const VideoPipelineClient& client)
-    : video_decoder_(video_decoder),
-      video_client_(client),
-      weak_factory_(this) {
-  weak_this_ = weak_factory_.GetWeakPtr();
-  av_pipeline_impl_.reset(new AvPipelineImpl(
-      video_decoder_,
-      base::Bind(&VideoPipelineImpl::OnUpdateConfig, base::Unretained(this))));
+    : AvPipelineImpl(decoder, client.av_pipeline_client),
+      video_decoder_(decoder),
+      natural_size_changed_cb_(client.natural_size_changed_cb) {
+  DCHECK(video_decoder_);
 }
 
 VideoPipelineImpl::~VideoPipelineImpl() {
 }
 
-void VideoPipelineImpl::SetCodedFrameProvider(
-    scoped_ptr<CodedFrameProvider> frame_provider) {
-  av_pipeline_impl_->SetCodedFrameProvider(
-      frame_provider.Pass(), kAppVideoBufferSize, kMaxVideoFrameSize);
-}
-
-bool VideoPipelineImpl::StartPlayingFrom(
-    base::TimeDelta time,
-    const scoped_refptr<BufferingState>& buffering_state) {
-  CMALOG(kLogControl) << __FUNCTION__ << " t0=" << time.InMilliseconds();
-
-  // Reset the pipeline statistics.
-  previous_stats_ = ::media::PipelineStatistics();
-
-  // Start playing.
-  if (av_pipeline_impl_->GetState() == AvPipelineImpl::kError)
-    return false;
-  DCHECK_EQ(av_pipeline_impl_->GetState(), AvPipelineImpl::kFlushed);
-
-  if (!av_pipeline_impl_->StartPlayingFrom(time, buffering_state)) {
-    av_pipeline_impl_->TransitionToState(AvPipelineImpl::kError);
-    return false;
-  }
-  av_pipeline_impl_->TransitionToState(AvPipelineImpl::kPlaying);
-
-  return true;
-}
-
-bool VideoPipelineImpl::StartFlush() {
-  CMALOG(kLogControl) << __FUNCTION__;
-  if (av_pipeline_impl_->GetState() == AvPipelineImpl::kError) {
-    return false;
-  }
-  DCHECK_EQ(av_pipeline_impl_->GetState(), AvPipelineImpl::kPlaying);
-  av_pipeline_impl_->TransitionToState(AvPipelineImpl::kFlushing);
-  return true;
-}
-
-void VideoPipelineImpl::Flush(const ::media::PipelineStatusCB& status_cb) {
-  CMALOG(kLogControl) << __FUNCTION__;
-  DCHECK_EQ(av_pipeline_impl_->GetState(), AvPipelineImpl::kFlushing);
-  av_pipeline_impl_->Flush(
-      base::Bind(&VideoPipelineImpl::OnFlushDone, weak_this_, status_cb));
-}
-
-void VideoPipelineImpl::BackendStopped() {
-  CMALOG(kLogControl) << __FUNCTION__;
-  av_pipeline_impl_->BackendStopped();
-}
-
-void VideoPipelineImpl::OnFlushDone(
-    const ::media::PipelineStatusCB& status_cb) {
-  CMALOG(kLogControl) << __FUNCTION__;
-  if (av_pipeline_impl_->GetState() == AvPipelineImpl::kError) {
-    status_cb.Run(::media::PIPELINE_ERROR_ABORT);
-    return;
-  }
-  av_pipeline_impl_->TransitionToState(AvPipelineImpl::kFlushed);
-  status_cb.Run(::media::PIPELINE_OK);
-}
-
-void VideoPipelineImpl::Stop() {
-  CMALOG(kLogControl) << __FUNCTION__;
-  av_pipeline_impl_->Stop();
-  av_pipeline_impl_->TransitionToState(AvPipelineImpl::kStopped);
-}
-
-void VideoPipelineImpl::SetCdm(BrowserCdmCast* media_keys) {
-  av_pipeline_impl_->SetCdm(media_keys);
-}
-
-void VideoPipelineImpl::OnBufferPushed(
-    MediaPipelineBackend::BufferStatus status) {
-  av_pipeline_impl_->OnBufferPushed(status);
-}
-
-void VideoPipelineImpl::OnEndOfStream() {
-  if (!video_client_.av_pipeline_client.eos_cb.is_null())
-    video_client_.av_pipeline_client.eos_cb.Run();
-}
-
-void VideoPipelineImpl::OnError() {
-  if (!video_client_.av_pipeline_client.playback_error_cb.is_null()) {
-    video_client_.av_pipeline_client.playback_error_cb.Run(
-        ::media::PIPELINE_ERROR_COULD_NOT_RENDER);
-  }
-}
-
 void VideoPipelineImpl::Initialize(
     const std::vector<::media::VideoDecoderConfig>& configs,
     scoped_ptr<CodedFrameProvider> frame_provider,
@@ -134,8 +44,10 @@
                         << config.AsHumanReadableString();
   }
 
-  if (frame_provider)
-    SetCodedFrameProvider(frame_provider.Pass());
+  if (frame_provider) {
+    SetCodedFrameProvider(frame_provider.Pass(), kAppVideoBufferSize,
+                          kMaxVideoFrameSize);
+  }
 
   if (configs.empty()) {
      status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED);
@@ -157,10 +69,19 @@
     status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED);
     return;
   }
-  av_pipeline_impl_->TransitionToState(AvPipelineImpl::kFlushed);
+  TransitionToState(kFlushed);
   status_cb.Run(::media::PIPELINE_OK);
 }
 
+void VideoPipelineImpl::OnVideoResolutionChanged(const Size& size) {
+  if (state() != kPlaying)
+    return;
+
+  if (!natural_size_changed_cb_.is_null()) {
+    natural_size_changed_cb_.Run(gfx::Size(size.width, size.height));
+  }
+}
+
 void VideoPipelineImpl::OnUpdateConfig(
     StreamId id,
     const ::media::AudioDecoderConfig& audio_config,
@@ -171,26 +92,13 @@
 
     bool success = video_decoder_->SetConfig(
         DecoderConfigAdapter::ToCastVideoConfig(id, video_config));
-    if (!success &&
-        !video_client_.av_pipeline_client.playback_error_cb.is_null()) {
-      video_client_.av_pipeline_client.playback_error_cb.Run(
-          ::media::PIPELINE_ERROR_DECODE);
-    }
-  }
-}
-
-void VideoPipelineImpl::OnNaturalSizeChanged(const Size& size) {
-  if (av_pipeline_impl_->GetState() != AvPipelineImpl::kPlaying)
-    return;
-
-  if (!video_client_.natural_size_changed_cb.is_null()) {
-    video_client_.natural_size_changed_cb.Run(
-        gfx::Size(size.width, size.height));
+    if (!success && !client().playback_error_cb.is_null())
+      client().playback_error_cb.Run(::media::PIPELINE_ERROR_DECODE);
   }
 }
 
 void VideoPipelineImpl::UpdateStatistics() {
-  if (video_client_.av_pipeline_client.statistics_cb.is_null())
+  if (client().statistics_cb.is_null())
     return;
 
   MediaPipelineBackend::Decoder::Statistics device_stats;
@@ -211,7 +119,7 @@
 
   previous_stats_ = current_stats;
 
-  video_client_.av_pipeline_client.statistics_cb.Run(delta_stats);
+  client().statistics_cb.Run(delta_stats);
 }
 
 }  // namespace media
diff --git a/chromecast/media/cma/pipeline/video_pipeline_impl.h b/chromecast/media/cma/pipeline/video_pipeline_impl.h
index 318b7f0c..b20ac6a 100644
--- a/chromecast/media/cma/pipeline/video_pipeline_impl.h
+++ b/chromecast/media/cma/pipeline/video_pipeline_impl.h
@@ -7,13 +7,12 @@
 
 #include <vector>
 
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
+#include "base/memory/scoped_ptr.h"
+#include "chromecast/media/cma/pipeline/av_pipeline_impl.h"
 #include "chromecast/media/cma/pipeline/video_pipeline_client.h"
 #include "chromecast/public/media/media_pipeline_backend.h"
 #include "chromecast/public/media/stream_id.h"
+#include "media/base/pipeline_status.h"
 
 namespace media {
 class AudioDecoderConfig;
@@ -23,61 +22,31 @@
 namespace chromecast {
 struct Size;
 namespace media {
-class AvPipelineImpl;
-class BrowserCdmCast;
-class BufferingState;
 class CodedFrameProvider;
 
-class VideoPipelineImpl {
+class VideoPipelineImpl : public AvPipelineImpl {
  public:
   VideoPipelineImpl(MediaPipelineBackend::VideoDecoder* decoder,
                     const VideoPipelineClient& client);
-  ~VideoPipelineImpl();
+  ~VideoPipelineImpl() override;
 
-  // Input port of the pipeline.
-  void SetCodedFrameProvider(scoped_ptr<CodedFrameProvider> frame_provider);
-
-  // Provide the CDM to use to decrypt samples.
-  void SetCdm(BrowserCdmCast* media_keys);
-
-  // Functions to control the state of the audio pipeline.
   void Initialize(
       const std::vector<::media::VideoDecoderConfig>& configs,
       scoped_ptr<CodedFrameProvider> frame_provider,
       const ::media::PipelineStatusCB& status_cb);
-  bool StartPlayingFrom(base::TimeDelta time,
-                        const scoped_refptr<BufferingState>& buffering_state);
-  bool StartFlush();
-  void Flush(const ::media::PipelineStatusCB& status_cb);
-  void BackendStopped();
-  void Stop();
 
-  // Update the playback statistics for this video stream.
-  void UpdateStatistics();
-
-  void OnBufferPushed(MediaPipelineBackend::BufferStatus status);
-  void OnEndOfStream();
-  void OnError();
-  void OnNaturalSizeChanged(const Size& size);
+  // AvPipelineImpl implementation:
+  void UpdateStatistics() override;
 
  private:
-  class DeviceClientImpl;
-  friend class DeviceClientImpl;
-
-  void OnFlushDone(const ::media::PipelineStatusCB& status_cb);
+  // AvPipelineImpl implementation:
+  void OnVideoResolutionChanged(const Size& size) override;
   void OnUpdateConfig(StreamId id,
                       const ::media::AudioDecoderConfig& audio_config,
-                      const ::media::VideoDecoderConfig& video_config);
+                      const ::media::VideoDecoderConfig& video_config) override;
 
-  MediaPipelineBackend::VideoDecoder* video_decoder_;
-
-  scoped_ptr<AvPipelineImpl> av_pipeline_impl_;
-  VideoPipelineClient video_client_;
-
-  ::media::PipelineStatistics previous_stats_;
-
-  base::WeakPtr<VideoPipelineImpl> weak_this_;
-  base::WeakPtrFactory<VideoPipelineImpl> weak_factory_;
+  MediaPipelineBackend::VideoDecoder* const video_decoder_;
+  const VideoPipelineClient::NaturalSizeChangedCB natural_size_changed_cb_;
 
   DISALLOW_COPY_AND_ASSIGN(VideoPipelineImpl);
 };
diff --git a/chromecast/public/media/media_pipeline_backend.h b/chromecast/public/media/media_pipeline_backend.h
index ece8452a..febd2523 100644
--- a/chromecast/public/media/media_pipeline_backend.h
+++ b/chromecast/public/media/media_pipeline_backend.h
@@ -25,7 +25,7 @@
 // If more backends are requested than the platform supports, the unsupported
 // extra backends may return nullptr for CreateAudioDecoder/CreateVideoDecoder.
 // The basic usage pattern is:
-//   * Decoder objects created, then Initialize called
+//   * Decoder objects created and delegates set, then Initialize called
 //   * Start/Stop/Pause/Resume used to manage playback state
 //   * Decoder objects are used to pass actual stream data buffers
 //   * Backend must make appropriate callbacks on the provided Delegate
@@ -42,7 +42,36 @@
 
   class Decoder {
    public:
-    typedef MediaPipelineBackend::BufferStatus BufferStatus;
+    using BufferStatus = MediaPipelineBackend::BufferStatus;
+
+    // Delegate methods must be called on the main CMA thread.
+    class Delegate {
+     public:
+      using BufferStatus = MediaPipelineBackend::BufferStatus;
+
+      // See comments on PushBuffer.  Must not be called with kBufferPending.
+      virtual void OnPushBufferComplete(BufferStatus status) = 0;
+
+      // Must be called after an end-of-stream buffer has been rendered (ie, the
+      // last real buffer has been sent to the output hardware).
+      virtual void OnEndOfStream() = 0;
+
+      // May be called if a decoder error occurs. No more calls to PushBuffer()
+      // will be made after this is called.
+      virtual void OnDecoderError() = 0;
+
+      // Must be called when a decryption key status changes.
+      virtual void OnKeyStatusChanged(const std::string& key_id,
+                                      CastKeyStatus key_status,
+                                      uint32_t system_code) = 0;
+
+      // Must be called when video resolution change is detected by the decoder.
+      // Only relevant for video decoders.
+      virtual void OnVideoResolutionChanged(const Size& size) = 0;
+
+     protected:
+      virtual ~Delegate() {}
+    };
 
     // Statistics (computed since pipeline last started playing).
     // For video, a sample is defined as a frame.
@@ -52,13 +81,17 @@
       uint64_t dropped_samples;
     };
 
+    // Provides the delegate for this decoder. Called once before the backend
+    // is initialized; is never called after the backend is initialized.
+    virtual void SetDelegate(Delegate* delegate) = 0;
+
     // Pushes a buffer of data for decoding and output.  If the implementation
     // cannot push the buffer now, it must store the buffer, return
     // |kBufferPending| and execute the push at a later time when it becomes
     // possible to do so.  The implementation must then invoke
-    // Delegate::OnPushBufferComplete.  Pushing a pending buffer should be
-    // aborted if Stop is called; OnPushAudioComplete need not be invoked in
-    // this case.
+    // Delegate::OnPushBufferComplete once the push has been completed.  Pushing
+    // a pending buffer should be aborted if Stop is called;
+    // OnPushBufferComplete need not be invoked in this case.
     // If |kBufferPending| is returned, the pipeline will stop pushing any
     // further buffers until OnPushBufferComplete is invoked.
     // OnPushBufferComplete should be only be invoked to indicate completion of
@@ -97,6 +130,7 @@
 
     // Provides the audio configuration.  Called once before the backend is
     // initialized, and again any time the configuration changes (in any state).
+    // Note that SetConfig() may be called before SetDelegate() is called.
     // Returns true if the configuration is a supported configuration.
     virtual bool SetConfig(const AudioConfig& config) = 0;
 
@@ -120,6 +154,7 @@
    public:
     // Provides the video configuration.  Called once before the backend is
     // initialized, and again any time the configuration changes (in any state).
+    // Note that SetConfig() may be called before SetDelegate() is called.
     // Returns true if the configuration is a supported configuration.
     virtual bool SetConfig(const VideoConfig& config) = 0;
 
@@ -127,34 +162,6 @@
     ~VideoDecoder() override {}
   };
 
-  // Delegate methods must be called on the main CMA thread.
-  class Delegate {
-   public:
-    // Must be called when video resolution change is detected by decoder.
-    virtual void OnVideoResolutionChanged(VideoDecoder* decoder,
-                                          const Size& size) = 0;
-
-    // See comments on PushBuffer.  Must not be called with kBufferPending.
-    virtual void OnPushBufferComplete(Decoder* decoder,
-                                      BufferStatus status) = 0;
-
-    // Must be called after an end-of-stream buffer has been rendered (ie, the
-    // last real buffer has been sent to the output hardware).
-    virtual void OnEndOfStream(Decoder* decoder) = 0;
-
-    // May be called if a decoder error occurs. No more calls to PushBuffer()
-    // will be made after this is called.
-    virtual void OnDecoderError(Decoder* decoder) = 0;
-
-    // Must be called when a decryption key status changes.
-    virtual void OnKeyStatusChanged(const std::string& key_id,
-                                    CastKeyStatus key_status,
-                                    uint32_t system_code) = 0;
-
-   protected:
-    virtual ~Delegate() {}
-  };
-
   virtual ~MediaPipelineBackend() {}
 
   // Creates a new AudioDecoder attached to this pipeline.  MediaPipelineBackend
@@ -178,7 +185,7 @@
   // but before all other functions.  Hardware resources for all decoders should
   // be acquired here.  Backend is then considered in Initialized state.
   // Returns false for failure.
-  virtual bool Initialize(Delegate* delegate) = 0;
+  virtual bool Initialize() = 0;
 
   // Places pipeline into playing state.  Playback will start at given time once
   // buffers are pushed.  Called only when in Initialized state. |start_pts| is
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 5a48217e..2438b001 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-7710.0.0
\ No newline at end of file
+7715.0.0
\ No newline at end of file
diff --git a/chromeos/login/auth/login_performer.cc b/chromeos/login/auth/login_performer.cc
index b988f1d..40b085c5 100644
--- a/chromeos/login/auth/login_performer.cc
+++ b/chromeos/login/auth/login_performer.cc
@@ -130,22 +130,21 @@
 
 void LoginPerformer::DoPerformLogin(const UserContext& user_context,
                                     AuthorizationMode auth_mode) {
-  const std::string email =
-      gaia::CanonicalizeEmail(user_context.GetAccountId().GetUserEmail());
   bool wildcard_match = false;
 
-  if (!IsUserWhitelisted(email, &wildcard_match)) {
+  const AccountId& account_id = user_context.GetAccountId();
+  if (!IsUserWhitelisted(account_id, &wildcard_match)) {
     NotifyWhitelistCheckFailure();
     return;
   }
 
   if (user_context.GetAuthFlow() == UserContext::AUTH_FLOW_EASY_UNLOCK)
-    SetupEasyUnlockUserFlow(user_context.GetAccountId().GetUserEmail());
+    SetupEasyUnlockUserFlow(user_context.GetAccountId());
 
   switch (auth_mode_) {
     case AUTH_MODE_EXTENSION: {
       RunOnlineWhitelistCheck(
-          email, wildcard_match, user_context.GetRefreshToken(),
+          account_id, wildcard_match, user_context.GetRefreshToken(),
           base::Bind(&LoginPerformer::StartLoginCompletion,
                      weak_factory_.GetWeakPtr()),
           base::Bind(&LoginPerformer::NotifyWhitelistCheckFailure,
@@ -182,7 +181,7 @@
     return;
   }
 
-  SetupSupervisedUserFlow(user_context.GetAccountId().GetUserEmail());
+  SetupSupervisedUserFlow(user_context.GetAccountId());
   UserContext user_context_copy = TransformSupervisedKey(user_context);
 
   if (UseExtendedAuthenticatorForSupervisedUser(user_context)) {
@@ -206,7 +205,7 @@
 }
 
 void LoginPerformer::LoginAsPublicSession(const UserContext& user_context) {
-  if (!CheckPolicyForUser(user_context.GetAccountId().GetUserEmail())) {
+  if (!CheckPolicyForUser(user_context.GetAccountId())) {
     DCHECK(delegate_);
     if (delegate_)
       delegate_->PolicyLoadFailed();
diff --git a/chromeos/login/auth/login_performer.h b/chromeos/login/auth/login_performer.h
index a4e6ab36..68b5aa1f 100644
--- a/chromeos/login/auth/login_performer.h
+++ b/chromeos/login/auth/login_performer.h
@@ -18,6 +18,8 @@
 #include "chromeos/login/auth/user_context.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 
+class AccountId;
+
 namespace net {
 class URLRequestContextGetter;
 }
@@ -116,7 +118,7 @@
   // Check if user is allowed to sign in on device. |wildcard_match| will
   // contain additional information whether this user is explicitly listed or
   // not (may be relevant for extension-based sign-in).
-  virtual bool IsUserWhitelisted(const std::string& user_id,
+  virtual bool IsUserWhitelisted(const AccountId& account_id,
                                  bool* wildcard_match) = 0;
 
  protected:
@@ -131,7 +133,7 @@
   // Either |success_callback| or |failure_callback| should be called upon this
   // check.
   virtual void RunOnlineWhitelistCheck(
-      const std::string& user_id,
+      const AccountId& account_id,
       bool wildcard_match,
       const std::string& refresh_token,
       const base::Closure& success_callback,
@@ -150,14 +152,14 @@
   virtual UserContext TransformSupervisedKey(const UserContext& context) = 0;
 
   // Set up sign-in flow for supervised user.
-  virtual void SetupSupervisedUserFlow(const std::string& user_id) = 0;
+  virtual void SetupSupervisedUserFlow(const AccountId& account_id) = 0;
 
   // Set up sign-in flow for Easy Unlock.
-  virtual void SetupEasyUnlockUserFlow(const std::string& user_id) = 0;
+  virtual void SetupEasyUnlockUserFlow(const AccountId& account_id) = 0;
 
-  // Run policy check for |user_id|. If something is wrong, delegate's
+  // Run policy check for |account_id|. If something is wrong, delegate's
   // PolicyLoadFailed is called.
-  virtual bool CheckPolicyForUser(const std::string& user_id) = 0;
+  virtual bool CheckPolicyForUser(const AccountId& account_id) = 0;
 
   // Look up browser context to use during signin.
   virtual content::BrowserContext* GetSigninContext() = 0;
diff --git a/cloud_print/virtual_driver/win/install/setup.cc b/cloud_print/virtual_driver/win/install/setup.cc
index 9032258..c7fc3a5 100644
--- a/cloud_print/virtual_driver/win/install/setup.cc
+++ b/cloud_print/virtual_driver/win/install/setup.cc
@@ -193,7 +193,7 @@
   if (notification == SPFILENOTIFY_FILEINCABINET) {
     FILE_IN_CABINET_INFO* info =
         reinterpret_cast<FILE_IN_CABINET_INFO*>(param1);
-    for (int i = 0; i < arraysize(kDependencyList); i++) {
+    for (size_t i = 0; i < arraysize(kDependencyList); i++) {
       base::FilePath base_name(info->NameInCabinet);
       base_name = base_name.BaseName();
       if (base::FilePath::CompareEqualIgnoreCase(base_name.value().c_str(),
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 6f1afce..935c2cfd 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -50,6 +50,7 @@
     "//components/autofill/core/common:unit_tests",
     "//components/bookmarks/browser:unit_tests",
     "//components/bookmarks/managed:unit_tests",
+    "//components/browser_sync/browser:unit_tests",
     "//components/compression:unit_tests",
     "//components/content_settings/core/browser:unit_tests",
     "//components/content_settings/core/common",
diff --git a/components/arc.gypi b/components/arc.gypi
index 8af8626..62cc463 100644
--- a/components/arc.gypi
+++ b/components/arc.gypi
@@ -16,6 +16,8 @@
         '../base/base.gyp:base',
         '../chromeos/chromeos.gyp:chromeos',
         '../ipc/ipc.gyp:ipc',
+        '../ui/aura/aura.gyp:aura',
+        '../ui/events/events.gyp:events_base',
       ],
       'sources': [
         'arc/arc_bridge_bootstrap.cc',
@@ -26,6 +28,9 @@
         'arc/arc_bridge_service_impl.h',
         'arc/arc_service_manager.cc',
         'arc/arc_service_manager.h',
+        'arc/input/arc_input_bridge.h',
+        'arc/input/arc_input_bridge_impl.cc',
+        'arc/input/arc_input_bridge_impl.h',
       ],
     },
     {
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn
index 3d53493a..0a518f5 100644
--- a/components/arc/BUILD.gn
+++ b/components/arc/BUILD.gn
@@ -14,6 +14,9 @@
     "arc_bridge_service_impl.h",
     "arc_service_manager.cc",
     "arc_service_manager.h",
+    "input/arc_input_bridge.h",
+    "input/arc_input_bridge_impl.cc",
+    "input/arc_input_bridge_impl.h",
   ]
 
   deps = [
@@ -24,6 +27,9 @@
     "//ipc:ipc",
     "//ipc/mojo:mojo",
     "//third_party/mojo/src/mojo/edk/system",
+    "//ui/aura",
+    "//ui/events",
+    "//ui/events:dom_keycode_converter",
   ]
 }
 
@@ -65,5 +71,8 @@
     "//mojo/public/cpp/environment:environment",
     "//mojo/public/cpp/system:system",
     "//testing/gtest",
+    "//ui/aura",
+    "//ui/events",
+    "//ui/events:dom_keycode_converter",
   ]
 }
diff --git a/components/arc/arc_service_manager.cc b/components/arc/arc_service_manager.cc
index 7927b55..2fc0e00 100644
--- a/components/arc/arc_service_manager.cc
+++ b/components/arc/arc_service_manager.cc
@@ -8,6 +8,7 @@
 #include "base/thread_task_runner_handle.h"
 #include "components/arc/arc_bridge_bootstrap.h"
 #include "components/arc/arc_bridge_service_impl.h"
+#include "components/arc/input/arc_input_bridge.h"
 
 namespace arc {
 
@@ -22,6 +23,7 @@
     : arc_bridge_service_(
           new ArcBridgeServiceImpl(ArcBridgeBootstrap::Create())) {
   DCHECK(!g_arc_service_manager);
+  arc_input_bridge_ = ArcInputBridge::Create(arc_bridge_service_.get());
   g_arc_service_manager = this;
 }
 
diff --git a/components/arc/arc_service_manager.h b/components/arc/arc_service_manager.h
index 1bffa89..ed4b434 100644
--- a/components/arc/arc_service_manager.h
+++ b/components/arc/arc_service_manager.h
@@ -12,6 +12,7 @@
 namespace arc {
 
 class ArcBridgeService;
+class ArcInputBridge;
 
 // Manages creation and destruction of services that communicate with the ARC
 // instance via the ArcBridgeService.
@@ -31,6 +32,7 @@
  private:
   base::ThreadChecker thread_checker_;
   scoped_ptr<ArcBridgeService> arc_bridge_service_;
+  scoped_ptr<ArcInputBridge> arc_input_bridge_;
 
   DISALLOW_COPY_AND_ASSIGN(ArcServiceManager);
 };
diff --git a/components/arc/input/DEPS b/components/arc/input/DEPS
new file mode 100644
index 0000000..6c46762
--- /dev/null
+++ b/components/arc/input/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+ui/aura",
+  "+ui/events",
+]
diff --git a/components/arc/input/arc_input_bridge.h b/components/arc/input/arc_input_bridge.h
new file mode 100644
index 0000000..1082dc4
--- /dev/null
+++ b/components/arc/input/arc_input_bridge.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 COMPONENTS_EXO_ARC_INPUT_ARC_INPUT_BRIDGE_H_
+#define COMPONENTS_EXO_ARC_INPUT_ARC_INPUT_BRIDGE_H_
+
+#include "base/macros.h"
+#include "components/arc/arc_bridge_service.h"
+
+namespace arc {
+
+class ArcBridgeService;
+
+// The ArcInputBridge is responsible for sending input events from ARC windows
+// to the ARC instance.
+// It hooks into aura::Env to watch for ExoSurface windows that are running ARC
+// applications. On those windows the input bridge will attach an EventPreTarget
+// to capture all input events.
+// To send those events to the ARC instance it will create bridge input devices
+// through the ArcBridgeService, which will provide a file descriptor to which
+// we can send linux input_event's.
+// ui::Events to the ARC windows are translated to linux input_event's, which
+// are then sent through the respective file descriptor.
+class ArcInputBridge {
+ public:
+  virtual ~ArcInputBridge() {}
+
+  // Creates a new instance of ArcInputBridge. It will register an Observer
+  // with aura::Env and the ArcBridgeService.
+  static scoped_ptr<ArcInputBridge> Create(
+      ArcBridgeService* arc_bridge_service);
+
+ protected:
+  ArcInputBridge() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ArcInputBridge);
+};
+
+}  // namespace arc
+
+#endif  // COMPONENTS_EXO_ARC_INPUT_ARC_INPUT_BRIDGE_H_
diff --git a/components/arc/input/arc_input_bridge_impl.cc b/components/arc/input/arc_input_bridge_impl.cc
new file mode 100644
index 0000000..c5a0065
--- /dev/null
+++ b/components/arc/input/arc_input_bridge_impl.cc
@@ -0,0 +1,365 @@
+// 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/input/arc_input_bridge_impl.h"
+
+#include <linux/input.h>
+#include <fcntl.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/arc/arc_bridge_service.h"
+#include "ui/aura/env.h"
+#include "ui/aura/env_observer.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_observer.h"
+#include "ui/events/event.h"
+#include "ui/events/event_handler.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
+
+namespace {
+
+// input_event values for keyboard events.
+const int kKeyReleased = 0;
+const int kKeyPressed = 1;
+const int kKeyRepeated = 2;
+
+// maximum number of supported multi-touch slots (simultaneous fingers).
+const int kMaxSlots = 64;
+
+// tracking id of an empty slot.
+const int kEmptySlot = -1;
+
+// maximum possible pressure as defined in EventHubARC.
+// TODO(denniskempin): communicate maximum during initialization.
+const int kMaxPressure = 65536;
+
+// speed of the scroll emulation. Scroll events are reported at about 100 times
+// the speed of a scroll wheel.
+const float kScrollEmulationSpeed = 100.0f;
+
+struct MouseButtonMapping {
+  int ui_flag;
+  int evdev_code;
+} kMouseButtonMap[] = {
+    {ui::EF_LEFT_MOUSE_BUTTON, BTN_LEFT},
+    {ui::EF_RIGHT_MOUSE_BUTTON, BTN_RIGHT},
+    {ui::EF_MIDDLE_MOUSE_BUTTON, BTN_MIDDLE},
+};
+
+// Offset between evdev key codes and chrome native key codes
+const int kXkbKeycodeOffset = 8;
+
+}  // namespace
+
+namespace arc {
+
+ArcInputBridgeImpl::ArcInputBridgeImpl(ArcBridgeService* arc_bridge_service)
+    : arc_bridge_service_(arc_bridge_service),
+      offset_x_acc_(0.5f),
+      offset_y_acc_(0.5f),
+      current_slot_(-1),
+      current_slot_tracking_ids_(kMaxSlots, kEmptySlot),
+      origin_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+      weak_factory_(this) {
+  DCHECK(arc_bridge_service->state() == ArcBridgeService::State::STOPPED);
+  arc_bridge_service->AddObserver(this);
+
+  aura::Env* env = aura::Env::GetInstanceDontCreate();
+  if (env)
+    env->AddObserver(this);
+}
+
+ArcInputBridgeImpl::~ArcInputBridgeImpl() {
+  DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
+  arc_bridge_service_->RemoveObserver(this);
+
+  aura::Env* env = aura::Env::GetInstanceDontCreate();
+  if (env)
+    env->RemoveObserver(this);
+
+  for (aura::Window* window : arc_windows_.windows()) {
+    window->RemovePreTargetHandler(this);
+  }
+}
+
+void ArcInputBridgeImpl::OnInstanceBootPhase(InstanceBootPhase phase) {
+  DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
+  if (phase != INSTANCE_BOOT_PHASE_SYSTEM_SERVICES_READY)
+    return;
+
+  keyboard_fd_ = CreateBridgeInputDevice("ChromeOS Keyboard", "keyboard");
+  mouse_fd_ = CreateBridgeInputDevice("ChromeOS Mouse", "mouse");
+  touchscreen_fd_ =
+      CreateBridgeInputDevice("ChromeOS Touchscreen", "touchscreen");
+}
+
+// Translates and sends a ui::Event to the appropriate bridge device of the
+// ARC instance. If the devices have not yet been initialized, the event
+// will be ignored.
+void ArcInputBridgeImpl::OnEvent(ui::Event* event) {
+  DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
+  if (event->IsKeyEvent()) {
+    SendKeyEvent(static_cast<ui::KeyEvent*>(event));
+  } else if (event->IsMouseEvent() || event->IsScrollEvent()) {
+    SendMouseEvent(static_cast<ui::MouseEvent*>(event));
+  } else if (event->IsTouchEvent()) {
+    SendTouchEvent(static_cast<ui::TouchEvent*>(event));
+  }
+}
+
+// Attaches the input bridge to the window if it is marked as an ARC window.
+void ArcInputBridgeImpl::OnWindowInitialized(aura::Window* new_window) {
+  if (new_window->name() == "ExoSurface") {
+    arc_windows_.Add(new_window);
+    new_window->AddPreTargetHandler(this);
+  }
+}
+
+void ArcInputBridgeImpl::SendKeyEvent(ui::KeyEvent* event) {
+  if (keyboard_fd_.get() < 0) {
+    VLOG(2) << "No keyboard bridge device available.";
+    return;
+  }
+
+  unsigned short evdev_code = DomCodeToEvdevCode(event->code());
+  int evdev_value = 0;
+  if (event->type() == ui::ET_KEY_PRESSED) {
+    if (event->flags() & ui::EF_IS_REPEAT) {
+      evdev_value = kKeyRepeated;
+    } else {
+      evdev_value = kKeyPressed;
+    }
+  } else if (event->type() == ui::ET_KEY_RELEASED) {
+    evdev_value = kKeyReleased;
+  } else {
+    NOTREACHED() << "Key should be either PRESSED or RELEASED.";
+  }
+
+  base::TimeDelta time_stamp = event->time_stamp();
+  SendKernelEvent(keyboard_fd_, time_stamp, EV_KEY, evdev_code, evdev_value);
+  SendSynReport(keyboard_fd_, time_stamp);
+}
+
+void ArcInputBridgeImpl::SendTouchEvent(ui::TouchEvent* event) {
+  if (touchscreen_fd_.get() < 0) {
+    VLOG(2) << "No touchscreen bridge device available.";
+    return;
+  }
+
+  ui::PointerDetails details = event->pointer_details();
+  base::TimeDelta time_stamp = event->time_stamp();
+
+  // find or assing a slot for this tracking id
+  int slot_id = AcquireTouchSlot(event);
+  if (slot_id < 0) {
+    VLOG(1) << "Ran out of slot IDs.";
+    return;
+  }
+
+  // we only need to send the slot ID when it has changed.
+  if (slot_id != current_slot_) {
+    current_slot_ = slot_id;
+    SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_SLOT,
+                    current_slot_);
+  }
+
+  // update tracking id
+  if (event->type() == ui::ET_TOUCH_PRESSED) {
+    SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TRACKING_ID,
+                    event->touch_id());
+  } else if (event->type() == ui::ET_TOUCH_RELEASED) {
+    SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TRACKING_ID,
+                    kEmptySlot);
+  }
+
+  // update touch information
+  if (event->type() == ui::ET_TOUCH_MOVED ||
+      event->type() == ui::ET_TOUCH_PRESSED) {
+    SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_POSITION_X,
+                    event->x());
+    SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_POSITION_Y,
+                    event->y());
+    SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TOUCH_MAJOR,
+                    details.radius_x());
+    SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TOUCH_MINOR,
+                    details.radius_y());
+    SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_PRESSURE,
+                    details.force() * kMaxPressure);
+  }
+  SendSynReport(touchscreen_fd_, time_stamp);
+}
+
+void ArcInputBridgeImpl::SendMouseEvent(ui::MouseEvent* event) {
+  if (mouse_fd_.get() < 0) {
+    VLOG(2) << "No mouse bridge device available.";
+    return;
+  }
+
+  base::TimeDelta time_stamp = event->time_stamp();
+
+  // update location
+  if (event->type() == ui::ET_MOUSE_MOVED ||
+      event->type() == ui::ET_MOUSE_DRAGGED) {
+    SendKernelEvent(mouse_fd_, time_stamp, EV_ABS, ABS_X, event->x());
+    SendKernelEvent(mouse_fd_, time_stamp, EV_ABS, ABS_Y, event->y());
+  }
+
+  // update buttons
+  if (event->type() == ui::ET_MOUSE_PRESSED ||
+      event->type() == ui::ET_MOUSE_RELEASED) {
+    int evdev_value = static_cast<int>(event->type() == ui::ET_MOUSE_PRESSED);
+    for (MouseButtonMapping mapping : kMouseButtonMap) {
+      if (event->changed_button_flags() & mapping.ui_flag) {
+        SendKernelEvent(mouse_fd_, time_stamp, EV_KEY, mapping.evdev_code,
+                        evdev_value);
+      }
+    }
+  }
+
+  // update scroll wheel
+  if (event->type() == ui::ET_SCROLL) {
+    ui::ScrollEvent* scroll_event = static_cast<ui::ScrollEvent*>(event);
+    // accumulate floating point scroll offset since we can only send full
+    // integer
+    // wheel events.
+    offset_x_acc_ += scroll_event->x_offset_ordinal() / kScrollEmulationSpeed;
+    offset_y_acc_ += scroll_event->y_offset_ordinal() / kScrollEmulationSpeed;
+
+    int wheel = floor(offset_y_acc_);
+    if (wheel != 0) {
+      SendKernelEvent(mouse_fd_, time_stamp, EV_REL, REL_WHEEL, wheel);
+      offset_y_acc_ -= static_cast<float>(wheel);
+    }
+
+    int hwheel = floor(offset_x_acc_);
+    if (hwheel != 0) {
+      SendKernelEvent(mouse_fd_, time_stamp, EV_REL, REL_HWHEEL, hwheel);
+      offset_x_acc_ -= static_cast<float>(hwheel);
+    }
+  }
+
+  SendSynReport(mouse_fd_, time_stamp);
+}
+
+void ArcInputBridgeImpl::SendKernelEvent(const base::ScopedFD& fd,
+                                         base::TimeDelta time_stamp,
+                                         unsigned short type,
+                                         unsigned short code,
+                                         int value) {
+  DCHECK(fd.is_valid());
+
+  // Chrome does not always use the monotonic system time for event times.
+  // For now always force the event time to the current system time.
+  // TODO(denniskempin): To enable performance tracing of events we will want
+  // to use the kernel-provided monotonic time stamps of events.
+  time_stamp = ui::EventTimeForNow();
+
+  struct input_event event;
+  event.time.tv_sec = time_stamp.InSeconds();
+  base::TimeDelta remainder =
+      time_stamp - base::TimeDelta::FromSeconds(event.time.tv_sec);
+  event.time.tv_usec = remainder.InMicroseconds();
+  event.type = type;
+  event.code = code;
+  event.value = value;
+
+  // Write event to file descriptor
+  size_t num_written = write(fd.get(), reinterpret_cast<void*>(&event),
+                             sizeof(struct input_event));
+  DCHECK_EQ(num_written, sizeof(struct input_event));
+}
+
+void ArcInputBridgeImpl::SendSynReport(const base::ScopedFD& fd,
+                                       base::TimeDelta time) {
+  DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
+
+  SendKernelEvent(fd, time, EV_SYN, SYN_REPORT, 0);
+}
+
+int ArcInputBridgeImpl::AcquireTouchSlot(ui::TouchEvent* event) {
+  int slot_id;
+  if (event->type() == ui::ET_TOUCH_PRESSED) {
+    slot_id = FindTouchSlot(kEmptySlot);
+  } else {
+    slot_id = FindTouchSlot(event->touch_id());
+  }
+  if (slot_id < 0) {
+    return -1;
+  }
+
+  if (event->type() == ui::ET_TOUCH_RELEASED) {
+    current_slot_tracking_ids_[slot_id] = kEmptySlot;
+  } else if (event->type() == ui::ET_TOUCH_PRESSED) {
+    current_slot_tracking_ids_[slot_id] = event->touch_id();
+  }
+  return slot_id;
+}
+
+int ArcInputBridgeImpl::FindTouchSlot(int tracking_id) {
+  for (int i = 0; i < kMaxSlots; ++i) {
+    if (current_slot_tracking_ids_[i] == tracking_id) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+unsigned short ArcInputBridgeImpl::DomCodeToEvdevCode(ui::DomCode dom_code) {
+  int native_code = ui::KeycodeConverter::DomCodeToNativeKeycode(dom_code);
+  if (native_code == ui::KeycodeConverter::InvalidNativeKeycode())
+    return KEY_RESERVED;
+
+  return native_code - kXkbKeycodeOffset;
+}
+
+base::ScopedFD ArcInputBridgeImpl::CreateBridgeInputDevice(
+    const std::string& name,
+    const std::string& device_type) {
+  if (!arc_bridge_service_) {
+    VLOG(1) << "ArcBridgeService disappeared.";
+    return base::ScopedFD();
+  }
+
+  // Create file descriptor pair for communication
+  int fd[2];
+  int res = HANDLE_EINTR(pipe(fd));
+  if (res < 0) {
+    VPLOG(1) << "Cannot create pipe";
+    return base::ScopedFD();
+  }
+  base::ScopedFD read_fd(fd[0]);
+  base::ScopedFD write_fd(fd[1]);
+
+  // The read end is sent to the instance, ownership of fd transfers.
+  if (!arc_bridge_service_->RegisterInputDevice(name, device_type,
+                                                std::move(read_fd))) {
+    VLOG(1) << "Cannot create bridge input device";
+    return base::ScopedFD();
+  }
+
+  // setup write end as non blocking
+  int flags = HANDLE_EINTR(fcntl(write_fd.get(), F_GETFL, 0));
+  if (res < 0) {
+    VPLOG(1) << "Cannot get file descriptor flags";
+    return base::ScopedFD();
+  }
+
+  res = HANDLE_EINTR(fcntl(write_fd.get(), F_SETFL, flags | O_NONBLOCK));
+  if (res < 0) {
+    VPLOG(1) << "Cannot set file descriptor flags";
+    return base::ScopedFD();
+  }
+  return write_fd;
+}
+
+scoped_ptr<ArcInputBridge> ArcInputBridge::Create(
+    ArcBridgeService* arc_bridge_service) {
+  return make_scoped_ptr(new ArcInputBridgeImpl(arc_bridge_service));
+}
+
+}  // namespace arc
diff --git a/components/arc/input/arc_input_bridge_impl.h b/components/arc/input/arc_input_bridge_impl.h
new file mode 100644
index 0000000..d71fbde
--- /dev/null
+++ b/components/arc/input/arc_input_bridge_impl.h
@@ -0,0 +1,133 @@
+// 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_EXO_ARC_INPUT_ARC_INPUT_BRIDGE_IMPL_H_
+#define COMPONENTS_EXO_ARC_INPUT_ARC_INPUT_BRIDGE_IMPL_H_
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "components/arc/input/arc_input_bridge.h"
+#include "ui/aura/env.h"
+#include "ui/aura/env_observer.h"
+#include "ui/aura/window_tracker.h"
+#include "ui/events/event.h"
+#include "ui/events/event_handler.h"
+
+namespace aura {
+class Window;
+}
+
+namespace ui {
+enum class DomCode;
+}
+
+namespace arc {
+
+class ArcBridgeService;
+
+// Private implementation of ArcInputBridge
+class ArcInputBridgeImpl : public ArcInputBridge,
+                           public ArcBridgeService::Observer,
+                           public aura::EnvObserver,
+                           public ui::EventHandler {
+ public:
+  // The constructor will register an Observer with aura::Env and the
+  // ArcBridgeService. From then on, no further interaction with this class
+  // is needed.
+  explicit ArcInputBridgeImpl(ArcBridgeService* arc_bridge_service);
+  ~ArcInputBridgeImpl() override;
+
+  // Overridden from ui::EventHandler:
+  void OnEvent(ui::Event* event) override;
+
+  // Overridden from aura::EnvObserver:
+  void OnWindowInitialized(aura::Window* new_window) override;
+
+  // Overridden from ArcBridgeService::Observer:
+  void OnInstanceBootPhase(InstanceBootPhase phase) override;
+
+ private:
+  // Specialized method to translate and send events to the right file
+  // descriptor.
+  void SendKeyEvent(ui::KeyEvent* event);
+  void SendTouchEvent(ui::TouchEvent* event);
+  void SendMouseEvent(ui::MouseEvent* event);
+
+  // Helper method to send a struct input_event to the file descriptor. This
+  // method is to be called on the ui thread and will post a request to send
+  // the event to the io thread.
+  // The parameters map directly to the members of input_event as
+  // defined by the evdev protocol.
+  // |type| is the type of event to sent, such as EV_SYN, EV_KEY, EV_ABS.
+  // |code| is either interpreted as axis (ABS_X, ABS_Y, ...) or as key-code
+  //        (KEY_A, KEY_B, ...).
+  // |value| is either the value of that axis or the boolean value of the key
+  //         as in 0 (released), 1 (pressed) or 2 (repeated press).
+  void SendKernelEvent(const base::ScopedFD& fd,
+                       base::TimeDelta timestamp,
+                       unsigned short type,
+                       unsigned short code,
+                       int value);
+
+  // Shorthand for sending EV_SYN/SYN_REPORT
+  void SendSynReport(const base::ScopedFD& fd, base::TimeDelta timestamp);
+
+  // Return existing or new slot for this event.
+  int AcquireTouchSlot(ui::TouchEvent* event);
+
+  // Return touch slot for tracking id.
+  int FindTouchSlot(int tracking_id);
+
+  // Maps DOM key codes to evdev key codes
+  unsigned short DomCodeToEvdevCode(ui::DomCode dom_code);
+
+
+  // Setup bridge devices on the instance side. This needs to be called after
+  // the InstanceBootPhase::SYSTEM_SERVICES_READY has been reached.
+  void SetupBridgeDevices();
+
+  // Creates and registers file descriptor pair with the ARC bridge service,
+  // the write end is returned while the read end is sent through the bridge
+  // to the ARC instance.
+  // TODO(denniskempin): Make this interface more typesafe.
+  // |name| should be the displayable name of the emulated device (e.g. "Chrome
+  // OS Keyboard"), |device_type| the name of the device type (e.g. "keyboard")
+  // and |fd| a file descriptor that emulates the kernel events of the device.
+  // This can only be called on the thread that this class was created on.
+  base::ScopedFD CreateBridgeInputDevice(const std::string& name,
+                                         const std::string& device_type);
+
+  // Owned by ArcServiceManager which makes sure ArcBridgeService is destroyed
+  // after ArcInputBridge.
+  ArcBridgeService* arc_bridge_service_;
+
+  // File descriptors for the different device types.
+  base::ScopedFD keyboard_fd_;
+  base::ScopedFD mouse_fd_;
+  base::ScopedFD touchscreen_fd_;
+
+  // Scroll accumlator.
+  float offset_x_acc_;
+  float offset_y_acc_;
+
+  // Currently selected slot for multi-touch events.
+  int current_slot_;
+
+  // List of touch tracking id to slot assignments.
+  std::vector<int> current_slot_tracking_ids_;
+
+  scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
+
+  // List of windows we are hooked into
+  aura::WindowTracker arc_windows_;
+
+  // WeakPtrFactory to use for callbacks.
+  base::WeakPtrFactory<ArcInputBridgeImpl> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcInputBridgeImpl);
+};
+
+}  // namespace arc
+
+#endif  // COMPONENTS_EXO_ARC_INPUT_ARC_INPUT_BRIDGE_IMPL_H_
diff --git a/components/autofill.gypi b/components/autofill.gypi
index af4f855..2f2ac05 100644
--- a/components/autofill.gypi
+++ b/components/autofill.gypi
@@ -11,6 +11,7 @@
       'dependencies': [
         '../base/base.gyp:base',
         '../base/base.gyp:base_i18n',
+        '../third_party/re2/re2.gyp:re2',
         '../ui/base/ui_base.gyp:ui_base',
         '../ui/gfx/gfx.gyp:gfx',
         '../url/url.gyp:url_lib',
diff --git a/components/autofill/content/browser/content_autofill_driver.cc b/components/autofill/content/browser/content_autofill_driver.cc
index f329d3c..788ab1d 100644
--- a/components/autofill/content/browser/content_autofill_driver.cc
+++ b/components/autofill/content/browser/content_autofill_driver.cc
@@ -161,6 +161,9 @@
   IPC_MESSAGE_FORWARD(AutofillHostMsg_TextFieldDidChange,
                       autofill_manager_.get(),
                       AutofillManager::OnTextFieldDidChange)
+  IPC_MESSAGE_FORWARD(AutofillHostMsg_FocusNoLongerOnForm,
+                      autofill_manager_.get(),
+                      AutofillManager::OnFocusNoLongerOnForm)
   IPC_MESSAGE_FORWARD(AutofillHostMsg_QueryFormFieldAutofill,
                       autofill_manager_.get(),
                       AutofillManager::OnQueryFormFieldAutofill)
diff --git a/components/autofill/content/common/autofill_messages.h b/components/autofill/content/common/autofill_messages.h
index b3878cb..f1d3ea6a 100644
--- a/components/autofill/content/common/autofill_messages.h
+++ b/components/autofill/content/common/autofill_messages.h
@@ -282,8 +282,12 @@
 // Sent immediately after the renderer receives a ping IPC.
 IPC_MESSAGE_ROUTED0(AutofillHostMsg_PingAck)
 
+// Sent when the current form is no longer focused.
+IPC_MESSAGE_ROUTED0(AutofillHostMsg_FocusNoLongerOnForm)
+
 // Sent when a form is filled with Autofill suggestions.
-IPC_MESSAGE_ROUTED1(AutofillHostMsg_DidFillAutofillFormData,
+IPC_MESSAGE_ROUTED2(AutofillHostMsg_DidFillAutofillFormData,
+                    autofill::FormData /* the form */,
                     base::TimeTicks /* timestamp */)
 
 // Sent when a form receives a request to do interactive autocomplete.
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index afb8274..5d00761e 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -259,11 +259,24 @@
 void AutofillAgent::FocusedNodeChanged(const WebNode& node) {
   HidePopup();
 
-  if (node.isNull() || !node.isElementNode())
+  if (node.isNull() || !node.isElementNode()) {
+    if (!last_interacted_form_.isNull()) {
+      // Focus moved away from the last interacted form to somewhere else on
+      // the page.
+      Send(new AutofillHostMsg_FocusNoLongerOnForm(routing_id()));
+    }
     return;
+  }
 
   WebElement web_element = node.toConst<WebElement>();
   const WebInputElement* element = toWebInputElement(&web_element);
+  if (!element || (!last_interacted_form_.isNull() &&
+                   last_interacted_form_ != element->form())) {
+    // The focused element is not part of the last interacted form (could be
+    // in a different form).
+    Send(new AutofillHostMsg_FocusNoLongerOnForm(routing_id()));
+    return;
+  }
 
   if (!element || !element->isEnabled() || element->isReadOnly() ||
       !element->isTextField())
@@ -523,7 +536,7 @@
   if (!element_.form().isNull())
     last_interacted_form_ = element_.form();
 
-  Send(new AutofillHostMsg_DidFillAutofillFormData(routing_id(),
+  Send(new AutofillHostMsg_DidFillAutofillFormData(routing_id(), form,
                                                    base::TimeTicks::Now()));
 }
 
diff --git a/components/autofill/core/browser/address_field.cc b/components/autofill/core/browser/address_field.cc
index bf96dc2..b9948dbc 100644
--- a/components/autofill/core/browser/address_field.cc
+++ b/components/autofill/core/browser/address_field.cc
@@ -8,16 +8,12 @@
 
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/strings/string16.h"
 #include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/autofill_regex_constants.h"
 #include "components/autofill/core/browser/autofill_scanner.h"
 #include "components/autofill/core/browser/field_types.h"
 
-using base::UTF8ToUTF16;
-
 namespace autofill {
 
 namespace {
@@ -48,9 +44,6 @@
   const AutofillField* const initial_field = scanner->Cursor();
   size_t saved_cursor = scanner->SaveCursor();
 
-  base::string16 attention_ignored = UTF8ToUTF16(kAttentionIgnoredRe);
-  base::string16 region_ignored = UTF8ToUTF16(kRegionIgnoredRe);
-
   // Allow address fields to appear in any order.
   size_t begin_trailing_non_labeled_fields = 0;
   bool has_trailing_non_labeled_fields = false;
@@ -62,8 +55,8 @@
         address_field->ParseCompany(scanner)) {
       has_trailing_non_labeled_fields = false;
       continue;
-    } else if (ParseField(scanner, attention_ignored, NULL) ||
-               ParseField(scanner, region_ignored, NULL)) {
+    } else if (ParseField(scanner, kAttentionIgnoredRe, NULL) ||
+               ParseField(scanner, kRegionIgnoredRe, NULL)) {
       // We ignore the following:
       // * Attention.
       // * Province/Region/Other.
@@ -148,7 +141,7 @@
   if (company_ && !company_->IsEmpty())
     return false;
 
-  return ParseField(scanner, UTF8ToUTF16(kCompanyRe), &company_);
+  return ParseField(scanner, kCompanyRe, &company_);
 }
 
 bool AddressField::ParseAddressLines(AutofillScanner* scanner) {
@@ -164,19 +157,17 @@
     return false;
 
   // Ignore "Address Lookup" field. http://crbug.com/427622
-  if (ParseField(scanner, base::UTF8ToUTF16(kAddressLookupRe), NULL))
+  if (ParseField(scanner, kAddressLookupRe, NULL))
     return false;
 
-  base::string16 pattern = UTF8ToUTF16(kAddressLine1Re);
-  base::string16 label_pattern = UTF8ToUTF16(kAddressLine1LabelRe);
-  if (!ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT, &address1_) &&
-      !ParseFieldSpecifics(scanner, label_pattern, MATCH_LABEL | MATCH_TEXT,
+  if (!ParseFieldSpecifics(scanner, kAddressLine1Re, MATCH_DEFAULT,
                            &address1_) &&
-      !ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT | MATCH_TEXT_AREA,
-                           &street_address_) &&
-      !ParseFieldSpecifics(scanner, label_pattern,
-                           MATCH_LABEL | MATCH_TEXT_AREA,
-                           &street_address_))
+      !ParseFieldSpecifics(scanner, kAddressLine1LabelRe,
+                           MATCH_LABEL | MATCH_TEXT, &address1_) &&
+      !ParseFieldSpecifics(scanner, kAddressLine1Re,
+                           MATCH_DEFAULT | MATCH_TEXT_AREA, &street_address_) &&
+      !ParseFieldSpecifics(scanner, kAddressLine1LabelRe,
+                           MATCH_LABEL | MATCH_TEXT_AREA, &street_address_))
     return false;
 
   if (street_address_)
@@ -185,19 +176,16 @@
   // This code may not pick up pages that have an address field consisting of a
   // sequence of unlabeled address fields. If we need to add this, see
   // discussion on https://codereview.chromium.org/741493003/
-  pattern = UTF8ToUTF16(kAddressLine2Re);
-  label_pattern = UTF8ToUTF16(kAddressLine2LabelRe);
-  if (!ParseField(scanner, pattern, &address2_) &&
-      !ParseFieldSpecifics(scanner, label_pattern, MATCH_LABEL | MATCH_TEXT,
-                           &address2_))
+  if (!ParseField(scanner, kAddressLine2Re, &address2_) &&
+      !ParseFieldSpecifics(scanner, kAddressLine2LabelRe,
+                           MATCH_LABEL | MATCH_TEXT, &address2_))
     return true;
 
   // Optionally parse address line 3. This uses the same label regexp as
   // address 2 above.
-  pattern = UTF8ToUTF16(kAddressLinesExtraRe);
-  if (!ParseField(scanner, pattern, &address3_) &&
-      !ParseFieldSpecifics(scanner, label_pattern, MATCH_LABEL | MATCH_TEXT,
-                           &address3_))
+  if (!ParseField(scanner, kAddressLinesExtraRe, &address3_) &&
+      !ParseFieldSpecifics(scanner, kAddressLine2LabelRe,
+                           MATCH_LABEL | MATCH_TEXT, &address3_))
     return true;
 
   // Try for surplus lines, which we will promptly discard. Some pages have 4
@@ -205,8 +193,7 @@
   //
   // Since these are rare, don't bother considering unlabeled lines as extra
   // address lines.
-  pattern = UTF8ToUTF16(kAddressLinesExtraRe);
-  while (ParseField(scanner, pattern, NULL)) {
+  while (ParseField(scanner, kAddressLinesExtraRe, NULL)) {
     // Consumed a surplus line, try for another.
   }
   return true;
@@ -217,9 +204,7 @@
     return false;
 
   scanner->SaveCursor();
-  if (ParseFieldSpecifics(scanner,
-                          UTF8ToUTF16(kCountryRe),
-                          MATCH_DEFAULT | MATCH_SELECT,
+  if (ParseFieldSpecifics(scanner, kCountryRe, MATCH_DEFAULT | MATCH_SELECT,
                           &country_)) {
     return true;
   }
@@ -227,8 +212,7 @@
   // The occasional page (e.g. google account registration page) calls this a
   // "location". However, this only makes sense for select tags.
   scanner->Rewind();
-  return ParseFieldSpecifics(scanner,
-                             UTF8ToUTF16(kCountryLocationRe),
+  return ParseFieldSpecifics(scanner, kCountryLocationRe,
                              MATCH_LABEL | MATCH_NAME | MATCH_SELECT,
                              &country_);
 }
@@ -237,16 +221,13 @@
   if (zip_)
     return false;
 
-  if (!ParseFieldSpecifics(scanner,
-                           UTF8ToUTF16(kZipCodeRe),
-                           kZipCodeMatchType,
-                           &zip_)) {
+  if (!ParseFieldSpecifics(scanner, kZipCodeRe, kZipCodeMatchType, &zip_)) {
     return false;
   }
 
   // Look for a zip+4, whose field name will also often contain
   // the substring "zip".
-  ParseFieldSpecifics(scanner, UTF8ToUTF16(kZip4Re), kZipCodeMatchType, &zip4_);
+  ParseFieldSpecifics(scanner, kZip4Re, kZipCodeMatchType, &zip4_);
   return true;
 }
 
@@ -254,20 +235,21 @@
   if (city_)
     return false;
 
-  return ParseFieldSpecifics(scanner,
-                             UTF8ToUTF16(kCityRe),
-                             kCityMatchType,
-                             &city_);
+  return ParseFieldSpecifics(scanner, kCityRe, kCityMatchType, &city_);
 }
 
 bool AddressField::ParseState(AutofillScanner* scanner) {
   if (state_)
     return false;
 
-  return ParseFieldSpecifics(scanner,
-                             UTF8ToUTF16(kStateRe),
-                             kStateMatchType,
-                             &state_);
+  // Ignore spurious matches for "United States".
+  size_t saved_cursor = scanner->SaveCursor();
+  if (ParseFieldSpecifics(scanner, "United States", kStateMatchType, nullptr)) {
+    scanner->RewindTo(saved_cursor);
+    return false;
+  }
+
+  return ParseFieldSpecifics(scanner, kStateRe, kStateMatchType, &state_);
 }
 
 bool AddressField::ParseCityStateZipCode(AutofillScanner* scanner) {
@@ -329,7 +311,7 @@
     return RESULT_MATCH_NONE;
 
   ParseNameLabelResult result = ParseNameAndLabelSeparately(
-      scanner, UTF8ToUTF16(kZipCodeRe), kZipCodeMatchType, &zip_);
+      scanner, kZipCodeRe, kZipCodeMatchType, &zip_);
 
   if (result != RESULT_MATCH_NAME_LABEL || scanner->IsEnd())
     return result;
@@ -349,10 +331,7 @@
   if (!found_non_zip4) {
     // Look for a zip+4, whose field name will also often contain
     // the substring "zip".
-    ParseFieldSpecifics(scanner,
-                        UTF8ToUTF16(kZip4Re),
-                        kZipCodeMatchType,
-                        &zip4_);
+    ParseFieldSpecifics(scanner, kZip4Re, kZipCodeMatchType, &zip4_);
   }
   return result;
 }
@@ -362,8 +341,7 @@
   if (city_)
     return RESULT_MATCH_NONE;
 
-  return ParseNameAndLabelSeparately(
-      scanner, UTF8ToUTF16(kCityRe), kCityMatchType, &city_);
+  return ParseNameAndLabelSeparately(scanner, kCityRe, kCityMatchType, &city_);
 }
 
 AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForState(
@@ -371,8 +349,14 @@
   if (state_)
     return RESULT_MATCH_NONE;
 
-  return ParseNameAndLabelSeparately(
-      scanner, UTF8ToUTF16(kStateRe), kStateMatchType, &state_);
+  size_t saved_cursor = scanner->SaveCursor();
+  if (ParseFieldSpecifics(scanner, "United States", kStateMatchType, nullptr)) {
+    scanner->RewindTo(saved_cursor);
+    return RESULT_MATCH_NONE;
+  }
+
+  return ParseNameAndLabelSeparately(scanner, kStateRe, kStateMatchType,
+                                     &state_);
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_download_manager.cc b/components/autofill/core/browser/autofill_download_manager.cc
index 38c8484..fa292e27 100644
--- a/components/autofill/core/browser/autofill_download_manager.cc
+++ b/components/autofill/core/browser/autofill_download_manager.cc
@@ -132,10 +132,12 @@
     const FormStructure& form,
     bool form_was_autofilled,
     const ServerFieldTypeSet& available_field_types,
-    const std::string& login_form_signature) {
+    const std::string& login_form_signature,
+    bool observed_submission) {
   std::string form_xml;
   if (!form.EncodeUploadRequest(available_field_types, form_was_autofilled,
-                                login_form_signature, &form_xml))
+                                login_form_signature, observed_submission,
+                                &form_xml))
     return false;
 
   if (next_upload_request_ > base::Time::Now()) {
@@ -202,9 +204,10 @@
     return false;
   }
 
-  AutofillMetrics::LogPayloadCompressionRatio(
-      static_cast<int>(100 * compressed_data.size() / form_xml.size()),
-      request_data.request_type);
+  const int compression_ratio =
+      static_cast<int>(100 * compressed_data.size() / form_xml.size());
+  AutofillMetrics::LogPayloadCompressionRatio(compression_ratio,
+                                              request_data.request_type);
 
   // Id is ignored for regular chrome, in unit test id's for fake fetcher
   // factory will be 0, 1, 2, ...
@@ -228,8 +231,8 @@
   fetcher->Start();
 
   VLOG(1) << "Sending AutofillDownloadManager "
-           << RequestTypeToString(request_data.request_type)
-           << " request: " << form_xml;
+          << RequestTypeToString(request_data.request_type)
+          << " request (compression " << compression_ratio << "): " << form_xml;
 
   return true;
 }
diff --git a/components/autofill/core/browser/autofill_download_manager.h b/components/autofill/core/browser/autofill_download_manager.h
index 8dedb72..57530ca0 100644
--- a/components/autofill/core/browser/autofill_download_manager.h
+++ b/components/autofill/core/browser/autofill_download_manager.h
@@ -85,11 +85,14 @@
   // Note that in this case, |form.FormSignature()| gives the signature for the
   // registration form on which the password was generated, rather than the
   // submitted form's signature.
+  // |observed_submission| indicates whether the upload request is the result of
+  // an observed submission event.
   virtual bool StartUploadRequest(
       const FormStructure& form,
       bool form_was_autofilled,
       const ServerFieldTypeSet& available_field_types,
-      const std::string& login_form_signature);
+      const std::string& login_form_signature,
+      bool observed_submission);
 
  private:
   friend class AutofillDownloadTest;
diff --git a/components/autofill/core/browser/autofill_download_manager_unittest.cc b/components/autofill/core/browser/autofill_download_manager_unittest.cc
index 2982ae12..cddcc14 100644
--- a/components/autofill/core/browser/autofill_download_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_download_manager_unittest.cc
@@ -234,14 +234,14 @@
   download_manager_.SetNegativeUploadRate(1.0);
   // Request with id 1.
   EXPECT_TRUE(download_manager_.StartUploadRequest(
-      *(form_structures[0]), true, ServerFieldTypeSet(), std::string()));
+      *(form_structures[0]), true, ServerFieldTypeSet(), std::string(), true));
   // Request with id 2.
   EXPECT_TRUE(download_manager_.StartUploadRequest(
-      *(form_structures[1]), false, ServerFieldTypeSet(), std::string()));
+      *(form_structures[1]), false, ServerFieldTypeSet(), std::string(), true));
   // Request with id 3. Upload request with a non-empty additional password form
   // signature.
-  EXPECT_TRUE(download_manager_.StartUploadRequest(*(form_structures[2]), false,
-                                                   ServerFieldTypeSet(), "42"));
+  EXPECT_TRUE(download_manager_.StartUploadRequest(
+      *(form_structures[2]), false, ServerFieldTypeSet(), "42", true));
 
   const char *responses[] = {
     "<autofillqueryresponse>"
@@ -306,9 +306,9 @@
   download_manager_.SetNegativeUploadRate(0.0);
   // No actual requests for the next two calls, as we set upload rate to 0%.
   EXPECT_FALSE(download_manager_.StartUploadRequest(
-      *(form_structures[0]), true, ServerFieldTypeSet(), std::string()));
+      *(form_structures[0]), true, ServerFieldTypeSet(), std::string(), true));
   EXPECT_FALSE(download_manager_.StartUploadRequest(
-      *(form_structures[1]), false, ServerFieldTypeSet(), std::string()));
+      *(form_structures[1]), false, ServerFieldTypeSet(), std::string(), true));
   fetcher = factory.GetFetcherByID(4);
   EXPECT_EQ(NULL, fetcher);
 
@@ -347,7 +347,7 @@
   form_structures[0]->upload_required_ = UPLOAD_REQUIRED;
   // Request with id 4.
   EXPECT_TRUE(download_manager_.StartUploadRequest(
-      *(form_structures[0]), true, ServerFieldTypeSet(), std::string()));
+      *(form_structures[0]), true, ServerFieldTypeSet(), std::string(), true));
   fetcher = factory.GetFetcherByID(5);
   ASSERT_TRUE(fetcher);
   fetcher->set_backoff_delay(TestTimeouts::action_max_timeout());
@@ -359,7 +359,7 @@
 
   // Upload requests should be ignored for the next 10 seconds.
   EXPECT_FALSE(download_manager_.StartUploadRequest(
-      *(form_structures[0]), true, ServerFieldTypeSet(), std::string()));
+      *(form_structures[0]), true, ServerFieldTypeSet(), std::string(), true));
   fetcher = factory.GetFetcherByID(6);
   EXPECT_EQ(NULL, fetcher);
 }
@@ -614,6 +614,8 @@
   EXPECT_EQ("gzip", header);
 
   // Expect that the compression is logged.
+  // NOTE: To get the expected value, run tests with --vmodule=autofill*=1 and
+  // watch for the VLOG which indicates compression.
   histogram.ExpectUniqueSample("Autofill.PayloadCompressionRatio.Query", 72, 1);
 }
 
@@ -621,7 +623,8 @@
   // Expected upload (uncompressed for visual verification).
   const char* kExpectedUploadXml =
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"14546501144368603154\" autofillused=\"true\""
       " datapresent=\"\"/>\n";
 
@@ -656,7 +659,7 @@
   base::HistogramTester histogram;
   // Request with id 0.
   EXPECT_TRUE(download_manager_.StartUploadRequest(
-      *(form_structures[0]), true, ServerFieldTypeSet(), std::string()));
+      *(form_structures[0]), true, ServerFieldTypeSet(), std::string(), true));
 
   // Request payload is gzipped.
   net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
@@ -671,7 +674,9 @@
   EXPECT_EQ("gzip", header);
 
   // Expect that the compression is logged.
-  histogram.ExpectUniqueSample("Autofill.PayloadCompressionRatio.Upload", 95,
+  // NOTE: To get the expected value, run tests with --vmodule=autofill*=1 and
+  // watch for the VLOG which indicates compression.
+  histogram.ExpectUniqueSample("Autofill.PayloadCompressionRatio.Upload", 90,
                                1);
 }
 
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index c3c0776..99e2aff 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -227,6 +227,30 @@
                                  base::ASCIIToUTF16("0123456789"));
 }
 
+void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms,
+                                  const TimeTicks& timestamp) {
+  if (!IsValidFormDataVector(forms))
+    return;
+
+  if (!driver_->RendererIsAvailable())
+    return;
+
+  bool enabled = IsAutofillEnabled();
+  if (!has_logged_autofill_enabled_) {
+    AutofillMetrics::LogIsAutofillEnabledAtPageLoad(enabled);
+    has_logged_autofill_enabled_ = true;
+  }
+
+  if (!enabled)
+    return;
+
+  for (const FormData& form : forms) {
+    forms_loaded_timestamps_[form] = timestamp;
+  }
+
+  ParseForms(forms);
+}
+
 bool AutofillManager::OnWillSubmitForm(const FormData& form,
                                        const TimeTicks& timestamp) {
   if (!IsValidFormData(form))
@@ -253,45 +277,7 @@
   address_form_event_logger_->OnWillSubmitForm();
   credit_card_form_event_logger_->OnWillSubmitForm();
 
-  // Only upload server statistics and UMA metrics if at least some local data
-  // is available to use as a baseline.
-  const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
-  if (submitted_form->IsAutofillable()) {
-    AutofillMetrics::LogNumberOfProfilesAtAutofillableFormSubmission(
-        personal_data_->GetProfiles().size());
-  }
-  const std::vector<CreditCard*>& credit_cards =
-      personal_data_->GetCreditCards();
-  if (!profiles.empty() || !credit_cards.empty()) {
-    // Copy the profile and credit card data, so that it can be accessed on a
-    // separate thread.
-    std::vector<AutofillProfile> copied_profiles;
-    copied_profiles.reserve(profiles.size());
-    for (const AutofillProfile* profile : profiles)
-      copied_profiles.push_back(*profile);
-
-    std::vector<CreditCard> copied_credit_cards;
-    copied_credit_cards.reserve(credit_cards.size());
-    for (const CreditCard* card : credit_cards)
-      copied_credit_cards.push_back(*card);
-
-    // Note that ownership of |submitted_form| is passed to the second task,
-    // using |base::Owned|.
-    FormStructure* raw_submitted_form = submitted_form.get();
-    driver_->GetBlockingPool()->PostTaskAndReply(
-        FROM_HERE,
-        base::Bind(&DeterminePossibleFieldTypesForUpload,
-                   copied_profiles,
-                   copied_credit_cards,
-                   app_locale_,
-                   raw_submitted_form),
-        base::Bind(&AutofillManager::UploadFormDataAsyncCallback,
-                   weak_ptr_factory_.GetWeakPtr(),
-                   base::Owned(submitted_form.release()),
-                   forms_loaded_timestamps_[form],
-                   initial_interaction_timestamp_,
-                   timestamp));
-  }
+  StartUploadProcess(std::move(submitted_form), timestamp, true);
 
   return true;
 }
@@ -318,28 +304,69 @@
   return true;
 }
 
-void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms,
-                                  const TimeTicks& timestamp) {
-  if (!IsValidFormDataVector(forms))
-    return;
-
-  if (!driver_->RendererIsAvailable())
-    return;
-
-  bool enabled = IsAutofillEnabled();
-  if (!has_logged_autofill_enabled_) {
-    AutofillMetrics::LogIsAutofillEnabledAtPageLoad(enabled);
-    has_logged_autofill_enabled_ = true;
+void AutofillManager::StartUploadProcess(
+    scoped_ptr<FormStructure> form_structure,
+    const TimeTicks& timestamp,
+    bool observed_submission) {
+  // Only upload server statistics and UMA metrics if at least some local data
+  // is available to use as a baseline.
+  const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
+  if (observed_submission && form_structure->IsAutofillable()) {
+    // TODO(mathp): provide metrics for non-submission uploads.
+    AutofillMetrics::LogNumberOfProfilesAtAutofillableFormSubmission(
+        personal_data_->GetProfiles().size());
   }
+  const std::vector<CreditCard*>& credit_cards =
+      personal_data_->GetCreditCards();
+  if (!profiles.empty() || !credit_cards.empty()) {
+    // Copy the profile and credit card data, so that it can be accessed on a
+    // separate thread.
+    std::vector<AutofillProfile> copied_profiles;
+    copied_profiles.reserve(profiles.size());
+    for (const AutofillProfile* profile : profiles)
+      copied_profiles.push_back(*profile);
 
-  if (!enabled)
+    std::vector<CreditCard> copied_credit_cards;
+    copied_credit_cards.reserve(credit_cards.size());
+    for (const CreditCard* card : credit_cards)
+      copied_credit_cards.push_back(*card);
+
+    // Note that ownership of |form_structure| is passed to the second task,
+    // using |base::Owned|.
+    FormStructure* raw_form = form_structure.get();
+    TimeTicks loaded_timestamp =
+        forms_loaded_timestamps_[raw_form->ToFormData()];
+    driver_->GetBlockingPool()->PostTaskAndReply(
+        FROM_HERE,
+        base::Bind(&DeterminePossibleFieldTypesForUpload, copied_profiles,
+                   copied_credit_cards, app_locale_, raw_form),
+        base::Bind(&AutofillManager::UploadFormDataAsyncCallback,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   base::Owned(form_structure.release()), loaded_timestamp,
+                   initial_interaction_timestamp_, timestamp,
+                   observed_submission));
+  }
+}
+
+void AutofillManager::UpdatePendingForm(const FormData& form) {
+  // Process the current pending form if different than supplied |form|.
+  if (pending_form_data_ && !pending_form_data_->SameFormAs(form)) {
+    ProcessPendingFormForUpload();
+  }
+  // A new pending form is assigned.
+  pending_form_data_.reset(new FormData(form));
+}
+
+void AutofillManager::ProcessPendingFormForUpload() {
+  if (!pending_form_data_)
     return;
 
-  for (size_t i = 0; i < forms.size(); ++i) {
-    forms_loaded_timestamps_[forms[i]] = timestamp;
-  }
+  // We copy |pending_form_data_| to a new FormStructure to be consumed by the
+  // upload process and reset |pending_form_data_|.
+  scoped_ptr<FormStructure> upload_form(new FormStructure(*pending_form_data_));
+  pending_form_data_.reset();
 
-  ParseForms(forms);
+  StartUploadProcess(std::move(upload_form), base::TimeTicks::Now(), false);
 }
 
 void AutofillManager::OnTextFieldDidChange(const FormData& form,
@@ -356,6 +383,8 @@
   if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field))
     return;
 
+  UpdatePendingForm(form);
+
   if (!user_did_type_) {
     user_did_type_ = true;
     AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::USER_DID_TYPE);
@@ -594,15 +623,22 @@
                              form, field, credit_card, true);
 }
 
+void AutofillManager::OnFocusNoLongerOnForm() {
+  ProcessPendingFormForUpload();
+}
+
 void AutofillManager::OnDidPreviewAutofillFormData() {
   if (test_delegate_)
     test_delegate_->DidPreviewFormData();
 }
 
-void AutofillManager::OnDidFillAutofillFormData(const TimeTicks& timestamp) {
+void AutofillManager::OnDidFillAutofillFormData(const FormData& form,
+                                                const TimeTicks& timestamp) {
   if (test_delegate_)
     test_delegate_->DidFillFormData();
 
+  UpdatePendingForm(form);
+
   AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::USER_DID_AUTOFILL);
   if (!user_did_autofill_) {
     user_did_autofill_ = true;
@@ -1014,16 +1050,21 @@
     const FormStructure* submitted_form,
     const TimeTicks& load_time,
     const TimeTicks& interaction_time,
-    const TimeTicks& submission_time) {
-  submitted_form->LogQualityMetrics(
-      load_time, interaction_time, submission_time, client_->GetRapporService(),
-      did_show_suggestions_);
+    const TimeTicks& submission_time,
+    bool observed_submission) {
+  // TODO(mathp): Have different set of metrics for non-submission uploads.
+  if (observed_submission) {
+    submitted_form->LogQualityMetrics(
+        load_time, interaction_time, submission_time,
+        client_->GetRapporService(), did_show_suggestions_);
+  }
 
   if (submitted_form->ShouldBeCrowdsourced())
-    UploadFormData(*submitted_form);
+    UploadFormData(*submitted_form, observed_submission);
 }
 
-void AutofillManager::UploadFormData(const FormStructure& submitted_form) {
+void AutofillManager::UploadFormData(const FormStructure& submitted_form,
+                                     bool observed_submission) {
   if (!download_manager_)
     return;
 
@@ -1042,7 +1083,7 @@
 
   download_manager_->StartUploadRequest(
       submitted_form, was_autofilled, non_empty_types,
-      std::string() /* login_form_signature */);
+      std::string() /* login_form_signature */, observed_submission);
 }
 
 void AutofillManager::Reset() {
@@ -1059,6 +1100,8 @@
   user_did_type_ = false;
   user_did_autofill_ = false;
   user_did_edit_autofilled_field_ = false;
+  ProcessPendingFormForUpload();
+  DCHECK(!pending_form_data_);
   unmask_request_ = payments::PaymentsClient::UnmaskRequestDetails();
   unmasking_query_id_ = -1;
   unmasking_form_ = FormData();
@@ -1501,7 +1544,6 @@
   for (const FormData& form : forms) {
     scoped_ptr<FormStructure> form_structure(new FormStructure(form));
     form_structure->ParseFieldTypesFromAutocompleteAttributes();
-
     if (!form_structure->ShouldBeParsed())
       continue;
 
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h
index aac1d95..f766f09 100644
--- a/components/autofill/core/browser/autofill_manager.h
+++ b/components/autofill/core/browser/autofill_manager.h
@@ -109,7 +109,9 @@
   void DidShowSuggestions(bool is_new_popup,
                           const FormData& form,
                           const FormFieldData& field);
-  void OnDidFillAutofillFormData(const base::TimeTicks& timestamp);
+  void OnFocusNoLongerOnForm();
+  void OnDidFillAutofillFormData(const FormData& form,
+                                 const base::TimeTicks& timestamp);
   void OnDidPreviewAutofillFormData();
 
   // Returns true if the value/identifier is deletable. Fills out
@@ -166,6 +168,20 @@
   // personal profile. Returns false if this form is not relevant for Autofill.
   bool OnFormSubmitted(const FormData& form);
 
+  // Will send an upload based on the |form_structure| data and the local
+  // Autofill profile data. |observed_submission| is specified if the upload
+  // follows an observed submission event.
+  void StartUploadProcess(scoped_ptr<FormStructure> form_structure,
+                          const base::TimeTicks& timestamp,
+                          bool observed_submission);
+
+  // Update the pending form with |form|, possibly processing the current
+  // pending form for upload.
+  void UpdatePendingForm(const FormData& form);
+
+  // Upload the current pending form.
+  void ProcessPendingFormForUpload();
+
   void OnTextFieldDidChange(const FormData& form,
                             const FormFieldData& field,
                             const base::TimeTicks& timestamp);
@@ -201,16 +217,20 @@
                   AutofillClient* client,
                   PersonalDataManager* personal_data);
 
-  // Uploads the form data to the Autofill server.
-  virtual void UploadFormData(const FormStructure& submitted_form);
+  // Uploads the form data to the Autofill server. |observed_submission|
+  // indicates that upload is the result of a submission event.
+  virtual void UploadFormData(const FormStructure& submitted_form,
+                              bool observed_submission);
 
   // Logs quality metrics for the |submitted_form| and uploads the form data
-  // to the crowdsourcing server, if appropriate.
+  // to the crowdsourcing server, if appropriate. |observed_submission|
+  // indicates whether the upload is a result of an observed submission event.
   virtual void UploadFormDataAsyncCallback(
       const FormStructure* submitted_form,
       const base::TimeTicks& load_time,
       const base::TimeTicks& interaction_time,
-      const base::TimeTicks& submission_time);
+      const base::TimeTicks& submission_time,
+      bool observed_submission);
 
   // Maps suggestion backend ID to and from an integer identifying it. Two of
   // these intermediate integers are packed by MakeFrontendID to make the IDs
@@ -444,6 +464,9 @@
   // Our copy of the form data.
   ScopedVector<FormStructure> form_structures_;
 
+  // A copy of the currently interacted form data.
+  scoped_ptr<FormData> pending_form_data_;
+
   // Collected information about a pending unmask request, and data about the
   // form.
   payments::PaymentsClient::UnmaskRequestDetails unmask_request_;
@@ -458,7 +481,7 @@
   bool user_did_accept_upload_prompt_;
 
   // Masked copies of recently unmasked cards, to help avoid double-asking to
-  // save the card (in the prompt and in the infobar after submit).
+  // save the card (in the unmask prompt and in the save prompt after submit).
   std::vector<CreditCard> recently_unmasked_cards_;
 
 #ifdef ENABLE_FORM_DEBUG_DUMP
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index 87dccd9..8f8af8e 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -472,7 +472,8 @@
         autofill_enabled_(true),
         credit_card_upload_enabled_(true),
         credit_card_was_uploaded_(false),
-        expect_all_unknown_possible_types_(false) {
+        expect_all_unknown_possible_types_(false),
+        expected_observed_submission_(true) {
     set_payments_client(
         new TestPaymentsClient(driver->GetURLRequestContext(), this));
   }
@@ -499,13 +500,19 @@
     expected_submitted_field_types_ = expected_types;
   }
 
-  void UploadFormDataAsyncCallback(
-      const FormStructure* submitted_form,
-      const base::TimeTicks& load_time,
-      const base::TimeTicks& interaction_time,
-      const base::TimeTicks& submission_time) override {
+  void set_expected_observed_submission(bool expected) {
+    expected_observed_submission_ = expected;
+  }
+
+  void UploadFormDataAsyncCallback(const FormStructure* submitted_form,
+                                   const base::TimeTicks& load_time,
+                                   const base::TimeTicks& interaction_time,
+                                   const base::TimeTicks& submission_time,
+                                   bool observed_submission) override {
     run_loop_->Quit();
 
+    EXPECT_EQ(expected_observed_submission_, observed_submission);
+
     // If we have expected field types set, make sure they match.
     if (!expected_submitted_field_types_.empty()) {
       ASSERT_EQ(expected_submitted_field_types_.size(),
@@ -528,20 +535,20 @@
       }
     }
 
-    AutofillManager::UploadFormDataAsyncCallback(submitted_form,
-                                                 load_time,
-                                                 interaction_time,
-                                                 submission_time);
+    AutofillManager::UploadFormDataAsyncCallback(
+        submitted_form, load_time, interaction_time, submission_time,
+        observed_submission);
   }
 
   // Resets the run loop so that it can wait for an asynchronous form
   // submission to complete.
   void ResetRunLoop() { run_loop_.reset(new base::RunLoop()); }
 
-  // Wait for the asynchronous OnWillSubmitForm() call to complete.
-  void WaitForAsyncOnWillSubmitForm() { run_loop_->Run(); }
+  // Wait for the asynchronous calls within StartUploadProcess() to complete.
+  void WaitForAsyncUploadProcess() { run_loop_->Run(); }
 
-  void UploadFormData(const FormStructure& submitted_form) override {
+  void UploadFormData(const FormStructure& submitted_form,
+                      bool observed_submission) override {
     submitted_form_signature_ = submitted_form.FormSignature();
   }
 
@@ -592,6 +599,7 @@
   bool credit_card_upload_enabled_;
   bool credit_card_was_uploaded_;
   bool expect_all_unknown_possible_types_;
+  bool expected_observed_submission_;
 
   scoped_ptr<base::RunLoop> run_loop_;
 
@@ -760,7 +768,7 @@
   void FormSubmitted(const FormData& form) {
     autofill_manager_->ResetRunLoop();
     if (autofill_manager_->OnWillSubmitForm(form, base::TimeTicks::Now()))
-      autofill_manager_->WaitForAsyncOnWillSubmitForm();
+      autofill_manager_->WaitForAsyncUploadProcess();
     autofill_manager_->OnFormSubmitted(form);
   }
 
@@ -2574,7 +2582,7 @@
   // OnFormSubmitted.
   autofill_manager_->ResetRunLoop();
   autofill_manager_->OnWillSubmitForm(response_data, base::TimeTicks::Now());
-  autofill_manager_->WaitForAsyncOnWillSubmitForm();
+  autofill_manager_->WaitForAsyncUploadProcess();
   EXPECT_EQ(0, personal_data_.num_times_save_imported_profile_called());
 }
 
@@ -3433,6 +3441,155 @@
   EXPECT_TRUE(external_delegate_->on_query_seen());
 }
 
+// Test that unfocusing a filled form sends an upload with types matching the
+// fields.
+TEST_F(AutofillManagerTest, OnTextFieldDidChangeAndUnfocus_Upload) {
+  // Set up our form data (it's already filled out with user data).
+  FormData form;
+  form.name = ASCIIToUTF16("MyForm");
+  form.origin = GURL("http://myform.com/form.html");
+  form.action = GURL("http://myform.com/submit.html");
+
+  std::vector<ServerFieldTypeSet> expected_types;
+  ServerFieldTypeSet types;
+
+  FormFieldData field;
+  test::CreateTestFormField("First Name", "firstname", "Elvis", "text", &field);
+  form.fields.push_back(field);
+  types.insert(NAME_FIRST);
+  expected_types.push_back(types);
+
+  test::CreateTestFormField("Last Name", "lastname", "Presley", "text", &field);
+  form.fields.push_back(field);
+  types.clear();
+  types.insert(NAME_LAST);
+  expected_types.push_back(types);
+
+  test::CreateTestFormField("Email", "email", "theking@gmail.com", "text",
+                            &field);
+  form.fields.push_back(field);
+  types.clear();
+  types.insert(EMAIL_ADDRESS);
+  expected_types.push_back(types);
+
+  FormsSeen(std::vector<FormData>(1, form));
+
+  // We will expect these types in the upload and no observed submission (the
+  // callback initiated by WaitForAsyncUploadProcess checks these expectations.)
+  autofill_manager_->set_expected_submitted_field_types(expected_types);
+  autofill_manager_->set_expected_observed_submission(false);
+
+  // Simulate editing a field.
+  autofill_manager_->OnTextFieldDidChange(form, form.fields.front(),
+                                          base::TimeTicks::Now());
+
+  autofill_manager_->ResetRunLoop();
+  // Simulate lost of focus on the form.
+  autofill_manager_->OnFocusNoLongerOnForm();
+  // Wait for upload to complete (will check expected types as well).
+  autofill_manager_->WaitForAsyncUploadProcess();
+}
+
+// Test that navigating with a filled form sends an upload with types matching
+// the fields.
+TEST_F(AutofillManagerTest, OnTextFieldDidChangeAndNavigation_Upload) {
+  // Set up our form data (it's already filled out with user data).
+  FormData form;
+  form.name = ASCIIToUTF16("MyForm");
+  form.origin = GURL("http://myform.com/form.html");
+  form.action = GURL("http://myform.com/submit.html");
+
+  std::vector<ServerFieldTypeSet> expected_types;
+  ServerFieldTypeSet types;
+
+  FormFieldData field;
+  test::CreateTestFormField("First Name", "firstname", "Elvis", "text", &field);
+  form.fields.push_back(field);
+  types.insert(NAME_FIRST);
+  expected_types.push_back(types);
+
+  test::CreateTestFormField("Last Name", "lastname", "Presley", "text", &field);
+  form.fields.push_back(field);
+  types.clear();
+  types.insert(NAME_LAST);
+  expected_types.push_back(types);
+
+  test::CreateTestFormField("Email", "email", "theking@gmail.com", "text",
+                            &field);
+  form.fields.push_back(field);
+  types.clear();
+  types.insert(EMAIL_ADDRESS);
+  expected_types.push_back(types);
+
+  FormsSeen(std::vector<FormData>(1, form));
+
+  // We will expect these types in the upload and no observed submission. (the
+  // callback initiated by WaitForAsyncUploadProcess checks these expectations.)
+  autofill_manager_->set_expected_submitted_field_types(expected_types);
+  autofill_manager_->set_expected_observed_submission(false);
+
+  // Simulate editing a field.
+  autofill_manager_->OnTextFieldDidChange(form, form.fields.front(),
+                                          base::TimeTicks::Now());
+
+  autofill_manager_->ResetRunLoop();
+  // Simulate a navigation so that the pending form is uploaded.
+  autofill_manager_->Reset();
+  // Wait for upload to complete (will check expected types as well).
+  autofill_manager_->WaitForAsyncUploadProcess();
+}
+
+// Test that unfocusing a filled form sends an upload with types matching the
+// fields.
+TEST_F(AutofillManagerTest, OnDidFillAutofillFormDataAndUnfocus_Upload) {
+  // Set up our form data (empty).
+  FormData form;
+  form.name = ASCIIToUTF16("MyForm");
+  form.origin = GURL("http://myform.com/form.html");
+  form.action = GURL("http://myform.com/submit.html");
+
+  std::vector<ServerFieldTypeSet> expected_types;
+
+  // These fields should all match.
+  ServerFieldTypeSet types;
+  FormFieldData field;
+  test::CreateTestFormField("First Name", "firstname", "", "text", &field);
+  form.fields.push_back(field);
+  types.insert(NAME_FIRST);
+  expected_types.push_back(types);
+
+  test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
+  form.fields.push_back(field);
+  types.clear();
+  types.insert(NAME_LAST);
+  expected_types.push_back(types);
+
+  test::CreateTestFormField("Email", "email", "", "text", &field);
+  form.fields.push_back(field);
+  types.clear();
+  types.insert(EMAIL_ADDRESS);
+  expected_types.push_back(types);
+
+  FormsSeen(std::vector<FormData>(1, form));
+
+  // We will expect these types in the upload and no observed submission. (the
+  // callback initiated by WaitForAsyncUploadProcess checks these expectations.)
+  autofill_manager_->set_expected_submitted_field_types(expected_types);
+  autofill_manager_->set_expected_observed_submission(false);
+
+  // Form was autofilled with user data.
+  form.fields[0].value = base::ASCIIToUTF16("Elvis");
+  form.fields[1].value = base::ASCIIToUTF16("Presley");
+  form.fields[2].value = base::ASCIIToUTF16("theking@gmail.com");
+  autofill_manager_->OnDidFillAutofillFormData(form, base::TimeTicks::Now());
+
+  autofill_manager_->ResetRunLoop();
+  // Simulate lost of focus on the form.
+  autofill_manager_->OnFocusNoLongerOnForm();
+  // Wait for upload to complete.
+  autofill_manager_->WaitForAsyncUploadProcess();
+}
+
 // Test to verify suggestions appears for forms having credit card number split
 // across fields.
 TEST_F(AutofillManagerTest, GetCreditCardSuggestionsForNumberSpitAcrossFields) {
diff --git a/components/autofill/core/browser/autofill_metrics_unittest.cc b/components/autofill/core/browser/autofill_metrics_unittest.cc
index ed36d534..f7777f54 100644
--- a/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -253,12 +253,12 @@
 
   // Calls AutofillManager::OnWillSubmitForm and waits for it to complete.
   void WillSubmitForm(const FormData& form, const TimeTicks& timestamp) {
-    run_loop_.reset(new base::RunLoop());
+    ResetRunLoop();
     if (!OnWillSubmitForm(form, timestamp))
       return;
 
     // Wait for the asynchronous OnWillSubmitForm() call to complete.
-    run_loop_->Run();
+    RunRunLoop();
   }
 
   // Calls both AutofillManager::OnWillSubmitForm and
@@ -268,17 +268,20 @@
     OnFormSubmitted(form);
   }
 
-  void UploadFormDataAsyncCallback(
-      const FormStructure* submitted_form,
-      const base::TimeTicks& load_time,
-      const base::TimeTicks& interaction_time,
-      const base::TimeTicks& submission_time) override {
+  // Control the run loop from within tests.
+  void ResetRunLoop() { run_loop_.reset(new base::RunLoop()); }
+  void RunRunLoop() { run_loop_->Run(); }
+
+  void UploadFormDataAsyncCallback(const FormStructure* submitted_form,
+                                   const base::TimeTicks& load_time,
+                                   const base::TimeTicks& interaction_time,
+                                   const base::TimeTicks& submission_time,
+                                   bool observed_submission) override {
     run_loop_->Quit();
 
-    AutofillManager::UploadFormDataAsyncCallback(submitted_form,
-                                                 load_time,
-                                                 interaction_time,
-                                                 submission_time);
+    AutofillManager::UploadFormDataAsyncCallback(
+        submitted_form, load_time, interaction_time, submission_time,
+        observed_submission);
   }
 
  private:
@@ -2854,7 +2857,7 @@
   // Simulate invoking autofill.
   {
     base::HistogramTester histogram_tester;
-    autofill_manager_->OnDidFillAutofillFormData(TimeTicks());
+    autofill_manager_->OnDidFillAutofillFormData(form, TimeTicks());
     histogram_tester.ExpectBucketCount("Autofill.UserHappiness",
                                        AutofillMetrics::USER_DID_AUTOFILL, 1);
     histogram_tester.ExpectBucketCount(
@@ -2884,7 +2887,7 @@
   // Simulate invoking autofill again.
   {
     base::HistogramTester histogram_tester;
-    autofill_manager_->OnDidFillAutofillFormData(TimeTicks());
+    autofill_manager_->OnDidFillAutofillFormData(form, TimeTicks());
     histogram_tester.ExpectUniqueSample("Autofill.UserHappiness",
                                         AutofillMetrics::USER_DID_AUTOFILL, 1);
   }
@@ -2915,7 +2918,7 @@
   test::CreateTestFormField("Phone", "phone", "", "text", &field);
   form.fields.push_back(field);
 
-  std::vector<FormData> forms(1, form);
+  const std::vector<FormData> forms(1, form);
 
   // Fill additional form.
   FormData second_form = form;
@@ -2971,7 +2974,10 @@
     histogram_tester.ExpectUniqueSample(
         "Autofill.FillDuration.FromInteraction.WithoutAutofill", 14, 1);
 
+    // We expected an upload to be triggered when the manager is reset.
+    autofill_manager_->ResetRunLoop();
     autofill_manager_->Reset();
+    autofill_manager_->RunRunLoop();
   }
 
   // Expect metric to be logged if the user autofilled the form.
@@ -2980,7 +2986,7 @@
     base::HistogramTester histogram_tester;
     autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1));
     autofill_manager_->OnDidFillAutofillFormData(
-        TimeTicks::FromInternalValue(5));
+        form, TimeTicks::FromInternalValue(5));
     autofill_manager_->SubmitForm(form, TimeTicks::FromInternalValue(17));
 
     histogram_tester.ExpectUniqueSample(
@@ -2992,7 +2998,10 @@
     histogram_tester.ExpectTotalCount(
         "Autofill.FillDuration.FromInteraction.WithoutAutofill", 0);
 
+    // We expected an upload to be triggered when the manager is reset.
+    autofill_manager_->ResetRunLoop();
     autofill_manager_->Reset();
+    autofill_manager_->RunRunLoop();
   }
 
   // Expect metric to be logged if the user both manually filled some fields
@@ -3003,7 +3012,7 @@
 
     autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1));
     autofill_manager_->OnDidFillAutofillFormData(
-        TimeTicks::FromInternalValue(5));
+        form, TimeTicks::FromInternalValue(5));
     autofill_manager_->OnTextFieldDidChange(form, form.fields.front(),
                                             TimeTicks::FromInternalValue(3));
     autofill_manager_->SubmitForm(form, TimeTicks::FromInternalValue(17));
@@ -3017,7 +3026,10 @@
     histogram_tester.ExpectTotalCount(
         "Autofill.FillDuration.FromInteraction.WithoutAutofill", 0);
 
+    // We expected an upload to be triggered when the manager is reset.
+    autofill_manager_->ResetRunLoop();
     autofill_manager_->Reset();
+    autofill_manager_->RunRunLoop();
   }
 
   // Make sure that loading another form doesn't affect metrics from the first
@@ -3028,7 +3040,7 @@
     autofill_manager_->OnFormsSeen(second_forms,
                                    TimeTicks::FromInternalValue(3));
     autofill_manager_->OnDidFillAutofillFormData(
-        TimeTicks::FromInternalValue(5));
+        form, TimeTicks::FromInternalValue(5));
     autofill_manager_->OnTextFieldDidChange(form, form.fields.front(),
                                             TimeTicks::FromInternalValue(3));
     autofill_manager_->SubmitForm(form, TimeTicks::FromInternalValue(17));
@@ -3042,7 +3054,11 @@
     histogram_tester.ExpectTotalCount(
         "Autofill.FillDuration.FromInteraction.WithoutAutofill", 0);
 
+    // We expected an upload to be triggered when the manager is reset.
+    autofill_manager_->ResetRunLoop();
     autofill_manager_->Reset();
+    autofill_manager_->RunRunLoop();
+    ;
   }
 
   // Make sure that submitting a form that was loaded later will report the
diff --git a/components/autofill/core/browser/autofill_regex_constants.cc b/components/autofill/core/browser/autofill_regex_constants.cc
index 4aed1a53..d4b49cb 100644
--- a/components/autofill/core/browser/autofill_regex_constants.cc
+++ b/components/autofill/core/browser/autofill_regex_constants.cc
@@ -8,6 +8,10 @@
 
 #include "components/autofill/core/browser/autofill_regex_constants.h"
 
+// This macro is to workaround the fact that RE2 library only supports ASCII
+// word boundaries and it is supposed to be the same as \b.
+#define WORDBREAK "(\\A|\\z|\\PL)"
+
 namespace autofill {
 
 /////////////////////////////////////////////////////////////////////////////
@@ -84,11 +88,11 @@
     "zip|postal|post.*code|pcode"
     "|pin.?code"  // en-IN
     "|postleitzahl"  // de-DE
-    "|\\bcp\\b"  // es
-    "|\\bcdp\\b"  // fr-FR
-    "|\\bcap\\b"  // it-IT
+    "|" WORDBREAK "cp" WORDBREAK  // es
+    "|" WORDBREAK "cdp" WORDBREAK  // fr-FR
+    "|" WORDBREAK "cap" WORDBREAK  // it-IT
     "|郵便番号"  // ja-JP
-    "|codigo|codpos|\\bcep\\b"  // pt-BR, pt-PT
+    "|codigo|codpos|" WORDBREAK "cep" WORDBREAK  // pt-BR, pt-PT
     "|Почтовый.?Индекс"  // ru
     "|邮政编码|邮编"  // zh-CN
     "|郵遞區號"  // zh-TW
@@ -98,7 +102,7 @@
     "|codpos2";  // pt-BR, pt-PT
 const char kCityRe[] =
     "city|town"
-    "|\\bort\\b|stadt"  // de-DE
+    "|" WORDBREAK "ort" WORDBREAK "|stadt"  // de-DE
     "|suburb"  // en-AU
     "|ciudad|provincia|localidad|poblacion"  // es
     "|ville|commune"  // fr-FR
@@ -110,7 +114,7 @@
     "|分區"  // zh-TW
     "|^시[^도·・]|시[·・]?군[·・]?구";  // ko-KR
 const char kStateRe[] =
-    "(?<!united )state|county|region|province"
+    "state|county|region|province"
     "|land"  // de-DE
     "|county|principality"  // en-UK
     "|都道府県"  // ja-JP
@@ -124,7 +128,8 @@
 // credit_card_field.cc
 /////////////////////////////////////////////////////////////////////////////
 const char kNameOnCardRe[] =
-    "card.?(holder|owner)|name.*\\bon\\b.*card|(card|cc).?name|cc.?full.?name"
+    "card.?(holder|owner)|name.*" WORDBREAK "on" WORDBREAK ".*card"
+    "|(card|cc).?name|cc.?full.?name"
     "|karteninhaber"  // de-DE
     "|nombre.*tarjeta"  // es
     "|nom.*carte"  // fr-FR
@@ -148,7 +153,7 @@
 const char kCardCvcRe[] =
     "verification|card identification|security code|card code"
     "|cvn|cvv|cvc|csc|cvd|cid|ccv"
-    "|\\bcid\\b";
+    "|" WORDBREAK "cid" WORDBREAK;
 
 // "Expiration date" is the most common label here, but some pages have
 // "Expires", "exp. date" or "exp. month" and "exp. year".  We also look
@@ -247,7 +252,8 @@
     "|nome"  // pt-BR, pt-PT
     "|Имя"  // ru
     "|이름";  // ko-KR
-const char kMiddleInitialRe[] = "middle.*initial|m\\.i\\.|mi$|\\bmi\\b";
+const char kMiddleInitialRe[] =
+    "middle.*initial|m\\.i\\.|mi$|" WORDBREAK "mi" WORDBREAK;
 const char kMiddleNameRe[] =
     "middle.*name|mname|middle$"
     "|apellido.?materno|lastlastname";  // es
@@ -293,7 +299,9 @@
 const char kPhoneSuffixRe[] =
     "suffix";
 const char kPhoneExtensionRe[] =
-    "\\bext|ext\\b|extension"
+    WORDBREAK "ext|ext" WORDBREAK "|extension"
     "|ramal";  // pt-BR, pt-PT
 
 }  // namespace autofill
+
+#undef WORDBREAK
diff --git a/components/autofill/core/browser/credit_card.cc b/components/autofill/core/browser/credit_card.cc
index 00593e7..51d697f 100644
--- a/components/autofill/core/browser/credit_card.cc
+++ b/components/autofill/core/browser/credit_card.cc
@@ -444,7 +444,7 @@
 
 void CreditCard::SetInfoForMonthInputType(const base::string16& value) {
   // Check if |text| is "yyyy-mm" format first, and check normal month format.
-  if (!MatchesPattern(value, base::UTF8ToUTF16("^[0-9]{4}-[0-9]{1,2}$")))
+  if (!MatchesPattern(value, "^[0-9]{4}-[0-9]{1,2}$"))
     return;
 
   std::vector<base::StringPiece16> year_month = base::SplitStringPiece(
diff --git a/components/autofill/core/browser/credit_card_field.cc b/components/autofill/core/browser/credit_card_field.cc
index 3b24ec3..9edfef2 100644
--- a/components/autofill/core/browser/credit_card_field.cc
+++ b/components/autofill/core/browser/credit_card_field.cc
@@ -11,7 +11,6 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/autofill_regex_constants.h"
@@ -31,7 +30,7 @@
 
 // Look for the vector |regex_needles| in |haystack|. Returns true if a
 // consecutive section of |haystack| matches |regex_needles|.
-bool FindConsecutiveStrings(const std::vector<base::string16>& regex_needles,
+bool FindConsecutiveStrings(const std::vector<std::string>& regex_needles,
                             const std::vector<base::string16>& haystack) {
   if (regex_needles.empty() ||
       haystack.empty() ||
@@ -91,9 +90,7 @@
       break;
 
     if (!credit_card_field->cardholder_) {
-      if (ParseField(scanner,
-                     base::UTF8ToUTF16(kNameOnCardRe),
-                     &credit_card_field->cardholder_)) {
+      if (ParseField(scanner, kNameOnCardRe, &credit_card_field->cardholder_)) {
         continue;
       }
 
@@ -103,10 +100,8 @@
       // fields. So we search for "name" only when we've already parsed at
       // least one other credit card field and haven't yet parsed the
       // expiration date (which usually appears at the end).
-      if (fields > 0 &&
-          !credit_card_field->expiration_month_ &&
-          ParseField(scanner,
-                     base::UTF8ToUTF16(kNameOnCardContextualRe),
+      if (fields > 0 && !credit_card_field->expiration_month_ &&
+          ParseField(scanner, kNameOnCardContextualRe,
                      &credit_card_field->cardholder_)) {
         continue;
       }
@@ -129,7 +124,7 @@
     const int kMatchNumAndTel = MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE;
     if (!credit_card_field->verification_ &&
         ParseFieldSpecifics(scanner,
-                            base::UTF8ToUTF16(kCardCvcRe),
+                            kCardCvcRe,
                             kMatchNumAndTel | MATCH_PASSWORD,
                             &credit_card_field->verification_)) {
       continue;
@@ -137,7 +132,7 @@
 
     AutofillField* current_number_field;
     if (ParseFieldSpecifics(scanner,
-                            base::UTF8ToUTF16(kCardNumberRe),
+                            kCardNumberRe,
                             kMatchNumAndTel,
                             &current_number_field)) {
       // Avoid autofilling any credit card number field having very low or high
@@ -214,8 +209,7 @@
     return false;
 
   // Filter out years.
-  const base::string16 kNumericalYearRe =
-      base::ASCIIToUTF16("[1-9][0-9][0-9][0-9]");
+  const char kNumericalYearRe[] = "[1-9][0-9][0-9][0-9]";
   for (const auto& value : field->option_values) {
     if (MatchesPattern(value, kNumericalYearRe))
       return false;
@@ -226,7 +220,7 @@
   }
 
   // Look for numerical months.
-  const base::string16 kNumericalMonthRe = base::ASCIIToUTF16("12");
+  const char kNumericalMonthRe[] = "12";
   if (MatchesPattern(field->option_values.back(), kNumericalMonthRe) ||
       MatchesPattern(field->option_contents.back(), kNumericalMonthRe)) {
     return true;
@@ -252,11 +246,11 @@
   time_now.UTCExplode(&time_exploded);
 
   const int kYearsToMatch = 3;
-  std::vector<base::string16> years_to_check;
+  std::vector<std::string> years_to_check;
   for (int year = time_exploded.year;
        year < time_exploded.year + kYearsToMatch;
        ++year) {
-    years_to_check.push_back(base::IntToString16(year));
+    years_to_check.push_back(base::IntToString(year));
   }
   return (FindConsecutiveStrings(years_to_check, field->option_values) ||
           FindConsecutiveStrings(years_to_check, field->option_contents));
@@ -285,16 +279,16 @@
     return false;
 
   size_t saved_cursor = scanner->SaveCursor();
-  if (ParseField(scanner, base::UTF8ToUTF16(kDebitCardRe), nullptr)) {
+  if (ParseField(scanner, kDebitCardRe, nullptr)) {
     scanner->RewindTo(saved_cursor);
     return false;
   }
-  if (ParseField(scanner, base::UTF8ToUTF16(kDebitGiftCardRe), nullptr)) {
+  if (ParseField(scanner, kDebitGiftCardRe, nullptr)) {
     scanner->RewindTo(saved_cursor);
     return false;
   }
 
-  return ParseField(scanner, base::UTF8ToUTF16(kGiftCardRe), nullptr);
+  return ParseField(scanner, kGiftCardRe, nullptr);
 }
 
 CreditCardField::CreditCardField()
@@ -376,11 +370,11 @@
   scanner->RewindTo(month_year_saved_cursor);
   const int kMatchTelAndSelect = MATCH_DEFAULT | MATCH_TELEPHONE | MATCH_SELECT;
   if (ParseFieldSpecifics(scanner,
-                          base::UTF8ToUTF16(kExpirationMonthRe),
+                          kExpirationMonthRe,
                           kMatchTelAndSelect,
                           &expiration_month_) &&
       ParseFieldSpecifics(scanner,
-                          base::UTF8ToUTF16(kExpirationYearRe),
+                          kExpirationYearRe,
                           kMatchTelAndSelect,
                           &expiration_year_)) {
     return true;
@@ -389,11 +383,11 @@
   // If that fails, look for just MM/YY(YY).
   scanner->RewindTo(month_year_saved_cursor);
   if (ParseFieldSpecifics(scanner,
-                          base::ASCIIToUTF16("^mm$"),
+                          "^mm$",
                           kMatchTelAndSelect,
                           &expiration_month_) &&
       ParseFieldSpecifics(scanner,
-                          base::ASCIIToUTF16("^(yy|yyyy)$"),
+                          "^(yy|yyyy)$",
                           kMatchTelAndSelect,
                           &expiration_year_)) {
     return true;
@@ -412,7 +406,7 @@
 
   // Try to look for a 2-digit year expiration date.
   if (ParseFieldSpecifics(scanner,
-                          base::UTF8ToUTF16(kExpirationDate2DigitYearRe),
+                          kExpirationDate2DigitYearRe,
                           kMatchTelAndSelect,
                           &expiration_date_)) {
     exp_year_type_ = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR;
@@ -422,7 +416,7 @@
 
   // Try to look for a generic expiration date field. (2 or 4 digit year)
   if (ParseFieldSpecifics(scanner,
-                          base::UTF8ToUTF16(kExpirationDateRe),
+                          kExpirationDateRe,
                           kMatchTelAndSelect,
                           &expiration_date_)) {
     // If such a field exists, but it cannot fit a 4-digit year expiration
@@ -440,7 +434,7 @@
   if (FieldCanFitDataForFieldType(current_field_max_length,
                                   CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) &&
       ParseFieldSpecifics(scanner,
-                          base::UTF8ToUTF16(kExpirationDate4DigitYearRe),
+                          kExpirationDate4DigitYearRe,
                           kMatchTelAndSelect,
                           &expiration_date_)) {
     expiration_month_ = nullptr;
diff --git a/components/autofill/core/browser/email_field.cc b/components/autofill/core/browser/email_field.cc
index cfe4a1a..98ed4626 100644
--- a/components/autofill/core/browser/email_field.cc
+++ b/components/autofill/core/browser/email_field.cc
@@ -4,7 +4,6 @@
 
 #include "components/autofill/core/browser/email_field.h"
 
-#include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/autofill_regex_constants.h"
 #include "components/autofill/core/browser/autofill_scanner.h"
 
@@ -13,8 +12,8 @@
 // static
 scoped_ptr<FormField> EmailField::Parse(AutofillScanner* scanner) {
   AutofillField* field;
-  if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kEmailRe),
-                          MATCH_DEFAULT | MATCH_EMAIL, &field)) {
+  if (ParseFieldSpecifics(scanner, kEmailRe, MATCH_DEFAULT | MATCH_EMAIL,
+                          &field)) {
     return make_scoped_ptr(new EmailField(field));
   }
 
diff --git a/components/autofill/core/browser/form_field.cc b/components/autofill/core/browser/form_field.cc
index 50d7e8a3..69a3771 100644
--- a/components/autofill/core/browser/form_field.cc
+++ b/components/autofill/core/browser/form_field.cc
@@ -12,7 +12,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/address_field.h"
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/autofill_scanner.h"
@@ -84,14 +83,14 @@
 
 // static
 bool FormField::ParseField(AutofillScanner* scanner,
-                           const base::string16& pattern,
+                           const std::string& pattern,
                            AutofillField** match) {
   return ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT, match);
 }
 
 // static
 bool FormField::ParseFieldSpecifics(AutofillScanner* scanner,
-                                    const base::string16& pattern,
+                                    const std::string& pattern,
                                     int match_type,
                                     AutofillField** match) {
   if (scanner->IsEnd())
@@ -108,7 +107,7 @@
 // static
 FormField::ParseNameLabelResult FormField::ParseNameAndLabelSeparately(
     AutofillScanner* scanner,
-    const base::string16& pattern,
+    const std::string& pattern,
     int match_type,
     AutofillField** match) {
   if (scanner->IsEnd())
@@ -143,7 +142,7 @@
 bool FormField::ParseEmptyLabel(AutofillScanner* scanner,
                                 AutofillField** match) {
   return ParseFieldSpecifics(scanner,
-                             base::ASCIIToUTF16("^$"),
+                             "^$",
                              MATCH_LABEL | MATCH_ALL_INPUTS,
                              match);
 }
@@ -161,7 +160,7 @@
 
 // static.
 bool FormField::MatchAndAdvance(AutofillScanner* scanner,
-                                const base::string16& pattern,
+                                const std::string& pattern,
                                 int match_type,
                                 AutofillField** match) {
   AutofillField* field = scanner->Cursor();
@@ -177,7 +176,7 @@
 
 // static
 bool FormField::Match(const AutofillField* field,
-                      const base::string16& pattern,
+                      const std::string& pattern,
                       int match_type) {
   if ((match_type & FormField::MATCH_LABEL) &&
       MatchesPattern(field->label, pattern)) {
diff --git a/components/autofill/core/browser/form_field.h b/components/autofill/core/browser/form_field.h
index c27dc089..1b1248e 100644
--- a/components/autofill/core/browser/form_field.h
+++ b/components/autofill/core/browser/form_field.h
@@ -69,7 +69,7 @@
   // Attempts to parse a form field with the given pattern.  Returns true on
   // success and fills |match| with a pointer to the field.
   static bool ParseField(AutofillScanner* scanner,
-                         const base::string16& pattern,
+                         const std::string& pattern,
                          AutofillField** match);
 
   // Parses the stream of fields in |scanner| with regular expression |pattern|
@@ -78,7 +78,7 @@
   // A |true| result is returned in the case of a successful match, false
   // otherwise.
   static bool ParseFieldSpecifics(AutofillScanner* scanner,
-                                  const base::string16& pattern,
+                                  const std::string& pattern,
                                   int match_type,
                                   AutofillField** match);
 
@@ -89,7 +89,7 @@
   // change.
   static ParseNameLabelResult ParseNameAndLabelSeparately(
       AutofillScanner* scanner,
-      const base::string16& pattern,
+      const std::string& pattern,
       int match_type,
       AutofillField** match);
 
@@ -123,14 +123,14 @@
   // Returns |true| if a match is found according to |match_type|, and |false|
   // otherwise.
   static bool MatchAndAdvance(AutofillScanner* scanner,
-                              const base::string16& pattern,
+                              const std::string& pattern,
                               int match_type,
                               AutofillField** match);
 
   // Matches the regular expression |pattern| against the components of |field|
   // as specified in the |match_type| bit field (see |MatchType|).
   static bool Match(const AutofillField* field,
-                    const base::string16& pattern,
+                    const std::string& pattern,
                     int match_type);
 
   // Perform a "pass" over the |fields| where each pass uses the supplied
diff --git a/components/autofill/core/browser/form_field_unittest.cc b/components/autofill/core/browser/form_field_unittest.cc
index f13c1d1..aac94d0 100644
--- a/components/autofill/core/browser/form_field_unittest.cc
+++ b/components/autofill/core/browser/form_field_unittest.cc
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "components/autofill/core/browser/form_field.h"
+
+#include <string>
+
 #include "base/memory/scoped_vector.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/autofill_field.h"
-#include "components/autofill/core/browser/form_field.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using base::ASCIIToUTF16;
@@ -17,108 +20,83 @@
   AutofillField field;
 
   // Empty strings match.
-  EXPECT_TRUE(FormField::Match(&field, base::string16(),
-                               FormField::MATCH_LABEL));
+  EXPECT_TRUE(FormField::Match(&field, std::string(), FormField::MATCH_LABEL));
 
   // Empty pattern matches non-empty string.
   field.label = ASCIIToUTF16("a");
-  EXPECT_TRUE(FormField::Match(&field, base::string16(),
-                               FormField::MATCH_LABEL));
+  EXPECT_TRUE(FormField::Match(&field, std::string(), FormField::MATCH_LABEL));
 
   // Strictly empty pattern matches empty string.
   field.label = base::string16();
-  EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("^$"),
-              FormField::MATCH_LABEL));
+  EXPECT_TRUE(FormField::Match(&field, "^$", FormField::MATCH_LABEL));
 
   // Strictly empty pattern does not match non-empty string.
   field.label = ASCIIToUTF16("a");
-  EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("^$"),
-               FormField::MATCH_LABEL));
+  EXPECT_FALSE(FormField::Match(&field, "^$", FormField::MATCH_LABEL));
 
   // Non-empty pattern doesn't match empty string.
   field.label = base::string16();
-  EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("a"),
-               FormField::MATCH_LABEL));
+  EXPECT_FALSE(FormField::Match(&field, "a", FormField::MATCH_LABEL));
 
   // Beginning of line.
   field.label = ASCIIToUTF16("head_tail");
-  EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("^head"),
-              FormField::MATCH_LABEL));
-  EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("^tail"),
-               FormField::MATCH_LABEL));
+  EXPECT_TRUE(FormField::Match(&field, "^head", FormField::MATCH_LABEL));
+  EXPECT_FALSE(FormField::Match(&field, "^tail", FormField::MATCH_LABEL));
 
   // End of line.
   field.label = ASCIIToUTF16("head_tail");
-  EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("head$"),
-               FormField::MATCH_LABEL));
-  EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("tail$"),
-              FormField::MATCH_LABEL));
+  EXPECT_FALSE(FormField::Match(&field, "head$", FormField::MATCH_LABEL));
+  EXPECT_TRUE(FormField::Match(&field, "tail$", FormField::MATCH_LABEL));
 
   // Exact.
   field.label = ASCIIToUTF16("head_tail");
-  EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("^head$"),
-               FormField::MATCH_LABEL));
-  EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("^tail$"),
-               FormField::MATCH_LABEL));
-  EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("^head_tail$"),
-              FormField::MATCH_LABEL));
+  EXPECT_FALSE(FormField::Match(&field, "^head$", FormField::MATCH_LABEL));
+  EXPECT_FALSE(FormField::Match(&field, "^tail$", FormField::MATCH_LABEL));
+  EXPECT_TRUE(FormField::Match(&field, "^head_tail$", FormField::MATCH_LABEL));
 
   // Escaped dots.
   field.label = ASCIIToUTF16("m.i.");
   // Note: This pattern is misleading as the "." characters are wild cards.
-  EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("m.i."),
-              FormField::MATCH_LABEL));
-  EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("m\\.i\\."),
-              FormField::MATCH_LABEL));
+  EXPECT_TRUE(FormField::Match(&field, "m.i.", FormField::MATCH_LABEL));
+  EXPECT_TRUE(FormField::Match(&field, "m\\.i\\.", FormField::MATCH_LABEL));
   field.label = ASCIIToUTF16("mXiX");
-  EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("m.i."),
-              FormField::MATCH_LABEL));
-  EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("m\\.i\\."),
-               FormField::MATCH_LABEL));
+  EXPECT_TRUE(FormField::Match(&field, "m.i.", FormField::MATCH_LABEL));
+  EXPECT_FALSE(FormField::Match(&field, "m\\.i\\.", FormField::MATCH_LABEL));
 
   // Repetition.
   field.label = ASCIIToUTF16("headtail");
-  EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head.*tail"),
-              FormField::MATCH_LABEL));
+  EXPECT_TRUE(FormField::Match(&field, "head.*tail", FormField::MATCH_LABEL));
   field.label = ASCIIToUTF16("headXtail");
-  EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head.*tail"),
-              FormField::MATCH_LABEL));
+  EXPECT_TRUE(FormField::Match(&field, "head.*tail", FormField::MATCH_LABEL));
   field.label = ASCIIToUTF16("headXXXtail");
-  EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head.*tail"),
-              FormField::MATCH_LABEL));
+  EXPECT_TRUE(FormField::Match(&field, "head.*tail", FormField::MATCH_LABEL));
   field.label = ASCIIToUTF16("headtail");
-  EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("head.+tail"),
-               FormField::MATCH_LABEL));
+  EXPECT_FALSE(FormField::Match(&field, "head.+tail", FormField::MATCH_LABEL));
   field.label = ASCIIToUTF16("headXtail");
-  EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head.+tail"),
-              FormField::MATCH_LABEL));
+  EXPECT_TRUE(FormField::Match(&field, "head.+tail", FormField::MATCH_LABEL));
   field.label = ASCIIToUTF16("headXXXtail");
-  EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head.+tail"),
-              FormField::MATCH_LABEL));
+  EXPECT_TRUE(FormField::Match(&field, "head.+tail", FormField::MATCH_LABEL));
 
   // Alternation.
   field.label = ASCIIToUTF16("head_tail");
-  EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head|other"),
-              FormField::MATCH_LABEL));
-  EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("tail|other"),
-              FormField::MATCH_LABEL));
-  EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("bad|good"),
-               FormField::MATCH_LABEL));
+  EXPECT_TRUE(FormField::Match(&field, "head|other", FormField::MATCH_LABEL));
+  EXPECT_TRUE(FormField::Match(&field, "tail|other", FormField::MATCH_LABEL));
+  EXPECT_FALSE(FormField::Match(&field, "bad|good", FormField::MATCH_LABEL));
 
   // Case sensitivity.
   field.label = ASCIIToUTF16("xxxHeAd_tAiLxxx");
-  EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head_tail"),
-              FormField::MATCH_LABEL));
+  EXPECT_TRUE(FormField::Match(&field, "head_tail", FormField::MATCH_LABEL));
 
   // Word boundaries.
+  const std::string kWordBoundary = "(\\A|\\z|\\PL)";
   field.label = ASCIIToUTF16("contains word:");
-  EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("\\bword\\b"),
+  EXPECT_TRUE(FormField::Match(&field, kWordBoundary + "word" + kWordBoundary,
                                FormField::MATCH_LABEL));
-  EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("\\bcon\\b"),
+  EXPECT_FALSE(FormField::Match(&field, kWordBoundary + "con" + kWordBoundary,
                                 FormField::MATCH_LABEL));
   // Make sure the circumflex in 'crepe' is not treated as a word boundary.
   field.label = base::UTF8ToUTF16("cr" "\xC3\xAA" "pe");
-  EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("\\bcr\\b"),
+  EXPECT_FALSE(FormField::Match(&field, kWordBoundary + "cr" + kWordBoundary,
                                 FormField::MATCH_LABEL));
 }
 
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index 351acbc..a2a25c4 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -43,6 +43,7 @@
 const char kAttributeAutofillUsed[] = "autofillused";
 const char kAttributeAutofillType[] = "autofilltype";
 const char kAttributeClientVersion[] = "clientversion";
+const char kAttributeSubmission[] = "submission";
 const char kAttributeDataPresent[] = "datapresent";
 const char kAttributeFieldID[] = "fieldid";
 const char kAttributeFieldType[] = "fieldtype";
@@ -453,6 +454,7 @@
     const ServerFieldTypeSet& available_field_types,
     bool form_was_autofilled,
     const std::string& login_form_signature,
+    bool observed_submission,
     std::string* encoded_xml) const {
   DCHECK(encoded_xml);
   DCHECK(ShouldBeCrowdsourced());
@@ -472,6 +474,9 @@
   xml_writer.StopIndenting();
   if (!xml_writer.StartElement(kXMLElementAutofillUpload))
     return false;
+  if (!xml_writer.AddAttribute(kAttributeSubmission,
+                               observed_submission ? "true" : "false"))
+    return false;
   if (!xml_writer.AddAttribute(kAttributeClientVersion, kClientVersion))
     return false;
   if (!xml_writer.AddAttribute(kAttributeFormSignature, FormSignature()))
diff --git a/components/autofill/core/browser/form_structure.h b/components/autofill/core/browser/form_structure.h
index 670f1c23..e6b2c36e 100644
--- a/components/autofill/core/browser/form_structure.h
+++ b/components/autofill/core/browser/form_structure.h
@@ -61,6 +61,7 @@
   bool EncodeUploadRequest(const ServerFieldTypeSet& available_field_types,
                            bool form_was_autofilled,
                            const std::string& login_form_signature,
+                           bool observed_submission,
                            std::string* encoded_xml) const;
 
   // Encodes a XML block contains autofill field type from this FormStructure.
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc
index b1acd4b..15e94e0 100644
--- a/components/autofill/core/browser/form_structure_unittest.cc
+++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -1675,11 +1675,12 @@
   available_field_types.insert(PHONE_HOME_WHOLE_NUMBER);
 
   std::string encoded_xml;
-  EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, false,
-                                                  std::string(), &encoded_xml));
+  EXPECT_TRUE(form_structure->EncodeUploadRequest(
+      available_field_types, false, std::string(), true, &encoded_xml));
   EXPECT_EQ(
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"8736493185895608956\" autofillused=\"false\""
       " datapresent=\"144200030e\""
       " actionsignature=\"15724779818122431245\">"
@@ -1695,11 +1696,12 @@
       " type=\"select-one\" label=\"Country\" autofilltype=\"36\"/>"
       "</autofillupload>\n",
       encoded_xml);
-  EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, true,
-                                                  std::string(), &encoded_xml));
+  EXPECT_TRUE(form_structure->EncodeUploadRequest(
+      available_field_types, true, std::string(), true, &encoded_xml));
   EXPECT_EQ(
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"8736493185895608956\""
       " autofillused=\"true\" datapresent=\"144200030e\""
       " actionsignature=\"15724779818122431245\">"
@@ -1734,11 +1736,12 @@
   for (size_t i = 0; i < form_structure->field_count(); ++i)
     form_structure->field(i)->set_possible_types(possible_field_types[i]);
 
-  EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, false,
-                                                  std::string(), &encoded_xml));
+  EXPECT_TRUE(form_structure->EncodeUploadRequest(
+      available_field_types, false, std::string(), true, &encoded_xml));
   EXPECT_EQ(
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"7816485729218079147\" autofillused=\"false\""
       " datapresent=\"144200030e\""
       " actionsignature=\"15724779818122431245\">"
@@ -1787,7 +1790,7 @@
   for (size_t i = 0; i < form_structure->field_count(); ++i)
     form_structure->field(i)->set_possible_types(possible_field_types[i]);
   EXPECT_FALSE(form_structure->EncodeUploadRequest(
-      available_field_types, false, std::string(), &encoded_xml));
+      available_field_types, false, std::string(), true, &encoded_xml));
 }
 
 TEST_F(FormStructureTest,
@@ -1850,9 +1853,9 @@
 
   std::string encoded_xml;
   EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, true,
-                                                  "42", &encoded_xml));
+                                                  "42", true, &encoded_xml));
   EXPECT_EQ(
-      "<?xml version=\"1.0\"?>\n<autofillupload "
+      "<?xml version=\"1.0\"?>\n<autofillupload submission=\"true\" "
       "clientversion=\"6.1.1715.1442/en (GGLL)\" "
       "formsignature=\"5810032074788446513\" autofillused=\"true\" "
       "datapresent=\"1440000000000000000802\" "
@@ -1916,11 +1919,12 @@
   available_field_types.insert(EMAIL_ADDRESS);
 
   std::string encoded_xml;
-  EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, true,
-                                                  std::string(), &encoded_xml));
+  EXPECT_TRUE(form_structure->EncodeUploadRequest(
+      available_field_types, true, std::string(), true, &encoded_xml));
   EXPECT_EQ(
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"14746822798145140279\" autofillused=\"true\""
       " datapresent=\"1440\" actionsignature=\"15724779818122431245\">"
       "<field signature=\"3763331450\" name=\"firstname\" type=\"text\""
@@ -1934,6 +1938,65 @@
       encoded_xml);
 }
 
+TEST_F(FormStructureTest, EncodeUploadRequest_ObservedSubmissionFalse) {
+  scoped_ptr<FormStructure> form_structure;
+  std::vector<ServerFieldTypeSet> possible_field_types;
+  FormData form;
+  form_structure.reset(new FormStructure(form));
+  form_structure->DetermineHeuristicTypes();
+
+  FormFieldData field;
+  field.form_control_type = "text";
+
+  field.label = ASCIIToUTF16("First Name");
+  field.name = ASCIIToUTF16("firstname");
+  form.fields.push_back(field);
+  possible_field_types.push_back(ServerFieldTypeSet());
+  possible_field_types.back().insert(NAME_FIRST);
+
+  field.label = ASCIIToUTF16("Last Name");
+  field.name = ASCIIToUTF16("lastname");
+  form.fields.push_back(field);
+  possible_field_types.push_back(ServerFieldTypeSet());
+  possible_field_types.back().insert(NAME_LAST);
+
+  field.label = ASCIIToUTF16("Email");
+  field.name = ASCIIToUTF16("email");
+  field.form_control_type = "email";
+  form.fields.push_back(field);
+  possible_field_types.push_back(ServerFieldTypeSet());
+  possible_field_types.back().insert(EMAIL_ADDRESS);
+
+  form_structure.reset(new FormStructure(form));
+
+  ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
+  for (size_t i = 0; i < form_structure->field_count(); ++i)
+    form_structure->field(i)->set_possible_types(possible_field_types[i]);
+
+  ServerFieldTypeSet available_field_types;
+  available_field_types.insert(NAME_FIRST);
+  available_field_types.insert(NAME_LAST);
+  available_field_types.insert(EMAIL_ADDRESS);
+
+  std::string encoded_xml;
+  EXPECT_TRUE(form_structure->EncodeUploadRequest(
+      available_field_types, true, std::string(),
+      /* observed_submission= */ false, &encoded_xml));
+  EXPECT_EQ(
+      "<?xml version=\"1.0\"?>\n"
+      "<autofillupload submission=\"false\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
+      " formsignature=\"14746822798145140279\" autofillused=\"true\""
+      " datapresent=\"1440\" actionsignature=\"15724779818122431245\">"
+      "<field signature=\"3763331450\" name=\"firstname\" type=\"text\""
+      " label=\"First Name\" autofilltype=\"3\"/>"
+      "<field signature=\"3494530716\" name=\"lastname\" type=\"text\""
+      " label=\"Last Name\" autofilltype=\"5\"/><field signature=\"1029417091\""
+      " name=\"email\" type=\"email\" label=\"Email\" autofilltype=\"9\"/>"
+      "</autofillupload>\n",
+      encoded_xml);
+}
+
 TEST_F(FormStructureTest, EncodeUploadRequest_WithLabels) {
   scoped_ptr<FormStructure> form_structure;
   std::vector<ServerFieldTypeSet> possible_field_types;
@@ -1971,12 +2034,13 @@
   available_field_types.insert(EMAIL_ADDRESS);
 
   std::string encoded_xml;
-  EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, true,
-                                                  std::string(), &encoded_xml));
+  EXPECT_TRUE(form_structure->EncodeUploadRequest(
+      available_field_types, true, std::string(), true, &encoded_xml));
   // Expected that the first field does not send the label but others do.
   EXPECT_EQ(
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"6949133589768631292\" autofillused=\"true\""
       " datapresent=\"1440\""
       " actionsignature=\"15724779818122431245\">"
@@ -2024,10 +2088,10 @@
   available_field_types.insert(EMAIL_ADDRESS);
 
   std::string encoded_xml;
-  EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, true,
-                                                  std::string(), &encoded_xml));
+  EXPECT_TRUE(form_structure->EncodeUploadRequest(
+      available_field_types, true, std::string(), true, &encoded_xml));
   EXPECT_EQ(
-      "<?xml version=\"1.0\"?>\n<autofillupload"
+      "<?xml version=\"1.0\"?>\n<autofillupload submission=\"true\""
       " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"2345951786066580868\" autofillused=\"true\""
       " datapresent=\"1440\" actionsignature=\"15724779818122431245\""
@@ -2081,11 +2145,12 @@
   available_field_types.insert(EMAIL_ADDRESS);
 
   std::string encoded_xml;
-  EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, true,
-                                                  std::string(), &encoded_xml));
+  EXPECT_TRUE(form_structure->EncodeUploadRequest(
+      available_field_types, true, std::string(), true, &encoded_xml));
   EXPECT_EQ(
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"13043654279838250996\" autofillused=\"true\""
       " datapresent=\"1440\" actionsignature=\"15724779818122431245\">"
       "<field signature=\"1318412689\" type=\"text\" autofilltype=\"3\"/>"
@@ -2145,11 +2210,12 @@
   available_field_types.insert(EMAIL_ADDRESS);
 
   std::string encoded_xml;
-  EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, true,
-                                                  std::string(), &encoded_xml));
+  EXPECT_TRUE(form_structure->EncodeUploadRequest(
+      available_field_types, true, std::string(), true, &encoded_xml));
   EXPECT_EQ(
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"14746822798145140279\" autofillused=\"true\""
       " datapresent=\"1440\"><field signature=\"3763331450\""
       " autofilltype=\"3\"/><field signature=\"3494530716\""
@@ -2316,11 +2382,12 @@
   ServerFieldTypeSet available_field_types;
 
   std::string encoded_xml;
-  EXPECT_TRUE(form_structure.EncodeUploadRequest(available_field_types, false,
-                                                 std::string(), &encoded_xml));
+  EXPECT_TRUE(form_structure.EncodeUploadRequest(
+      available_field_types, false, std::string(), true, &encoded_xml));
   EXPECT_EQ(
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"6402244543831589061\" autofillused=\"false\""
       " datapresent=\"\" actionsignature=\"15724779818122431245\">"
       "<field signature=\"1089846351\" name=\"first\" type=\"text\""
@@ -2349,11 +2416,12 @@
   available_field_types.insert(ADDRESS_HOME_LINE1);
   available_field_types.insert(ADDRESS_HOME_CITY);
 
-  EXPECT_TRUE(form_structure.EncodeUploadRequest(available_field_types, false,
-                                                 std::string(), &encoded_xml));
+  EXPECT_TRUE(form_structure.EncodeUploadRequest(
+      available_field_types, false, std::string(), true, &encoded_xml));
   EXPECT_EQ(
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"6402244543831589061\" autofillused=\"false\""
       " datapresent=\"1540000240\""
       " actionsignature=\"15724779818122431245\">"
@@ -2407,11 +2475,12 @@
   available_field_types.insert(ADDRESS_HOME_COUNTRY);
   available_field_types.insert(COMPANY_NAME);
 
-  EXPECT_TRUE(form_structure.EncodeUploadRequest(available_field_types, false,
-                                                 std::string(), &encoded_xml));
+  EXPECT_TRUE(form_structure.EncodeUploadRequest(
+      available_field_types, false, std::string(), true, &encoded_xml));
   EXPECT_EQ(
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"6402244543831589061\" autofillused=\"false\""
       " datapresent=\"1f7e000378000008\""
       " actionsignature=\"15724779818122431245\">"
@@ -2443,11 +2512,12 @@
   available_field_types.insert(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR);
   available_field_types.insert(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR);
 
-  EXPECT_TRUE(form_structure.EncodeUploadRequest(available_field_types, false,
-                                                 std::string(), &encoded_xml));
+  EXPECT_TRUE(form_structure.EncodeUploadRequest(
+      available_field_types, false, std::string(), true, &encoded_xml));
   EXPECT_EQ(
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"6402244543831589061\" autofillused=\"false\""
       " datapresent=\"0000000000001fc0\""
       " actionsignature=\"15724779818122431245\">"
@@ -2515,11 +2585,12 @@
   available_field_types.insert(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR);
   available_field_types.insert(COMPANY_NAME);
 
-  EXPECT_TRUE(form_structure.EncodeUploadRequest(available_field_types, false,
-                                                 std::string(), &encoded_xml));
+  EXPECT_TRUE(form_structure.EncodeUploadRequest(
+      available_field_types, false, std::string(), true, &encoded_xml));
   EXPECT_EQ(
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"6402244543831589061\" autofillused=\"false\""
       " datapresent=\"1f7e000378001fc8\""
       " actionsignature=\"15724779818122431245\">"
@@ -2594,11 +2665,12 @@
   std::string encoded_xml;
 
   // Now we matched both fields singularly.
-  EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, false,
-                                                  std::string(), &encoded_xml));
+  EXPECT_TRUE(form_structure->EncodeUploadRequest(
+      available_field_types, false, std::string(), true, &encoded_xml));
   EXPECT_EQ(
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"18062476096658145866\" autofillused=\"false\""
       " datapresent=\"1440000360000008\""
       " actionsignature=\"15724779818122431245\">"
@@ -2614,11 +2686,12 @@
   // Match third field as both first and last.
   possible_field_types[2].insert(NAME_FIRST);
   form_structure->field(2)->set_possible_types(possible_field_types[2]);
-  EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, false,
-                                                  std::string(), &encoded_xml));
+  EXPECT_TRUE(form_structure->EncodeUploadRequest(
+      available_field_types, false, std::string(), true, &encoded_xml));
   EXPECT_EQ(
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"18062476096658145866\" autofillused=\"false\""
       " datapresent=\"1440000360000008\""
       " actionsignature=\"15724779818122431245\">"
@@ -2636,11 +2709,12 @@
   possible_field_types[3].insert(ADDRESS_HOME_LINE2);
   form_structure->field(form_structure->field_count() - 1)->set_possible_types(
       possible_field_types[form_structure->field_count() - 1]);
-  EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, false,
-                                                  std::string(), &encoded_xml));
+  EXPECT_TRUE(form_structure->EncodeUploadRequest(
+      available_field_types, false, std::string(), true, &encoded_xml));
   EXPECT_EQ(
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"18062476096658145866\" autofillused=\"false\""
       " datapresent=\"1440000360000008\""
       " actionsignature=\"15724779818122431245\">"
@@ -2662,11 +2736,12 @@
   possible_field_types[3].insert(COMPANY_NAME);
   form_structure->field(form_structure->field_count() - 1)->set_possible_types(
       possible_field_types[form_structure->field_count() - 1]);
-  EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, false,
-                                                  std::string(), &encoded_xml));
+  EXPECT_TRUE(form_structure->EncodeUploadRequest(
+      available_field_types, false, std::string(), true, &encoded_xml));
   EXPECT_EQ(
       "<?xml version=\"1.0\"?>\n"
-      "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
+      "<autofillupload submission=\"true\""
+      " clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"18062476096658145866\" autofillused=\"false\""
       " datapresent=\"1440000360000008\""
       " actionsignature=\"15724779818122431245\">"
diff --git a/components/autofill/core/browser/name_field.cc b/components/autofill/core/browser/name_field.cc
index 8532de1..e1e09346 100644
--- a/components/autofill/core/browser/name_field.cc
+++ b/components/autofill/core/browser/name_field.cc
@@ -6,13 +6,10 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/autofill_regex_constants.h"
 #include "components/autofill/core/browser/autofill_scanner.h"
 #include "components/autofill/core/browser/autofill_type.h"
 
-using base::UTF8ToUTF16;
-
 namespace autofill {
 namespace {
 
@@ -80,7 +77,7 @@
 scoped_ptr<FullNameField> FullNameField::Parse(AutofillScanner* scanner) {
   // Exclude e.g. "username" or "nickname" fields.
   scanner->SaveCursor();
-  bool should_ignore = ParseField(scanner, UTF8ToUTF16(kNameIgnoredRe), NULL);
+  bool should_ignore = ParseField(scanner, kNameIgnoredRe, NULL);
   scanner->Rewind();
   if (should_ignore)
     return NULL;
@@ -89,7 +86,7 @@
   // for example, Travelocity_Edit travel profile.html contains a field
   // "Travel Profile Name".
   AutofillField* field = NULL;
-  if (ParseField(scanner, UTF8ToUTF16(kNameRe), &field))
+  if (ParseField(scanner, kNameRe, &field))
     return make_scoped_ptr(new FullNameField(field));
 
   return NULL;
@@ -110,7 +107,7 @@
   scanner->SaveCursor();
 
   AutofillField* next = NULL;
-  if (ParseField(scanner, UTF8ToUTF16(kNameSpecificRe), &v->first_name_) &&
+  if (ParseField(scanner, kNameSpecificRe, &v->first_name_) &&
       ParseEmptyLabel(scanner, &next)) {
     if (ParseEmptyLabel(scanner, &v->last_name_)) {
       // There are three name fields; assume that the middle one is a
@@ -147,13 +144,12 @@
   // Allow name fields to appear in any order.
   while (!scanner->IsEnd()) {
     // Skip over any unrelated fields, e.g. "username" or "nickname".
-    if (ParseFieldSpecifics(scanner, UTF8ToUTF16(kNameIgnoredRe),
+    if (ParseFieldSpecifics(scanner, kNameIgnoredRe,
                             MATCH_DEFAULT | MATCH_SELECT, NULL)) {
           continue;
     }
 
-    if (!v->first_name_ &&
-        ParseField(scanner, UTF8ToUTF16(kFirstNameRe), &v->first_name_)) {
+    if (!v->first_name_ && ParseField(scanner, kFirstNameRe, &v->first_name_)) {
       continue;
     }
 
@@ -163,18 +159,17 @@
     // "txtmiddlename"); such a field probably actually represents a
     // middle initial.
     if (!v->middle_name_ &&
-        ParseField(scanner, UTF8ToUTF16(kMiddleInitialRe), &v->middle_name_)) {
+        ParseField(scanner, kMiddleInitialRe, &v->middle_name_)) {
       v->middle_initial_ = true;
       continue;
     }
 
     if (!v->middle_name_ &&
-        ParseField(scanner, UTF8ToUTF16(kMiddleNameRe), &v->middle_name_)) {
+        ParseField(scanner, kMiddleNameRe, &v->middle_name_)) {
       continue;
     }
 
-    if (!v->last_name_ &&
-        ParseField(scanner, UTF8ToUTF16(kLastNameRe), &v->last_name_)) {
+    if (!v->last_name_ && ParseField(scanner, kLastNameRe, &v->last_name_)) {
       continue;
     }
 
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 0663afb..1b51952 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -455,7 +455,7 @@
   }
 
   // Don't import if we already have this info.
-  // Don't present an infobar if we have already saved this card number.
+  // Don't present a prompt if we have already saved this card number.
   bool merged_credit_card = false;
   if (local_imported_credit_card) {
     for (CreditCard* card : local_credit_cards_) {
@@ -1071,6 +1071,15 @@
       // verified profile, just drop it.
       matching_profile_found = true;
       guid = existing_profile->guid();
+
+      // We set the modification date so that immediate requests for profiles
+      // will properly reflect the fact that this profile has been modified
+      // recently. After writing to the database and refreshing the local copies
+      // the profile will have a very slightly newer time reflecting what's
+      // actually stored in the database.
+      existing_profile->set_modification_date(base::Time::Now());
+
+      existing_profile->RecordAndLogUse();
     }
     merged_profiles->push_back(*existing_profile);
   }
@@ -1078,6 +1087,9 @@
   // If the new profile was not merged with an existing one, add it to the list.
   if (!matching_profile_found) {
     merged_profiles->push_back(new_profile);
+    // Similar to updating merged profiles above, set the modification date on
+    // new profiles.
+    merged_profiles->back().set_modification_date(base::Time::Now());
     AutofillMetrics::LogProfileActionOnFormSubmitted(
         AutofillMetrics::NEW_PROFILE_CREATED);
   }
@@ -1257,16 +1269,18 @@
   if (is_off_the_record_)
     return std::string();
 
-  // ...or server profile.
-  for (AutofillProfile* profile : server_profiles_) {
-    if (imported_profile.IsSubsetOf(*profile, app_locale_))
+  // Don't save a web profile if the data in the profile is a subset of a
+  // server profile, but do record the fact that it was used.
+  for (const AutofillProfile* profile : server_profiles_) {
+    if (imported_profile.IsSubsetOf(*profile, app_locale_)) {
+      RecordUseOf(*profile);
       return profile->guid();
+    }
   }
 
   std::vector<AutofillProfile> profiles;
-  std::string guid =
-      MergeProfile(imported_profile, web_profiles_.get(), app_locale_,
-                   &profiles);
+  std::string guid = MergeProfile(imported_profile, web_profiles_.get(),
+                                  app_locale_, &profiles);
   SetProfiles(&profiles);
   return guid;
 }
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h
index 8d003bc..713491cc 100644
--- a/components/autofill/core/browser/personal_data_manager.h
+++ b/components/autofill/core/browser/personal_data_manager.h
@@ -106,7 +106,7 @@
   virtual std::string SaveImportedProfile(
       const AutofillProfile& imported_profile);
 
-  // Saves a credit card value detected in |ImportedFormData|. Returns the guid
+  // Saves |imported_credit_card| to the WebDB if it exists. Returns the guid of
   // of the new or updated card, or the empty string if no card was saved.
   virtual std::string SaveImportedCreditCard(
       const CreditCard& imported_credit_card);
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index 1f12a8e1..4febae9a 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -315,8 +315,25 @@
   base::MessageLoop::current()->Run();
 
   // Verify the non-addition.
-  EXPECT_EQ(1U, personal_data_->GetProfiles().size());
   EXPECT_EQ(0U, personal_data_->web_profiles().size());
+  ASSERT_EQ(1U, personal_data_->GetProfiles().size());
+
+  // Verify that the server profile's use date was updated.
+  const AutofillProfile* server_profile = personal_data_->GetProfiles()[0];
+  EXPECT_GT(base::TimeDelta::FromMilliseconds(500),
+            base::Time::Now() - server_profile->use_date());
+}
+
+// Tests that SaveImportedProfile sets the modification date on new profiles.
+TEST_F(PersonalDataManagerTest, SaveImportedProfileSetModificationDate) {
+  AutofillProfile profile(test::GetFullProfile());
+  EXPECT_EQ(base::Time(), profile.modification_date());
+
+  personal_data_->SaveImportedProfile(profile);
+  const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
+  ASSERT_EQ(1U, profiles.size());
+  EXPECT_GT(base::TimeDelta::FromMilliseconds(500),
+            base::Time::Now() - profiles[0]->modification_date());
 }
 
 TEST_F(PersonalDataManagerTest, AddUpdateRemoveProfiles) {
@@ -3310,6 +3327,13 @@
         EXPECT_EQ(base::UTF8ToUTF16(changed_field.field_value),
                   saved_profiles.front()->GetRawInfo(changed_field.field_type));
       }
+      // Verify that the merged profile's modification and use dates were
+      // updated.
+      EXPECT_GT(
+          base::TimeDelta::FromMilliseconds(500),
+          base::Time::Now() - saved_profiles.front()->modification_date());
+      EXPECT_GT(base::TimeDelta::FromMilliseconds(500),
+                base::Time::Now() - saved_profiles.front()->use_date());
     }
 
     // Erase the profiles for the next test.
diff --git a/components/autofill/core/browser/phone_field.cc b/components/autofill/core/browser/phone_field.cc
index 77a8d9f0..74f93a4 100644
--- a/components/autofill/core/browser/phone_field.cc
+++ b/components/autofill/core/browser/phone_field.cc
@@ -8,7 +8,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/autofill_regex_constants.h"
 #include "components/autofill/core/browser/autofill_scanner.h"
@@ -276,10 +275,8 @@
 bool PhoneField::ParsePhoneField(AutofillScanner* scanner,
                                  const std::string& regex,
                                  AutofillField** field) {
-  return ParseFieldSpecifics(scanner,
-                             base::UTF8ToUTF16(regex),
-                             MATCH_DEFAULT | MATCH_TELEPHONE | MATCH_NUMBER,
-                             field);
+  return ParseFieldSpecifics(
+      scanner, regex, MATCH_DEFAULT | MATCH_TELEPHONE | MATCH_NUMBER, field);
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/validation.cc b/components/autofill/core/browser/validation.cc
index b4c95674..f2f1a88 100644
--- a/components/autofill/core/browser/validation.cc
+++ b/components/autofill/core/browser/validation.cc
@@ -127,9 +127,9 @@
 
 bool IsValidEmailAddress(const base::string16& text) {
   // E-Mail pattern as defined by the WhatWG. (4.10.7.1.5 E-Mail state)
-  const base::string16 kEmailPattern = base::ASCIIToUTF16(
+  const char kEmailPattern[] =
       "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@"
-      "[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$");
+      "[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$";
   return MatchesPattern(text, kEmailPattern);
 }
 
@@ -139,7 +139,7 @@
 }
 
 bool IsValidZip(const base::string16& text) {
-  const base::string16 kZipPattern = base::ASCIIToUTF16("^\\d{5}(-\\d{4})?$");
+  const char kZipPattern[] = "^\\d{5}(-\\d{4})?$";
   return MatchesPattern(text, kZipPattern);
 }
 
diff --git a/components/autofill/core/common/BUILD.gn b/components/autofill/core/common/BUILD.gn
index 05ef7bd..6678086 100644
--- a/components/autofill/core/common/BUILD.gn
+++ b/components/autofill/core/common/BUILD.gn
@@ -39,6 +39,7 @@
   deps = [
     "//base",
     "//base:i18n",
+    "//third_party/re2",
     "//ui/base",
     "//ui/gfx",
     "//url",
diff --git a/components/autofill/core/common/DEPS b/components/autofill/core/common/DEPS
new file mode 100644
index 0000000..0de07bb
--- /dev/null
+++ b/components/autofill/core/common/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+third_party/re2",
+]
diff --git a/components/autofill/core/common/autofill_regexes.cc b/components/autofill/core/common/autofill_regexes.cc
index cdea63c..7f914b931 100644
--- a/components/autofill/core/common/autofill_regexes.cc
+++ b/components/autofill/core/common/autofill_regexes.cc
@@ -8,8 +8,8 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/singleton.h"
-#include "base/strings/string16.h"
-#include "third_party/icu/source/i18n/unicode/regex.h"
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/re2/re2/re2.h"
 
 namespace {
 
@@ -19,7 +19,7 @@
   static AutofillRegexes* GetInstance();
 
   // Returns the compiled regex matcher corresponding to |pattern|.
-  icu::RegexMatcher* GetMatcher(const base::string16& pattern);
+  re2::RE2* GetMatcher(const std::string& pattern);
 
  private:
   AutofillRegexes();
@@ -27,8 +27,7 @@
   friend struct base::DefaultSingletonTraits<AutofillRegexes>;
 
   // Maps patterns to their corresponding regex matchers.
-  base::ScopedPtrHashMap<base::string16, scoped_ptr<icu::RegexMatcher>>
-      matchers_;
+  base::ScopedPtrHashMap<std::string, scoped_ptr<re2::RE2>> matchers_;
 
   DISALLOW_COPY_AND_ASSIGN(AutofillRegexes);
 };
@@ -44,16 +43,13 @@
 AutofillRegexes::~AutofillRegexes() {
 }
 
-icu::RegexMatcher* AutofillRegexes::GetMatcher(const base::string16& pattern) {
+re2::RE2* AutofillRegexes::GetMatcher(const std::string& pattern) {
   auto it = matchers_.find(pattern);
   if (it == matchers_.end()) {
-    const icu::UnicodeString icu_pattern(pattern.data(), pattern.length());
-
-    UErrorCode status = U_ZERO_ERROR;
-    scoped_ptr<icu::RegexMatcher> matcher(
-        new icu::RegexMatcher(icu_pattern, UREGEX_CASE_INSENSITIVE, status));
-    DCHECK(U_SUCCESS(status));
-
+    re2::RE2::Options options;
+    options.set_case_sensitive(false);
+    scoped_ptr<re2::RE2> matcher(new re2::RE2(pattern, options));
+    DCHECK(matcher->ok());
     auto result = matchers_.add(pattern, matcher.Pass());
     DCHECK(result.second);
     it = result.first;
@@ -65,17 +61,12 @@
 
 namespace autofill {
 
-bool MatchesPattern(const base::string16& input,
-                    const base::string16& pattern) {
-  icu::RegexMatcher* matcher =
-      AutofillRegexes::GetInstance()->GetMatcher(pattern);
-  icu::UnicodeString icu_input(input.data(), input.length());
-  matcher->reset(icu_input);
-
-  UErrorCode status = U_ZERO_ERROR;
-  UBool match = matcher->find(0, status);
-  DCHECK(U_SUCCESS(status));
-  return match == TRUE;
+bool MatchesPattern(const base::string16& input, const std::string& pattern) {
+  // TODO(isherman): Run performance tests to determine whether caching regex
+  // matchers is still useful now that we've switched from ICU to RE2.
+  // http://crbug.com/470065
+  re2::RE2* matcher = AutofillRegexes::GetInstance()->GetMatcher(pattern);
+  return re2::RE2::PartialMatch(base::UTF16ToUTF8(input), *matcher);
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/common/autofill_regexes.h b/components/autofill/core/common/autofill_regexes.h
index 1bf1aa7..e5024ce9f 100644
--- a/components/autofill/core/common/autofill_regexes.h
+++ b/components/autofill/core/common/autofill_regexes.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEXES_H_
 #define COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEXES_H_
 
+#include <string>
+
 #include "base/strings/string16.h"
 
 // Parsing utilities.
@@ -13,7 +15,7 @@
 // Case-insensitive regular expression matching.
 // Returns true if |pattern| is found in |input|.
 bool MatchesPattern(const base::string16& input,
-                    const base::string16& pattern);
+                    const std::string& pattern);
 
 }  // namespace autofill
 
diff --git a/components/autofill/core/common/autofill_regexes_unittest.cc b/components/autofill/core/common/autofill_regexes_unittest.cc
index 05895c7..a4a3ebe 100644
--- a/components/autofill/core/common/autofill_regexes_unittest.cc
+++ b/components/autofill/core/common/autofill_regexes_unittest.cc
@@ -38,8 +38,8 @@
     const TestCase& test_case = kPositiveCases[i];
     SCOPED_TRACE(test_case.input);
     SCOPED_TRACE(test_case.pattern);
-    EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input),
-                               ASCIIToUTF16(test_case.pattern)));
+    EXPECT_TRUE(
+        MatchesPattern(ASCIIToUTF16(test_case.input), test_case.pattern));
   }
 
   const TestCase kNegativeCases[] = {
@@ -58,8 +58,8 @@
     const TestCase& test_case = kNegativeCases[i];
     SCOPED_TRACE(test_case.input);
     SCOPED_TRACE(test_case.pattern);
-    EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input),
-                                ASCIIToUTF16(test_case.pattern)));
+    EXPECT_FALSE(
+        MatchesPattern(ASCIIToUTF16(test_case.input), test_case.pattern));
   }
 }
 
diff --git a/components/browser_sync/browser/BUILD.gn b/components/browser_sync/browser/BUILD.gn
index af99698..c76c80aa 100644
--- a/components/browser_sync/browser/BUILD.gn
+++ b/components/browser_sync/browser/BUILD.gn
@@ -42,3 +42,37 @@
     "//ui/base",
   ]
 }
+
+source_set("unit_tests") {
+  testonly = true
+
+  sources = [
+    "profile_sync_service_unittest.cc",
+  ]
+
+  deps = [
+    ":browser",
+    "//base",
+    "//base/test:test_support",
+    "//components/browser_sync/common",
+    "//components/dom_distiller/core",
+    "//components/invalidation/impl",
+    "//components/invalidation/public",
+    "//components/signin/core/browser",
+    "//components/signin/core/browser:test_support",
+    "//components/strings",
+    "//components/sync_driver",
+    "//components/sync_driver:test_support",
+    "//components/sync_sessions",
+    "//components/sync_sessions:test_support",
+    "//components/syncable_prefs",
+    "//components/syncable_prefs:test_support",
+    "//components/version_info",
+    "//components/version_info:generate_version_info",
+    "//google_apis",
+    "//net",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//ui/base",
+  ]
+}
diff --git a/components/browser_sync/browser/profile_sync_service.cc b/components/browser_sync/browser/profile_sync_service.cc
index ba28615..be73bba 100644
--- a/components/browser_sync/browser/profile_sync_service.cc
+++ b/components/browser_sync/browser/profile_sync_service.cc
@@ -111,31 +111,31 @@
     "Sync.UnrecoverableErrors";
 
 const net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy = {
-  // Number of initial errors (in sequence) to ignore before applying
-  // exponential back-off rules.
-  0,
+    // Number of initial errors (in sequence) to ignore before applying
+    // exponential back-off rules.
+    0,
 
-  // Initial delay for exponential back-off in ms.
-  2000,
+    // Initial delay for exponential back-off in ms.
+    2000,
 
-  // Factor by which the waiting time will be multiplied.
-  2,
+    // Factor by which the waiting time will be multiplied.
+    2,
 
-  // Fuzzing percentage. ex: 10% will spread requests randomly
-  // between 90%-100% of the calculated time.
-  0.2, // 20%
+    // Fuzzing percentage. ex: 10% will spread requests randomly
+    // between 90%-100% of the calculated time.
+    0.2,  // 20%
 
-  // Maximum amount of time we are willing to delay our request in ms.
-  // TODO(pavely): crbug.com/246686 ProfileSyncService should retry
-  // RequestAccessToken on connection state change after backoff
-  1000 * 3600 * 4, // 4 hours.
+    // Maximum amount of time we are willing to delay our request in ms.
+    // TODO(pavely): crbug.com/246686 ProfileSyncService should retry
+    // RequestAccessToken on connection state change after backoff
+    1000 * 3600 * 4,  // 4 hours.
 
-  // Time to keep an entry from being discarded even when it
-  // has no significant state, -1 to never discard.
-  -1,
+    // Time to keep an entry from being discarded even when it
+    // has no significant state, -1 to never discard.
+    -1,
 
-  // Don't use initial delay unless the last request was an error.
-  false,
+    // Don't use initial delay unless the last request was an error.
+    false,
 };
 
 static const base::FilePath::CharType kSyncDataFolderName[] =
@@ -167,39 +167,46 @@
           error.action != syncer::RESET_LOCAL_SYNC_DATA);
 }
 
-ProfileSyncService::ProfileSyncService(
-    scoped_ptr<sync_driver::SyncClient> sync_client,
-    scoped_ptr<SigninManagerWrapper> signin_wrapper,
-    ProfileOAuth2TokenService* oauth2_token_service,
-    ProfileSyncServiceStartBehavior start_behavior,
-    const syncer::NetworkTimeUpdateCallback& network_time_update_callback,
-    base::FilePath base_directory,
-    scoped_refptr<net::URLRequestContextGetter> url_request_context,
-    std::string debug_identifier,
-    version_info::Channel channel,
-    scoped_refptr<base::SingleThreadTaskRunner> db_thread,
-    scoped_refptr<base::SingleThreadTaskRunner> file_thread,
-    base::SequencedWorkerPool* blocking_pool)
+ProfileSyncService::InitParams::InitParams() = default;
+ProfileSyncService::InitParams::~InitParams() = default;
+ProfileSyncService::InitParams::InitParams(InitParams&& other)  // NOLINT
+    : sync_client(std::move(other.sync_client)),
+      signin_wrapper(std::move(other.signin_wrapper)),
+      oauth2_token_service(other.oauth2_token_service),
+      start_behavior(other.start_behavior),
+      network_time_update_callback(
+          std::move(other.network_time_update_callback)),
+      base_directory(std::move(other.base_directory)),
+      url_request_context(std::move(other.url_request_context)),
+      debug_identifier(std::move(other.debug_identifier)),
+      channel(other.channel),
+      db_thread(std::move(other.db_thread)),
+      file_thread(std::move(other.file_thread)),
+      blocking_pool(other.blocking_pool) {}
+
+ProfileSyncService::ProfileSyncService(InitParams init_params)
     : OAuth2TokenService::Consumer("sync"),
       last_auth_error_(AuthError::AuthErrorNone()),
       passphrase_required_reason_(syncer::REASON_PASSPHRASE_NOT_REQUIRED),
-      sync_client_(sync_client.Pass()),
+      sync_client_(std::move(init_params.sync_client)),
       sync_prefs_(sync_client_->GetPrefService()),
       sync_service_url_(
-          GetSyncServiceURL(*base::CommandLine::ForCurrentProcess(), channel)),
-      network_time_update_callback_(network_time_update_callback),
-      base_directory_(base_directory),
-      url_request_context_(url_request_context),
-      debug_identifier_(debug_identifier),
-      channel_(channel),
-      db_thread_(db_thread),
-      file_thread_(file_thread),
-      blocking_pool_(blocking_pool),
+          GetSyncServiceURL(*base::CommandLine::ForCurrentProcess(),
+                            init_params.channel)),
+      network_time_update_callback_(
+          std::move(init_params.network_time_update_callback)),
+      base_directory_(init_params.base_directory),
+      url_request_context_(init_params.url_request_context),
+      debug_identifier_(std::move(init_params.debug_identifier)),
+      channel_(init_params.channel),
+      db_thread_(init_params.db_thread),
+      file_thread_(init_params.file_thread),
+      blocking_pool_(init_params.blocking_pool),
       is_first_time_sync_configure_(false),
       backend_initialized_(false),
       sync_disabled_by_admin_(false),
       is_auth_in_progress_(false),
-      signin_(signin_wrapper.Pass()),
+      signin_(std::move(init_params.signin_wrapper)),
       unrecoverable_error_reason_(ERROR_REASON_UNSET),
       expect_sync_configuration_aborted_(false),
       encrypted_types_(syncer::SyncEncryptionHandler::SensitiveTypes()),
@@ -207,12 +214,12 @@
       encrypt_everything_(false),
       encryption_pending_(false),
       configure_status_(DataTypeManager::UNKNOWN),
-      oauth2_token_service_(oauth2_token_service),
+      oauth2_token_service_(init_params.oauth2_token_service),
       request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy),
       connection_status_(syncer::CONNECTION_NOT_ATTEMPTED),
       last_get_token_error_(GoogleServiceAuthError::AuthErrorNone()),
       network_resources_(new syncer::HttpBridgeNetworkResources),
-      start_behavior_(start_behavior),
+      start_behavior_(init_params.start_behavior),
       backend_mode_(IDLE),
       need_backup_(false),
       backup_finished_(false),
@@ -2011,7 +2018,7 @@
   }
 
   SyncBackendHost::Status detailed_status = backend_->GetDetailedStatus();
-  ModelTypeSet &throttled_types(detailed_status.throttled_types);
+  ModelTypeSet& throttled_types(detailed_status.throttled_types);
   ModelTypeSet registered = GetRegisteredDataTypes();
   scoped_ptr<base::DictionaryValue> type_status_header(
       new base::DictionaryValue());
diff --git a/components/browser_sync/browser/profile_sync_service.h b/components/browser_sync/browser/profile_sync_service.h
index e2203f24..3d4883a 100644
--- a/components/browser_sync/browser/profile_sync_service.h
+++ b/components/browser_sync/browser/profile_sync_service.h
@@ -230,19 +230,35 @@
     ROLLBACK    // Backend for rollback.
   };
 
-  ProfileSyncService(
-      scoped_ptr<sync_driver::SyncClient> sync_client,
-      scoped_ptr<SigninManagerWrapper> signin_wrapper,
-      ProfileOAuth2TokenService* oauth2_token_service,
-      browser_sync::ProfileSyncServiceStartBehavior start_behavior,
-      const syncer::NetworkTimeUpdateCallback& network_time_update_callback,
-      base::FilePath base_directory,
-      scoped_refptr<net::URLRequestContextGetter> url_request_context,
-      std::string debug_identifier,
-      version_info::Channel channel,
-      scoped_refptr<base::SingleThreadTaskRunner> db_thread,
-      scoped_refptr<base::SingleThreadTaskRunner> file_thread,
-      base::SequencedWorkerPool* blocking_pool);
+  // Bundles the arguments for ProfileSyncService construction. This is a
+  // movable struct. Because of the non-POD data members, it needs out-of-line
+  // constructors, so in particular the move constructor needs to be
+  // explicitly defined.
+  struct InitParams {
+    InitParams();
+    ~InitParams();
+    InitParams(InitParams&& other);  // NOLINT
+
+    scoped_ptr<sync_driver::SyncClient> sync_client;
+    scoped_ptr<SigninManagerWrapper> signin_wrapper;
+    ProfileOAuth2TokenService* oauth2_token_service = nullptr;
+    browser_sync::ProfileSyncServiceStartBehavior start_behavior =
+        browser_sync::MANUAL_START;
+    syncer::NetworkTimeUpdateCallback network_time_update_callback;
+    base::FilePath base_directory;
+    scoped_refptr<net::URLRequestContextGetter> url_request_context;
+    std::string debug_identifier;
+    version_info::Channel channel = version_info::Channel::UNKNOWN;
+    scoped_refptr<base::SingleThreadTaskRunner> db_thread;
+    scoped_refptr<base::SingleThreadTaskRunner> file_thread;
+    base::SequencedWorkerPool* blocking_pool = nullptr;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(InitParams);
+  };
+
+  explicit ProfileSyncService(InitParams init_params);
+
   ~ProfileSyncService() override;
 
   // Initializes the object. This must be called at most once, and
diff --git a/chrome/browser/sync/profile_sync_service_unittest.cc b/components/browser_sync/browser/profile_sync_service_unittest.cc
similarity index 83%
rename from chrome/browser/sync/profile_sync_service_unittest.cc
rename to components/browser_sync/browser/profile_sync_service_unittest.cc
index 5b69f26b..5611f2d 100644
--- a/chrome/browser/sync/profile_sync_service_unittest.cc
+++ b/components/browser_sync/browser/profile_sync_service_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/command_line.h"
@@ -12,33 +14,22 @@
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/sequenced_worker_pool_owner.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/values.h"
-#include "chrome/browser/invalidation/fake_invalidation_service.h"
-#include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
-#include "chrome/browser/signin/account_tracker_service_factory.h"
-#include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
-#include "chrome/browser/sync/chrome_sync_client.h"
-#include "chrome/browser/sync/profile_sync_test_util.h"
-#include "chrome/common/channel_info.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/test/base/testing_browser_process.h"
-#include "chrome/test/base/testing_profile.h"
-#include "chrome/test/base/testing_profile_manager.h"
 #include "components/browser_sync/browser/profile_sync_service.h"
 #include "components/browser_sync/common/browser_sync_switches.h"
 #include "components/invalidation/impl/profile_invalidation_provider.h"
 #include "components/invalidation/public/invalidation_service.h"
 #include "components/signin/core/browser/account_tracker_service.h"
 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
-#include "components/signin/core/browser/signin_manager.h"
+#include "components/signin/core/browser/fake_signin_manager.h"
+#include "components/signin/core/browser/test_signin_client.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/sync_driver/data_type_manager.h"
 #include "components/sync_driver/data_type_manager_observer.h"
 #include "components/sync_driver/fake_data_type_controller.h"
+#include "components/sync_driver/fake_sync_client.h"
 #include "components/sync_driver/glue/sync_backend_host_mock.h"
 #include "components/sync_driver/pref_names.h"
 #include "components/sync_driver/signin_manager_wrapper.h"
@@ -48,18 +39,16 @@
 #include "components/sync_driver/sync_prefs.h"
 #include "components/sync_driver/sync_service_observer.h"
 #include "components/sync_driver/sync_util.h"
+#include "components/sync_sessions/fake_sync_sessions_client.h"
 #include "components/syncable_prefs/testing_pref_service_syncable.h"
+#include "components/version_info/version_info.h"
 #include "components/version_info/version_info_values.h"
-#include "content/public/test/test_browser_thread_bundle.h"
 #include "google_apis/gaia/gaia_constants.h"
+#include "net/url_request/url_request_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
 
-namespace content {
-class BrowserContext;
-}
-
 namespace browser_sync {
 
 namespace {
@@ -67,6 +56,10 @@
 const char kGaiaId[] = "12345";
 const char kEmail[] = "test_user@gmail.com";
 
+void EmptyNetworkTimeUpdate(const base::Time&,
+                            const base::TimeDelta&,
+                            const base::TimeDelta&) {}
+
 class FakeDataTypeManager : public sync_driver::DataTypeManager {
  public:
   typedef base::Callback<void(syncer::ConfigureReason)> ConfigureCalled;
@@ -103,19 +96,26 @@
 using testing::StrictMock;
 using testing::_;
 
-class TestChromeSyncClient : public ChromeSyncClient {
+class TestSyncClient : public sync_driver::FakeSyncClient {
  public:
-  TestChromeSyncClient(
+  TestSyncClient(
       scoped_ptr<sync_driver::SyncApiComponentFactory> component_factory,
-      Profile* profile,
+      PrefService* pref_service,
       sync_driver::ClearBrowsingDataCallback callback)
-      : ChromeSyncClient(profile),
+      : sync_driver::FakeSyncClient(),
         callback_(callback),
+        pref_service_(pref_service),
         component_factory_(component_factory.Pass()) {}
-  ~TestChromeSyncClient() override {}
+  ~TestSyncClient() override {}
 
  private:
   // SyncClient:
+  PrefService* GetPrefService() override { return pref_service_; }
+
+  sync_sessions::SyncSessionsClient* GetSyncSessionsClient() override {
+    return &sync_sessions_client_;
+  }
+
   sync_driver::ClearBrowsingDataCallback GetClearBrowsingDataCallback()
       override {
     return callback_;
@@ -125,6 +125,8 @@
   }
 
   sync_driver::ClearBrowsingDataCallback callback_;
+  sync_sessions::FakeSyncSessionsClient sync_sessions_client_;
+  PrefService* pref_service_;
   scoped_ptr<sync_driver::SyncApiComponentFactory> component_factory_;
 };
 
@@ -244,13 +246,6 @@
       &OnClearServerDataCalled, base::Unretained(captured_callback)));
 }
 
-scoped_ptr<KeyedService> BuildFakeProfileInvalidationProvider(
-    content::BrowserContext* context) {
-  return make_scoped_ptr(new invalidation::ProfileInvalidationProvider(
-      scoped_ptr<invalidation::InvalidationService>(
-          new invalidation::FakeInvalidationService)));
-}
-
 // A test harness that uses a real ProfileSyncService and in most cases a
 // MockSyncBackendHost.
 //
@@ -259,9 +254,7 @@
 class ProfileSyncServiceTest : public ::testing::Test {
  protected:
   ProfileSyncServiceTest()
-      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
-        profile_manager_(TestingBrowserProcess::GetGlobal()),
-        profile_(NULL),
+      : worker_pool_owner_(2, "sync test worker pool"),
         components_factory_(NULL) {}
   ~ProfileSyncServiceTest() override {}
 
@@ -269,20 +262,34 @@
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
         switches::kSyncDeferredStartupTimeoutSeconds, "0");
 
-    CHECK(profile_manager_.SetUp());
+    // TODO(crbug.com/544972): Pull all this setup code out into helper classes
+    // and/or utils as needed to be reused by other //components-level sync
+    // tests.
+    sync_driver::SyncPrefs::RegisterProfilePrefs(pref_service_.registry());
+    AccountTrackerService::RegisterPrefs(pref_service_.registry());
+    SigninManagerBase::RegisterProfilePrefs(pref_service_.registry());
+    SigninManagerBase::RegisterPrefs(pref_service_.registry());
 
-    TestingProfile::TestingFactories testing_factories;
-    testing_factories.push_back(
-        std::make_pair(ProfileOAuth2TokenServiceFactory::GetInstance(),
-                       BuildAutoIssuingFakeProfileOAuth2TokenService));
-    testing_factories.push_back(std::make_pair(
-        invalidation::ProfileInvalidationProviderFactory::GetInstance(),
-        BuildFakeProfileInvalidationProvider));
+    url_request_context_ = new net::TestURLRequestContextGetter(
+        base::ThreadTaskRunnerHandle::Get());
 
-    profile_ = profile_manager_.CreateTestingProfile(
-        "sync-service-test", scoped_ptr<syncable_prefs::PrefServiceSyncable>(),
-        base::UTF8ToUTF16("sync-service-test"), 0, std::string(),
-        testing_factories);
+    auth_service_.reset(new FakeProfileOAuth2TokenService());
+    auth_service_->set_auto_post_fetch_response_on_message_loop(true);
+
+    signin_client_.reset(new TestSigninClient(prefs()));
+
+    account_tracker_.reset(new AccountTrackerService());
+    account_tracker_->Initialize(signin_client_.get());
+
+#if defined(OS_CHROMEOS)
+    signin_manager_.reset(new FakeSigninManagerBase(signin_client_.get(),
+                                                    account_tracker_.get()));
+#else
+    signin_manager_.reset(
+        new FakeSigninManager(signin_client_.get(), auth_service_.get(),
+                              account_tracker_.get(), nullptr));
+#endif
+    signin_manager_->Initialize(prefs());
   }
 
   void TearDown() override {
@@ -294,46 +301,46 @@
   }
 
   void IssueTestTokens() {
-    std::string account_id =
-        AccountTrackerServiceFactory::GetForProfile(profile_)
-            ->SeedAccountInfo(kGaiaId, kEmail);
-    ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)
-        ->UpdateCredentials(account_id, "oauth2_login_token");
+    std::string account_id = account_tracker_->SeedAccountInfo(kGaiaId, kEmail);
+    auth_service_->UpdateCredentials(account_id, "oauth2_login_token");
   }
 
   void CreateService(ProfileSyncServiceStartBehavior behavior) {
-    SigninManagerBase* signin =
-        SigninManagerFactory::GetForProfile(profile_);
-    signin->SetAuthenticatedAccountInfo(kGaiaId, kEmail);
-    ProfileOAuth2TokenService* oauth2_token_service =
-        ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
+    signin_manager_->SetAuthenticatedAccountInfo(kGaiaId, kEmail);
     scoped_ptr<SyncApiComponentFactoryMock> components_factory(
         new SyncApiComponentFactoryMock());
     components_factory_ = components_factory.get();
-    scoped_ptr<ChromeSyncClient> sync_client(new TestChromeSyncClient(
-        components_factory.Pass(), profile_,
+    scoped_ptr<sync_driver::SyncClient> sync_client(new TestSyncClient(
+        components_factory.Pass(), &pref_service_,
         base::Bind(&ProfileSyncServiceTest::ClearBrowsingDataCallback,
                    base::Unretained(this))));
-    service_.reset(new ProfileSyncService(
-        sync_client.Pass(),
-        make_scoped_ptr(new SigninManagerWrapper(signin)), oauth2_token_service,
-        behavior, base::Bind(&EmptyNetworkTimeUpdate), profile_->GetPath(),
-        profile_->GetRequestContext(), profile_->GetDebugName(),
-        chrome::GetChannel(),
-        content::BrowserThread::GetMessageLoopProxyForThread(
-            content::BrowserThread::DB),
-        content::BrowserThread::GetMessageLoopProxyForThread(
-            content::BrowserThread::FILE),
-        content::BrowserThread::GetBlockingPool()));
+
+    ProfileSyncService::InitParams init_params;
+    init_params.signin_wrapper =
+        make_scoped_ptr(new SigninManagerWrapper(signin_manager_.get()));
+    init_params.oauth2_token_service = auth_service_.get();
+    init_params.start_behavior = behavior;
+    init_params.sync_client = std::move(sync_client);
+    init_params.network_time_update_callback =
+        base::Bind(&EmptyNetworkTimeUpdate);
+    init_params.base_directory = base::FilePath(FILE_PATH_LITERAL("dummyPath"));
+    init_params.url_request_context = url_request_context_;
+    init_params.debug_identifier = "dummyDebugName";
+    init_params.channel = version_info::Channel::UNKNOWN;
+    init_params.db_thread = base::ThreadTaskRunnerHandle::Get();
+    init_params.file_thread = base::ThreadTaskRunnerHandle::Get();
+    init_params.blocking_pool = worker_pool_owner_.pool().get();
+
+    service_.reset(new ProfileSyncService(std::move(init_params)));
     service_->RegisterDataTypeController(
         new sync_driver::FakeDataTypeController(syncer::BOOKMARKS));
   }
 
-#if defined(OS_WIN) || defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+#if defined(OS_WIN) || defined(OS_MACOSX) || \
+    (defined(OS_LINUX) && !defined(OS_CHROMEOS))
   void CreateServiceWithoutSignIn() {
     CreateService(browser_sync::AUTO_START);
-    SigninManagerFactory::GetForProfile(profile())->SignOut(
-        signin_metrics::SIGNOUT_TEST);
+    signin_manager_->SignOut(signin_metrics::SIGNOUT_TEST);
   }
 #endif
 
@@ -346,7 +353,8 @@
   void InitializeForNthSync() {
     // Set first sync time before initialize to disable backup and simulate
     // a complete sync setup.
-    sync_driver::SyncPrefs sync_prefs(profile()->GetPrefs());
+    sync_driver::SyncPrefs sync_prefs(
+        service_->GetSyncClient()->GetPrefService());
     sync_prefs.SetFirstSyncTime(base::Time::Now());
     sync_prefs.SetSyncSetupCompleted();
     sync_prefs.SetKeepEverythingSynced(true);
@@ -423,14 +431,24 @@
         .WillOnce(ReturnNewSyncBackendHostNoReturn());
   }
 
-  TestingProfile* profile() {
-    return profile_;
+  AccountTrackerService* account_tracker() { return account_tracker_.get(); }
+
+#if defined(OS_CHROMEOS)
+  SigninManagerBase* signin_manager() {
+#else
+  SigninManager* signin_manager() {
+#endif
+    return signin_manager_.get();
   }
 
+  ProfileOAuth2TokenService* auth_service() { return auth_service_.get(); }
+
   ProfileSyncService* service() {
     return service_.get();
   }
 
+  syncable_prefs::TestingPrefServiceSyncable* prefs() { return &pref_service_; }
+
   SyncApiComponentFactoryMock* components_factory() {
     return components_factory_;
   }
@@ -451,9 +469,18 @@
   base::Time clear_browsing_date_start_;
 
  private:
-  content::TestBrowserThreadBundle thread_bundle_;
-  TestingProfileManager profile_manager_;
-  TestingProfile* profile_;
+  base::MessageLoop message_loop_;
+  base::SequencedWorkerPoolOwner worker_pool_owner_;
+  scoped_refptr<net::URLRequestContextGetter> url_request_context_;
+  syncable_prefs::TestingPrefServiceSyncable pref_service_;
+  scoped_ptr<TestSigninClient> signin_client_;
+  scoped_ptr<AccountTrackerService> account_tracker_;
+#if defined(OS_CHROMEOS)
+  scoped_ptr<SigninManagerBase> signin_manager_;
+#else
+  scoped_ptr<SigninManager> signin_manager_;
+#endif
+  scoped_ptr<FakeProfileOAuth2TokenService> auth_service_;
   scoped_ptr<ProfileSyncService> service_;
 
   // The current component factory used by sync. May be null if the server
@@ -472,8 +499,8 @@
 
 // Verify a successful initialization.
 TEST_F(ProfileSyncServiceTest, SuccessfulInitialization) {
-  profile()->GetTestingPrefService()->SetManagedPref(
-      sync_driver::prefs::kSyncManaged, new base::FundamentalValue(false));
+  prefs()->SetManagedPref(sync_driver::prefs::kSyncManaged,
+                          new base::FundamentalValue(false));
   IssueTestTokens();
   CreateService(browser_sync::AUTO_START);
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
@@ -503,8 +530,8 @@
 
 // Verify that disable by enterprise policy works.
 TEST_F(ProfileSyncServiceTest, DisabledByPolicyBeforeInit) {
-  profile()->GetTestingPrefService()->SetManagedPref(
-      sync_driver::prefs::kSyncManaged, new base::FundamentalValue(true));
+  prefs()->SetManagedPref(sync_driver::prefs::kSyncManaged,
+                          new base::FundamentalValue(true));
   IssueTestTokens();
   CreateService(browser_sync::AUTO_START);
   InitializeForNthSync();
@@ -524,8 +551,8 @@
   EXPECT_FALSE(service()->IsManaged());
   EXPECT_TRUE(service()->IsSyncActive());
 
-  profile()->GetTestingPrefService()->SetManagedPref(
-      sync_driver::prefs::kSyncManaged, new base::FundamentalValue(true));
+  prefs()->SetManagedPref(sync_driver::prefs::kSyncManaged,
+                          new base::FundamentalValue(true));
 
   EXPECT_TRUE(service()->IsManaged());
   EXPECT_FALSE(service()->IsSyncActive());
@@ -550,11 +577,11 @@
   IssueTestTokens();
 
   service()->RequestStop(ProfileSyncService::KEEP_DATA);
-  EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
-      sync_driver::prefs::kSyncSuppressStart));
+  EXPECT_TRUE(prefs()->GetBoolean(sync_driver::prefs::kSyncSuppressStart));
 
   // Because of suppression, this should fail.
-  sync_driver::SyncPrefs sync_prefs(profile()->GetPrefs());
+  sync_driver::SyncPrefs sync_prefs(
+      service()->GetSyncClient()->GetPrefService());
   sync_prefs.SetFirstSyncTime(base::Time::Now());
   service()->Initialize();
   EXPECT_FALSE(service()->IsSyncActive());
@@ -564,8 +591,7 @@
   ExpectSyncBackendHostCreation(1);
   service()->RequestStart();
   EXPECT_TRUE(service()->IsSyncActive());
-  EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
-      sync_driver::prefs::kSyncSuppressStart));
+  EXPECT_FALSE(prefs()->GetBoolean(sync_driver::prefs::kSyncSuppressStart));
 }
 
 // Test RequestStop() after we've initialized the backend.
@@ -577,23 +603,20 @@
   InitializeForNthSync();
 
   EXPECT_TRUE(service()->IsSyncActive());
-  EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
-      sync_driver::prefs::kSyncSuppressStart));
+  EXPECT_FALSE(prefs()->GetBoolean(sync_driver::prefs::kSyncSuppressStart));
 
   testing::Mock::VerifyAndClearExpectations(components_factory());
 
   service()->RequestStop(ProfileSyncService::KEEP_DATA);
   EXPECT_FALSE(service()->IsSyncActive());
-  EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
-      sync_driver::prefs::kSyncSuppressStart));
+  EXPECT_TRUE(prefs()->GetBoolean(sync_driver::prefs::kSyncSuppressStart));
 
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
   ExpectSyncBackendHostCreation(1);
 
   service()->RequestStart();
   EXPECT_TRUE(service()->IsSyncActive());
-  EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
-      sync_driver::prefs::kSyncSuppressStart));
+  EXPECT_FALSE(prefs()->GetBoolean(sync_driver::prefs::kSyncSuppressStart));
 }
 
 // Certain ProfileSyncService tests don't apply to Chrome OS, for example
@@ -607,11 +630,9 @@
   InitializeForNthSync();
 
   EXPECT_TRUE(service()->IsSyncActive());
-  EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
-      sync_driver::prefs::kSyncSuppressStart));
+  EXPECT_FALSE(prefs()->GetBoolean(sync_driver::prefs::kSyncSuppressStart));
 
-  SigninManagerFactory::GetForProfile(profile())->SignOut(
-      signin_metrics::SIGNOUT_TEST);
+  signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST);
   EXPECT_FALSE(service()->IsSyncActive());
 }
 #endif  // !defined(OS_CHROMEOS)
@@ -662,26 +683,21 @@
   EXPECT_TRUE(service()->IsSyncActive());
 
   std::string primary_account_id =
-      SigninManagerFactory::GetForProfile(profile())
-          ->GetAuthenticatedAccountId();
-  ProfileOAuth2TokenServiceFactory::GetForProfile(profile())
-      ->LoadCredentials(primary_account_id);
+      signin_manager()->GetAuthenticatedAccountId();
+  auth_service()->LoadCredentials(primary_account_id);
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(service()->GetAccessTokenForTest().empty());
 
   std::string secondary_account_gaiaid = "1234567";
   std::string secondary_account_name = "test_user2@gmail.com";
-  std::string secondary_account_id =
-      AccountTrackerServiceFactory::GetForProfile(profile())
-          ->SeedAccountInfo(secondary_account_gaiaid, secondary_account_name);
-  ProfileOAuth2TokenServiceFactory::GetForProfile(profile())
-      ->UpdateCredentials(secondary_account_id, "second_account_refresh_token");
-  ProfileOAuth2TokenServiceFactory::GetForProfile(profile())
-      ->RevokeCredentials(secondary_account_id);
+  std::string secondary_account_id = account_tracker()->SeedAccountInfo(
+      secondary_account_gaiaid, secondary_account_name);
+  auth_service()->UpdateCredentials(secondary_account_id,
+                                    "second_account_refresh_token");
+  auth_service()->RevokeCredentials(secondary_account_id);
   EXPECT_FALSE(service()->GetAccessTokenForTest().empty());
 
-  ProfileOAuth2TokenServiceFactory::GetForProfile(profile())
-      ->RevokeCredentials(primary_account_id);
+  auth_service()->RevokeCredentials(primary_account_id);
   EXPECT_TRUE(service()->GetAccessTokenForTest().empty());
 }
 
@@ -696,15 +712,12 @@
   EXPECT_TRUE(service()->IsSyncActive());
 
   std::string primary_account_id =
-      SigninManagerFactory::GetForProfile(profile())
-          ->GetAuthenticatedAccountId();
-  ProfileOAuth2TokenServiceFactory::GetForProfile(profile())
-      ->LoadCredentials(primary_account_id);
+      signin_manager()->GetAuthenticatedAccountId();
+  auth_service()->LoadCredentials(primary_account_id);
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(service()->GetAccessTokenForTest().empty());
 
-  SigninManagerFactory::GetForProfile(profile())
-      ->SignOut(signin_metrics::SIGNOUT_TEST);
+  signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST);
   EXPECT_TRUE(service()->GetAccessTokenForTest().empty());
 }
 #endif
@@ -724,8 +737,7 @@
   ExpectSyncBackendHostCreationCollectDeleteDir(2, &delete_dir_param);
   InitializeForFirstSync();
 
-  SigninManagerFactory::GetForProfile(profile())
-      ->SetAuthenticatedAccountInfo(kGaiaId, kEmail);
+  signin_manager()->SetAuthenticatedAccountInfo(kGaiaId, kEmail);
   IssueTestTokens();
   PumpLoop();
 
@@ -780,7 +792,8 @@
   EXPECT_EQ(ProfileSyncService::SYNC, service()->backend_mode());
 
   // First sync time should be recorded.
-  sync_driver::SyncPrefs sync_prefs(profile()->GetPrefs());
+  sync_driver::SyncPrefs sync_prefs(
+      service()->GetSyncClient()->GetPrefService());
   base::Time first_sync_time = sync_prefs.GetFirstSyncTime();
   EXPECT_FALSE(first_sync_time.is_null());
 
@@ -849,16 +862,16 @@
   InitializeForNthSync();
 
   EXPECT_TRUE(service()->IsSyncActive());
-  EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
-      sync_driver::prefs::kSyncSuppressStart));
+  EXPECT_FALSE(prefs()->GetBoolean(sync_driver::prefs::kSyncSuppressStart));
 
   testing::Mock::VerifyAndClearExpectations(components_factory());
 
-  sync_driver::SyncPrefs sync_prefs(profile()->GetPrefs());
+  sync_driver::SyncPrefs sync_prefs(
+      service()->GetSyncClient()->GetPrefService());
 
-  EXPECT_EQ(profile()->GetPrefs()->GetInteger(
-                sync_driver::prefs::kSyncMemoryPressureWarningCount),
-            0);
+  EXPECT_EQ(
+      prefs()->GetInteger(sync_driver::prefs::kSyncMemoryPressureWarningCount),
+      0);
   EXPECT_FALSE(sync_prefs.DidSyncShutdownCleanly());
 
   // Simulate memory pressure notification.
@@ -867,9 +880,9 @@
   base::RunLoop().RunUntilIdle();
 
   // Verify memory pressure recorded.
-  EXPECT_EQ(profile()->GetPrefs()->GetInteger(
-                sync_driver::prefs::kSyncMemoryPressureWarningCount),
-            1);
+  EXPECT_EQ(
+      prefs()->GetInteger(sync_driver::prefs::kSyncMemoryPressureWarningCount),
+      1);
   EXPECT_FALSE(sync_prefs.DidSyncShutdownCleanly());
 
   // Simulate memory pressure notification.
@@ -879,9 +892,9 @@
   ShutdownAndDeleteService();
 
   // Verify memory pressure and shutdown recorded.
-  EXPECT_EQ(profile()->GetPrefs()->GetInteger(
-                sync_driver::prefs::kSyncMemoryPressureWarningCount),
-            2);
+  EXPECT_EQ(
+      prefs()->GetInteger(sync_driver::prefs::kSyncMemoryPressureWarningCount),
+      2);
   EXPECT_TRUE(sync_prefs.DidSyncShutdownCleanly());
 }
 
@@ -1051,7 +1064,8 @@
   ExpectSyncBackendHostCreation(1);
   InitializeForNthSync();
 
-  sync_driver::SyncPrefs sync_prefs(profile()->GetPrefs());
+  sync_driver::SyncPrefs sync_prefs(
+      service()->GetSyncClient()->GetPrefService());
   EXPECT_EQ(PRODUCT_VERSION, sync_prefs.GetLastRunVersion());
 
   sync_prefs.SetPassphrasePrompted(true);
diff --git a/components/components_resources.gyp b/components/components_resources.gyp
index 82d1c1a8..9d73e3d 100644
--- a/components/components_resources.gyp
+++ b/components/components_resources.gyp
@@ -23,7 +23,6 @@
           # GN version: //components/resources:components_resources
           'action_name': 'generate_components_resources',
           'variables': {
-            'grit_whitelist': '',
             'grit_grd_file': 'resources/components_resources.grd',
             'grit_additional_defines': [
               '-E', 'about_credits_file=<(about_credits_file)',
@@ -35,7 +34,6 @@
           # GN version: //components/resources:components_scaled_resources
           'action_name': 'generate_components_scaled_resources',
           'variables': {
-            'grit_whitelist': '',
             'grit_grd_file': 'resources/components_scaled_resources.grd',
           },
           'includes': [ '../build/grit_action.gypi' ],
diff --git a/components/components_settings_strings.grdp b/components/components_settings_strings.grdp
new file mode 100644
index 0000000..eb9fe3a
--- /dev/null
+++ b/components/components_settings_strings.grdp
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+  <message name="IDS_SETTINGS_TITLE" desc="Title for the settings tab.">
+    Settings
+  </message>
+  <message name="IDS_SETTINGS_HIDE_ADVANCED_SETTINGS" desc="Title for the link to hide advanced settings.">
+    Hide advanced settings...
+  </message>
+  <message name="IDS_SETTINGS_SHOW_ADVANCED_SETTINGS" desc="Title for the link to show advanced settings.">
+    Show advanced settings...
+  </message>
+  <message name="IDS_NETWORK_PREDICTION_ENABLED_DESCRIPTION" desc="In the advanced options tab, the text next to the checkbox that enables prediction of network actions.  Actions include DNS prefetching, TCP and SSL preconnection, and prerendering of webpages.">
+    Prefetch resources to load pages more quickly
+  </message>
+  <message name="IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON" desc="The label of the 'Configure proxy settings' button">
+    Change proxy settings...
+  </message>
+</grit-part>
diff --git a/components/components_strings.grd b/components/components_strings.grd
index c760f16..18e3c0b 100644
--- a/components/components_strings.grd
+++ b/components/components_strings.grd
@@ -186,8 +186,10 @@
       <part file="autofill_strings.grdp" />
       <part file="bookmark_bar_strings.grdp" />
       <part file="browser_sync_strings.grdp" />
+      <part file="components_settings_strings.grdp" />
       <part file="crash_strings.grdp" />
       <part file="data_reduction_proxy_strings.grdp" />
+      <part file="dialog_strings.grdp" />
       <part file="dom_distiller_strings.grdp" />
       <part file="enhanced_bookmarks_strings.grdp" />
       <part file="error_page_strings.grdp" />
diff --git a/components/components_strings.gyp b/components/components_strings.gyp
index 31789acc..ac7b47c 100644
--- a/components/components_strings.gyp
+++ b/components/components_strings.gyp
@@ -15,7 +15,6 @@
           # GN version: //components/strings:components_strings
           'action_name': 'generate_components_strings',
           'variables': {
-            'grit_whitelist': '',
             'grit_grd_file': 'components_strings.grd',
           },
           'includes': [ '../build/grit_action.gypi' ],
@@ -24,7 +23,6 @@
           # GN version: //components/strings:components_chromium_strings
           'action_name': 'generate_components_chromium_strings',
           'variables': {
-            'grit_whitelist': '',
             'grit_grd_file': 'components_chromium_strings.grd',
           },
           'includes': [ '../build/grit_action.gypi' ],
@@ -33,7 +31,6 @@
           # GN version: //components/strings:components_google_chrome_strings
           'action_name': 'generate_components_google_chrome_strings',
           'variables': {
-            'grit_whitelist': '',
             'grit_grd_file': 'components_google_chrome_strings.grd',
           },
           'includes': [ '../build/grit_action.gypi' ],
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index b2be43b..a3b33281 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -74,6 +74,9 @@
       'bookmarks/browser/bookmark_utils_unittest.cc',
       'bookmarks/managed/managed_bookmarks_tracker_unittest.cc',
     ],
+    'browser_sync_unittest_sources': [
+      'browser_sync/browser/profile_sync_service_unittest.cc',
+    ],
     'browser_watcher_unittest_sources': [
       'browser_watcher/crash_reporting_metrics_win_unittest.cc',
       'browser_watcher/endsession_watcher_window_win_unittest.cc',
@@ -361,6 +364,13 @@
       'metrics/stability_metrics_helper_unittest.cc',
       'metrics/ui/screen_info_metrics_provider_unittest.cc',
     ],
+    'metrics_leak_detector_unittest_sources': [
+      'metrics/leak_detector/call_stack_manager_unittest.cc',
+      'metrics/leak_detector/call_stack_table_unittest.cc',
+      'metrics/leak_detector/leak_analyzer_unittest.cc',
+      'metrics/leak_detector/leak_detector_impl_unittest.cc',
+      'metrics/leak_detector/ranked_list_unittest.cc',
+    ],
     'mime_util_unittest_sources': [
       'mime_util/mime_util_unittest.cc',
     ],
@@ -395,6 +405,7 @@
       'omnibox/browser/answers_cache_unittest.cc',
       'omnibox/browser/autocomplete_input_unittest.cc',
       'omnibox/browser/autocomplete_match_unittest.cc',
+      'omnibox/browser/autocomplete_provider_unittest.cc',
       'omnibox/browser/autocomplete_result_unittest.cc',
       'omnibox/browser/base_search_provider_unittest.cc',
       'omnibox/browser/clipboard_url_provider_unittest.cc',
@@ -690,6 +701,7 @@
     ],
     'sync_driver_unittest_sources': [
       'sync_driver/about_sync_util_unittest.cc',
+      'sync_driver/backend_migrator_unittest.cc',
       'sync_driver/backup_rollback_controller_unittest.cc',
       'sync_driver/data_type_manager_impl_unittest.cc',
       'sync_driver/device_info_data_type_controller_unittest.cc',
@@ -705,7 +717,9 @@
       'sync_driver/non_blocking_data_type_controller_unittest.cc',
       'sync_driver/non_frontend_data_type_controller_unittest.cc',
       'sync_driver/non_ui_data_type_controller_unittest.cc',
+      'sync_driver/profile_sync_auth_provider_unittest.cc',
       'sync_driver/shared_change_processor_unittest.cc',
+      'sync_driver/startup_controller_unittest.cc',
       'sync_driver/sync_prefs_unittest.cc',
       'sync_driver/sync_stopped_reporter_unittest.cc',
       'sync_driver/sync_util_unittest.cc',
@@ -869,6 +883,7 @@
         '<@(auto_login_parser_unittest_sources)',
         '<@(autofill_unittest_sources)',
         '<@(bookmarks_unittest_sources)',
+        '<@(browser_sync_unittest_sources)',
         '<@(browser_watcher_unittest_sources)',
         '<@(bubble_unittest_sources)',
         '<@(captive_portal_unittest_sources)',
@@ -975,6 +990,7 @@
         'components.gyp:bookmarks_browser',
         'components.gyp:bookmarks_managed',
         'components.gyp:bookmarks_test_support',
+        'components.gyp:browser_sync_browser',
         'components.gyp:bubble',
         'components.gyp:captive_portal_test_support',
         'components.gyp:certificate_reporting',
@@ -1026,6 +1042,7 @@
         'components.gyp:network_time',
         'components.gyp:ntp_snippets',
         'components.gyp:offline_pages',
+        'components.gyp:offline_pages_test_support',
         'components.gyp:omnibox_browser',
         'components.gyp:omnibox_test_support',
         'components.gyp:open_from_clipboard',
@@ -1384,6 +1401,7 @@
             'wifi_sync/wifi_credential_unittest.cc',
             'wifi_sync/wifi_security_class_chromeos_unittest.cc',
             'wifi_sync/wifi_security_class_unittest.cc',
+            '<@(metrics_leak_detector_unittest_sources)',
             '<@(ownership_unittest_sources)',
           ],
           'sources!': [
@@ -1394,6 +1412,7 @@
             '../chromeos/chromeos.gyp:chromeos_test_support',
             'components.gyp:arc',
             'components.gyp:arc_test_support',
+            'components.gyp:metrics_leak_detector',
             'components.gyp:ownership',
             'components.gyp:pairing',
             'components.gyp:user_manager_test_support',
diff --git a/components/content_settings/core/common/content_settings_pattern.cc b/components/content_settings/core/common/content_settings_pattern.cc
index 3065cb3..3201cb8 100644
--- a/components/content_settings/core/common/content_settings_pattern.cc
+++ b/components/content_settings/core/common/content_settings_pattern.cc
@@ -240,9 +240,11 @@
 
 // static
 bool ContentSettingsPattern::Builder::Validate(const PatternParts& parts) {
-  // Sanity checks first: {scheme, port} wildcards imply empty {scheme, port}.
+  // Sanity checks first: {scheme, port, path} wildcards imply
+  // empty {scheme, port, path}.
   if ((parts.is_scheme_wildcard && !parts.scheme.empty()) ||
-      (parts.is_port_wildcard && !parts.port.empty())) {
+      (parts.is_port_wildcard && !parts.port.empty()) ||
+      (parts.is_path_wildcard && !parts.path.empty())) {
     NOTREACHED();
     return false;
   }
@@ -366,7 +368,6 @@
     const GURL& url) {
   scoped_ptr<ContentSettingsPattern::BuilderInterface> builder(
       ContentSettingsPattern::CreateBuilder(false));
-
   const GURL* local_url = &url;
   if (url.SchemeIsFileSystem() && url.inner_url()) {
     local_url = url.inner_url();
@@ -481,9 +482,8 @@
   // or if the path in the URL is identical to the one in the pattern.
   // For filesystem:file URLs, the path used is the filesystem type, so all
   // filesystem:file:///temporary/... are equivalent.
-  // TODO(markusheintz): Content settings should be defined for all files on
-  // a machine. Unless there is a good use case for supporting paths for file
-  // patterns, stop supporting path for file patterns.
+  // TODO(msramek): The file scheme should not behave differently when nested
+  // inside the filesystem scheme. Investigate and fix.
   if (!parts_.is_scheme_wildcard && scheme == url::kFileScheme)
     return parts_.is_path_wildcard ||
         parts_.path == std::string(local_url->path());
@@ -561,11 +561,18 @@
       scheme_relation == DISJOINT_ORDER_POST)
     return scheme_relation;
 
+  Relation path_relation = ComparePath(parts_, other.parts_);
+  if (path_relation == DISJOINT_ORDER_PRE ||
+      path_relation == DISJOINT_ORDER_POST)
+    return path_relation;
+
   if (host_relation != IDENTITY)
     return host_relation;
   if (port_relation != IDENTITY)
     return port_relation;
-  return scheme_relation;
+  if (scheme_relation != IDENTITY)
+    return scheme_relation;
+  return path_relation;
 }
 
 bool ContentSettingsPattern::operator==(
@@ -708,3 +715,27 @@
     return ContentSettingsPattern::DISJOINT_ORDER_PRE;
   return ContentSettingsPattern::DISJOINT_ORDER_POST;
 }
+
+ContentSettingsPattern::Relation ContentSettingsPattern::ComparePath(
+    const ContentSettingsPattern::PatternParts& parts,
+    const ContentSettingsPattern::PatternParts& other_parts) {
+  // Path is only set (in builder methods) and checked (in |Matches()|) for
+  // file:// URLs. For all other schemes, path is completely disregarded,
+  // and thus the result of this comparison is identity.
+  if (parts.scheme != url::kFileScheme ||
+      other_parts.scheme != url::kFileScheme) {
+    return ContentSettingsPattern::IDENTITY;
+  }
+
+  if (parts.is_path_wildcard && !other_parts.is_path_wildcard)
+    return ContentSettingsPattern::SUCCESSOR;
+  if (!parts.is_path_wildcard && other_parts.is_path_wildcard)
+    return ContentSettingsPattern::PREDECESSOR;
+
+  int result = parts.path.compare(other_parts.path);
+  if (result == 0)
+    return ContentSettingsPattern::IDENTITY;
+  if (result > 0)
+    return ContentSettingsPattern::DISJOINT_ORDER_PRE;
+  return ContentSettingsPattern::DISJOINT_ORDER_POST;
+}
diff --git a/components/content_settings/core/common/content_settings_pattern.h b/components/content_settings/core/common/content_settings_pattern.h
index 70b17a5..735012c 100644
--- a/components/content_settings/core/common/content_settings_pattern.h
+++ b/components/content_settings/core/common/content_settings_pattern.h
@@ -204,6 +204,10 @@
       const ContentSettingsPattern::PatternParts& parts,
       const ContentSettingsPattern::PatternParts& other_parts);
 
+  static Relation ComparePath(
+      const ContentSettingsPattern::PatternParts& parts,
+      const ContentSettingsPattern::PatternParts& other_parts);
+
   ContentSettingsPattern(const PatternParts& parts, bool valid);
 
   PatternParts parts_;
diff --git a/components/content_settings/core/common/content_settings_pattern_unittest.cc b/components/content_settings/core/common/content_settings_pattern_unittest.cc
index 3fb0448..c21658d 100644
--- a/components/content_settings/core/common/content_settings_pattern_unittest.cc
+++ b/components/content_settings/core/common/content_settings_pattern_unittest.cc
@@ -120,6 +120,9 @@
 
   EXPECT_STREQ("https://[*.]www.google.com:443", pattern2.ToString().c_str());
 
+  // TODO(msramek): Filesystem URLs do not return correct paths. For example,
+  // GURL("filesystem:file:///temporary/test.txt").inner_url().path() returns
+  // only '/temporary' instead of 'temporary/test.txt'. crbug.com/568110.
   pattern =
       ContentSettingsPattern::FromURL(
           GURL("filesystem:file:///temporary/foo/bar"));
@@ -130,7 +133,10 @@
   pattern2 =
       ContentSettingsPattern::FromURL(
           GURL("filesystem:file:///persistent/foo2/bar2"));
-  EXPECT_EQ(ContentSettingsPattern::IDENTITY, pattern.Compare(pattern2));
+  EXPECT_EQ(
+      ContentSettingsPattern::DISJOINT_ORDER_PRE, pattern.Compare(pattern2));
+  EXPECT_EQ(
+      ContentSettingsPattern::DISJOINT_ORDER_POST, pattern2.Compare(pattern));
 }
 
 TEST(ContentSettingsPatternTest, FromURLNoWildcard) {
@@ -248,6 +254,11 @@
   EXPECT_TRUE(Pattern("file:///*").IsValid());
   EXPECT_EQ("file:///*", Pattern("file:///*").ToString());
 
+  // It matches every file pattern.
+  ContentSettingsPattern file_wildcard = Pattern("file:///*");
+  EXPECT_TRUE(file_wildcard.Matches(GURL("file:///tmp/test.html")));
+  EXPECT_TRUE(file_wildcard.Matches(GURL("file://localhost/tmp/test.html")));
+
   // Wildcards are not allowed anywhere in the file path.
   EXPECT_FALSE(Pattern("file:///f*o/bar/file.html").IsValid());
   EXPECT_FALSE(Pattern("file:///*/bar/file.html").IsValid());
@@ -257,19 +268,42 @@
   EXPECT_FALSE(Pattern("file:///foo/bar/*.html").IsValid());
   EXPECT_FALSE(Pattern("file:///foo/bar/file.*").IsValid());
 
-  EXPECT_TRUE(Pattern("file:///tmp/test.html").IsValid());
-  EXPECT_EQ("file:///tmp/file.html",
-            Pattern("file:///tmp/file.html").ToString());
-  EXPECT_TRUE(Pattern("file:///tmp/test.html").Matches(
-      GURL("file:///tmp/test.html")));
-  EXPECT_FALSE(Pattern("file:///tmp/test.html").Matches(
-      GURL("file:///tmp/other.html")));
-  EXPECT_FALSE(Pattern("file:///tmp/test.html").Matches(
-      GURL("http://example.org/")));
+  // File patterns match URLs with the same path on any host.
+  EXPECT_TRUE(Pattern("file:///foo/bar/file.html").Matches(
+      GURL("file://localhost/foo/bar/file.html")));
+  EXPECT_TRUE(Pattern("file:///foo/bar/file.html").Matches(
+      GURL("file://example.com/foo/bar/file.html")));
+  EXPECT_FALSE(Pattern("file:///foo/bar/file.html").Matches(
+        GURL("file://localhost/foo/bar/other.html")));
+  EXPECT_FALSE(Pattern("file:///foo/bar/file.html").Matches(
+      GURL("file://example.com/foo/bar/other.html")));
 
-  EXPECT_TRUE(Pattern("file:///*").Matches(GURL("file:///tmp/test.html")));
-  EXPECT_TRUE(Pattern("file:///*").Matches(
-      GURL("file://localhost/tmp/test.html")));
+  ContentSettingsPattern pattern =
+      ContentSettingsPattern::FromURL(GURL("file:///tmp/test.html"));
+
+  EXPECT_TRUE(pattern.IsValid());
+  EXPECT_EQ("file:///tmp/test.html", pattern.ToString());
+  EXPECT_TRUE(pattern.Matches(GURL("file:///tmp/test.html")));
+  EXPECT_FALSE(pattern.Matches(GURL("file:///tmp/other.html")));
+  EXPECT_FALSE(pattern.Matches(GURL("http://example.org/")));
+
+  ContentSettingsPattern pattern2 =
+      ContentSettingsPattern::FromString("file:///tmp/test.html");
+  ContentSettingsPattern pattern3 =
+      ContentSettingsPattern::FromString("file:///tmp/other.html");
+
+  EXPECT_EQ(ContentSettingsPattern::IDENTITY,
+            pattern.Compare(pattern));
+  EXPECT_EQ(ContentSettingsPattern::IDENTITY,
+            pattern.Compare(pattern2));
+  EXPECT_EQ(ContentSettingsPattern::DISJOINT_ORDER_PRE,
+            pattern.Compare(pattern3));
+  EXPECT_EQ(ContentSettingsPattern::DISJOINT_ORDER_POST,
+            pattern3.Compare(pattern));
+  EXPECT_EQ(ContentSettingsPattern::SUCCESSOR,
+            file_wildcard.Compare(pattern));
+  EXPECT_EQ(ContentSettingsPattern::PREDECESSOR,
+            pattern.Compare(file_wildcard));
 }
 
 TEST(ContentSettingsPatternTest, FromString_ExtensionPatterns) {
diff --git a/components/crash/content/app/hard_error_handler_win.cc b/components/crash/content/app/hard_error_handler_win.cc
index a310666..21f24369 100644
--- a/components/crash/content/app/hard_error_handler_win.cc
+++ b/components/crash/content/app/hard_error_handler_win.cc
@@ -33,8 +33,9 @@
 // This is not a generic function. It only works with some |nt_status| values.
 // Check the strings here http://msdn.microsoft.com/en-us/library/cc704588.aspx
 // before attempting to use this function.
-void RaiseHardErrorMsg(long nt_status, const std::string& p1,
-                                       const std::string& p2) {
+void RaiseHardErrorMsg(DWORD nt_status,
+                       const std::string& p1,
+                       const std::string& p2) {
   // If headless just exit silently.
   if (GetCrashReporterClient()->IsRunningUnattended())
     return;
@@ -95,7 +96,7 @@
   if (!ex_info->ExceptionRecord)
     return false;
 
-  long exception = ex_info->ExceptionRecord->ExceptionCode;
+  DWORD exception = ex_info->ExceptionRecord->ExceptionCode;
   if (exception == kExceptionModuleNotFound) {
     ModuleNotFoundHardError(ex_info->ExceptionRecord);
     return true;
diff --git a/components/cronet.gypi b/components/cronet.gypi
index 4f567a8..b9972a8e 100644
--- a/components/cronet.gypi
+++ b/components/cronet.gypi
@@ -48,16 +48,12 @@
           'includes': [ '../build/android/java_cpp_enum.gypi' ],
         },
         {
-          'target_name': 'cronet_engine_builder_list',
+          'target_name': 'http_cache_type_java',
           'type': 'none',
-          'sources': [
-            'cronet/android/java/src/org/chromium/net/CronetEngineBuilderList.template',
-          ],
           'variables': {
-            'package_name': 'org/chromium/net',
-            'template_deps': ['cronet/url_request_context_config_list.h'],
+            'source_file': 'cronet/url_request_context_config.h',
           },
-          'includes': [ '../build/android/java_cpp_template.gypi' ],
+          'includes': [ '../build/android/java_cpp_enum.gypi' ],
         },
         {
           'target_name': 'load_states_list',
@@ -214,7 +210,7 @@
           'target_name': 'cronet_api',
           'type': 'none',
           'dependencies': [
-            'cronet_engine_builder_list',
+            'http_cache_type_java',
             'cronet_version',
             'load_states_list',
             'network_quality_observations_java',
@@ -328,6 +324,7 @@
             'cronet/android/test/src/org/chromium/net/QuicTestServer.java',
             'cronet/android/test/src/org/chromium/net/SdchObserver.java',
             'cronet/android/test/src/org/chromium/net/TestUploadDataStreamHandler.java',
+            'cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java',
           ],
           'variables': {
             'jni_gen_package': 'cronet_tests',
@@ -353,6 +350,8 @@
             'cronet/android/test/test_upload_data_stream_handler.h',
             'cronet/android/test/network_change_notifier_util.cc',
             'cronet/android/test/network_change_notifier_util.h',
+            'cronet/android/test/cronet_url_request_context_config_test.cc',
+            'cronet/android/test/cronet_url_request_context_config_test.h',
           ],
           'dependencies': [
             'cronet_tests_jni_headers',
diff --git a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
index 9170046e..4bf88d7 100644
--- a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
+++ b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
@@ -6,13 +6,8 @@
 
 import android.content.Context;
 import android.support.annotation.IntDef;
-import android.util.Base64;
 import android.util.Log;
 
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
 import java.io.File;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -24,6 +19,7 @@
 import java.net.URLStreamHandlerFactory;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -41,18 +37,72 @@
      * then {@link #build} is called to create the {@code CronetEngine}.
      */
     public static class Builder {
+        // A hint that a host supports QUIC.
+        static class QuicHint {
+            // The host.
+            final String mHost;
+            // Port of the server that supports QUIC.
+            final int mPort;
+            // Alternate protocol port.
+            final int mAlternatePort;
+
+            QuicHint(String host, int port, int alternatePort) {
+                mHost = host;
+                mPort = port;
+                mAlternatePort = alternatePort;
+            }
+        }
+
+        // A public key pin.
+        static class Pkp {
+            // Host to pin for.
+            final String mHost;
+            // Array of SHA-256 hashes of keys.
+            final byte[][] mHashes;
+            // Should pin apply to subdomains?
+            final boolean mIncludeSubdomains;
+            // When the pin expires.
+            final Date mExpirationDate;
+
+            Pkp(String host, byte[][] hashes, boolean includeSubdomains, Date expirationDate) {
+                mHost = host;
+                mHashes = hashes;
+                mIncludeSubdomains = includeSubdomains;
+                mExpirationDate = expirationDate;
+            }
+        }
+
         private static final Pattern INVALID_PKP_HOST_NAME = Pattern.compile("^[0-9\\.]*$");
 
-        private final JSONObject mConfig;
+        // Private fields are simply storage of configuration for the resulting CronetEngine.
+        // See setters below for verbose descriptions.
         private final Context mContext;
+        private final List<QuicHint> mQuicHints = new LinkedList<QuicHint>();
+        private final List<Pkp> mPkps = new LinkedList<Pkp>();
+        private String mUserAgent;
+        private String mStoragePath;
+        private boolean mLegacyModeEnabled;
+        private String mLibraryName;
+        private boolean mQuicEnabled;
+        private boolean mHttp2Enabled;
+        private boolean mSdchEnabled;
+        private String mDataReductionProxyKey;
+        private String mDataReductionProxyPrimaryProxy;
+        private String mDataReductionProxyFallbackProxy;
+        private String mDataReductionProxySecureProxyCheckUrl;
+        private boolean mDisableCache;
+        private int mHttpCacheMode;
+        private long mHttpCacheMaxSize;
+        private String mExperimentalOptions;
+        private long mMockCertVerifier;
 
         /**
          * Default config enables SPDY, disables QUIC, SDCH and HTTP cache.
          * @param context Android {@link Context} for engine to use.
          */
         public Builder(Context context) {
-            mConfig = new JSONObject();
             mContext = context;
+            setLibraryName("cronet");
             enableLegacyMode(false);
             enableQUIC(false);
             enableHTTP2(true);
@@ -75,11 +125,12 @@
          * @return the builder to facilitate chaining.
          */
         public Builder setUserAgent(String userAgent) {
-            return putString(CronetEngineBuilderList.USER_AGENT, userAgent);
+            mUserAgent = userAgent;
+            return this;
         }
 
         String getUserAgent() {
-            return mConfig.optString(CronetEngineBuilderList.USER_AGENT);
+            return mUserAgent;
         }
 
         /**
@@ -98,12 +149,12 @@
                 throw new IllegalArgumentException(
                         "Storage path must be set to existing directory");
             }
-
-            return putString(CronetEngineBuilderList.STORAGE_PATH, value);
+            mStoragePath = value;
+            return this;
         }
 
         String storagePath() {
-            return mConfig.optString(CronetEngineBuilderList.STORAGE_PATH);
+            return mStoragePath;
         }
 
         /**
@@ -115,11 +166,12 @@
          */
         @Deprecated
         public Builder enableLegacyMode(boolean value) {
-            return putBoolean(CronetEngineBuilderList.ENABLE_LEGACY_MODE, value);
+            mLegacyModeEnabled = value;
+            return this;
         }
 
         boolean legacyMode() {
-            return mConfig.optBoolean(CronetEngineBuilderList.ENABLE_LEGACY_MODE);
+            return mLegacyModeEnabled;
         }
 
         /**
@@ -127,11 +179,12 @@
          * @return the builder to facilitate chaining.
          */
         Builder setLibraryName(String libName) {
-            return putString(CronetEngineBuilderList.NATIVE_LIBRARY_NAME, libName);
+            mLibraryName = libName;
+            return this;
         }
 
         String libraryName() {
-            return mConfig.optString(CronetEngineBuilderList.NATIVE_LIBRARY_NAME, "cronet");
+            return mLibraryName;
         }
 
         /**
@@ -140,7 +193,12 @@
          * @return the builder to facilitate chaining.
          */
         public Builder enableQUIC(boolean value) {
-            return putBoolean(CronetEngineBuilderList.ENABLE_QUIC, value);
+            mQuicEnabled = value;
+            return this;
+        }
+
+        boolean quicEnabled() {
+            return mQuicEnabled;
         }
 
         /**
@@ -149,7 +207,12 @@
          * @return the builder to facilitate chaining.
          */
         public Builder enableHTTP2(boolean value) {
-            return putBoolean(CronetEngineBuilderList.ENABLE_SPDY, value);
+            mHttp2Enabled = value;
+            return this;
+        }
+
+        boolean http2Enabled() {
+            return mHttp2Enabled;
         }
 
         /**
@@ -160,7 +223,12 @@
          * @return the builder to facilitate chaining.
          */
         public Builder enableSDCH(boolean value) {
-            return putBoolean(CronetEngineBuilderList.ENABLE_SDCH, value);
+            mSdchEnabled = value;
+            return this;
+        }
+
+        boolean sdchEnabled() {
+            return mSdchEnabled;
         }
 
         /**
@@ -171,7 +239,12 @@
          * @return the builder to facilitate chaining.
          */
         public Builder enableDataReductionProxy(String key) {
-            return (putString(CronetEngineBuilderList.DATA_REDUCTION_PROXY_KEY, key));
+            mDataReductionProxyKey = key;
+            return this;
+        }
+
+        String dataReductionProxyKey() {
+            return mDataReductionProxyKey;
         }
 
         /**
@@ -197,13 +270,24 @@
                 throw new IllegalArgumentException(
                         "Primary and fallback proxies and check url must be set");
             }
-            putString(CronetEngineBuilderList.DATA_REDUCTION_PRIMARY_PROXY, primaryProxy);
-            putString(CronetEngineBuilderList.DATA_REDUCTION_FALLBACK_PROXY, fallbackProxy);
-            putString(CronetEngineBuilderList.DATA_REDUCTION_SECURE_PROXY_CHECK_URL,
-                    secureProxyCheckUrl);
+            mDataReductionProxyPrimaryProxy = primaryProxy;
+            mDataReductionProxyFallbackProxy = fallbackProxy;
+            mDataReductionProxySecureProxyCheckUrl = secureProxyCheckUrl;
             return this;
         }
 
+        String dataReductionProxyPrimaryProxy() {
+            return mDataReductionProxyPrimaryProxy;
+        }
+
+        String dataReductionProxyFallbackProxy() {
+            return mDataReductionProxyFallbackProxy;
+        }
+
+        String dataReductionProxySecureProxyCheckUrl() {
+            return mDataReductionProxySecureProxyCheckUrl;
+        }
+
         /** @deprecated not really deprecated but hidden. */
         @IntDef({
                 HTTP_CACHE_DISABLED, HTTP_CACHE_IN_MEMORY, HTTP_CACHE_DISK_NO_HTTP, HTTP_CACHE_DISK,
@@ -249,34 +333,47 @@
          */
         public Builder enableHttpCache(@HttpCacheSetting int cacheMode, long maxSize) {
             if (cacheMode == HTTP_CACHE_DISK || cacheMode == HTTP_CACHE_DISK_NO_HTTP) {
-                if (storagePath().isEmpty()) {
+                if (storagePath() == null) {
                     throw new IllegalArgumentException("Storage path must be set");
                 }
             } else {
-                if (!storagePath().isEmpty()) {
-                    throw new IllegalArgumentException("Storage path must be empty");
+                if (storagePath() != null) {
+                    throw new IllegalArgumentException("Storage path must not be set");
                 }
             }
-            putBoolean(CronetEngineBuilderList.LOAD_DISABLE_CACHE,
-                    cacheMode == HTTP_CACHE_DISABLED || cacheMode == HTTP_CACHE_DISK_NO_HTTP);
-            putLong(CronetEngineBuilderList.HTTP_CACHE_MAX_SIZE, maxSize);
+            mDisableCache =
+                    (cacheMode == HTTP_CACHE_DISABLED || cacheMode == HTTP_CACHE_DISK_NO_HTTP);
+            mHttpCacheMaxSize = maxSize;
 
             switch (cacheMode) {
                 case HTTP_CACHE_DISABLED:
-                    return putString(CronetEngineBuilderList.HTTP_CACHE,
-                            CronetEngineBuilderList.HTTP_CACHE_DISABLED);
+                    mHttpCacheMode = HttpCacheType.DISABLED;
+                    break;
                 case HTTP_CACHE_DISK_NO_HTTP:
                 case HTTP_CACHE_DISK:
-                    return putString(CronetEngineBuilderList.HTTP_CACHE,
-                            CronetEngineBuilderList.HTTP_CACHE_DISK);
-
+                    mHttpCacheMode = HttpCacheType.DISK;
+                    break;
                 case HTTP_CACHE_IN_MEMORY:
-                    return putString(CronetEngineBuilderList.HTTP_CACHE,
-                            CronetEngineBuilderList.HTTP_CACHE_MEMORY);
+                    mHttpCacheMode = HttpCacheType.MEMORY;
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unknown cache mode");
             }
             return this;
         }
 
+        boolean cacheDisabled() {
+            return mDisableCache;
+        }
+
+        long httpCacheMaxSize() {
+            return mHttpCacheMaxSize;
+        }
+
+        int httpCacheMode() {
+            return mHttpCacheMode;
+        }
+
         /**
          * Adds hint that {@code host} supports QUIC.
          * Note that {@link #enableHttpCache enableHttpCache}
@@ -292,24 +389,14 @@
             if (host.contains("/")) {
                 throw new IllegalArgumentException("Illegal QUIC Hint Host: " + host);
             }
-            try {
-                JSONArray quicHints = mConfig.optJSONArray(CronetEngineBuilderList.QUIC_HINTS);
-                if (quicHints == null) {
-                    quicHints = new JSONArray();
-                    mConfig.put(CronetEngineBuilderList.QUIC_HINTS, quicHints);
-                }
-
-                JSONObject hint = new JSONObject();
-                hint.put(CronetEngineBuilderList.QUIC_HINT_HOST, host);
-                hint.put(CronetEngineBuilderList.QUIC_HINT_PORT, port);
-                hint.put(CronetEngineBuilderList.QUIC_HINT_ALT_PORT, alternatePort);
-                quicHints.put(hint);
-            } catch (JSONException e) {
-                // Intentionally do nothing.
-            }
+            mQuicHints.add(new QuicHint(host, port, alternatePort));
             return this;
         }
 
+        List<QuicHint> quicHints() {
+            return mQuicHints;
+        }
+
         /**
          * <p>
          * Pins a set of public keys for a given host. By pinning a set of public keys,
@@ -363,51 +450,25 @@
                 throw new NullPointerException("The pin expiration date cannot be null");
             }
             String idnHostName = validateHostNameForPinningAndConvert(hostName);
-            try {
-                // Add PKP_LIST JSON array element if it is not present.
-                JSONArray pkpList = mConfig.optJSONArray(CronetEngineBuilderList.PKP_LIST);
-                if (pkpList == null) {
-                    pkpList = new JSONArray();
-                    mConfig.put(CronetEngineBuilderList.PKP_LIST, pkpList);
+            // Convert the pin to BASE64 encoding. The hash set will eliminate duplications.
+            Set<byte[]> hashes = new HashSet<>(pinsSha256.size());
+            for (byte[] pinSha256 : pinsSha256) {
+                if (pinSha256 == null || pinSha256.length != 32) {
+                    throw new IllegalArgumentException("Public key pin is invalid");
                 }
-
-                // Convert the pin to BASE64 encoding. The hash set will eliminate duplications.
-                Set<String> hashes = new HashSet<>(pinsSha256.size());
-                for (byte[] pinSha256 : pinsSha256) {
-                    hashes.add(convertSha256ToBase64WithPrefix(pinSha256));
-                }
-
-                // Add new element to PKP_LIST JSON array.
-                JSONObject pkp = new JSONObject();
-                pkp.put(CronetEngineBuilderList.PKP_HOST, idnHostName);
-                pkp.put(CronetEngineBuilderList.PKP_PIN_HASHES, new JSONArray(hashes));
-                pkp.put(CronetEngineBuilderList.PKP_INCLUDE_SUBDOMAINS, includeSubdomains);
-                // The expiration time is passed as a double, in seconds since January 1, 1970.
-                pkp.put(CronetEngineBuilderList.PKP_EXPIRATION_DATE,
-                        (double) expirationDate.getTime() / 1000);
-                pkpList.put(pkp);
-            } catch (JSONException e) {
-                // This exception should never happen.
-                throw new RuntimeException(
-                        "Failed to add pubic key pins with the given arguments", e);
+                hashes.add(pinSha256);
             }
+            // Add new element to PKP list.
+            mPkps.add(new Pkp(idnHostName, hashes.toArray(new byte[hashes.size()][]),
+                    includeSubdomains, expirationDate));
             return this;
         }
 
         /**
-         * Converts a given SHA256 array of bytes to BASE64 encoded string and prepends
-         * {@code sha256/} prefix to it. The format corresponds to the format that is expected by
-         * {@code net::HashValue} class.
-         *
-         * @param sha256 SHA256 bytes to convert to BASE64.
-         * @return the BASE64 encoded SHA256 with the prefix.
-         * @throws IllegalArgumentException if the provided pin is invalid.
+         * Returns list of public key pins.
          */
-        private static String convertSha256ToBase64WithPrefix(byte[] sha256) {
-            if (sha256 == null || sha256.length != 32) {
-                throw new IllegalArgumentException("Public key pin is invalid");
-            }
-            return "sha256/" + Base64.encodeToString(sha256, Base64.NO_WRAP);
+        List<Pkp> publicKeyPins() {
+            return mPkps;
         }
 
         /**
@@ -446,22 +507,24 @@
          * @return the builder to facilitate chaining.
          */
         public Builder setExperimentalOptions(String options) {
-            return putString(CronetEngineBuilderList.EXPERIMENTAL_OPTIONS, options);
+            mExperimentalOptions = options;
+            return this;
+        }
+
+        String experimentalOptions() {
+            return mExperimentalOptions;
         }
 
         /**
          * Sets a native MockCertVerifier for testing.
          */
         Builder setMockCertVerifierForTesting(long mockCertVerifier) {
-            return putString(
-                    CronetEngineBuilderList.MOCK_CERT_VERIFIER, String.valueOf(mockCertVerifier));
+            mMockCertVerifier = mockCertVerifier;
+            return this;
         }
 
-        /**
-         * Gets a JSON string representation of the builder.
-         */
-        String toJSONString() {
-            return mConfig.toString();
+        long mockCertVerifier() {
+            return mMockCertVerifier;
         }
 
         /**
@@ -474,55 +537,13 @@
         }
 
         /**
-         * Sets a boolean value in the config. Returns a reference to the same
-         * config object, so you can chain put calls together.
-         * @return the builder to facilitate chaining.
-         */
-        private Builder putBoolean(String key, boolean value) {
-            try {
-                mConfig.put(key, value);
-            } catch (JSONException e) {
-                // Intentionally do nothing.
-            }
-            return this;
-        }
-
-        /**
-         * Sets a long value in the config. Returns a reference to the same
-         * config object, so you can chain put calls together.
-         * @return the builder to facilitate chaining.
-         */
-        private Builder putLong(String key, long value) {
-            try {
-                mConfig.put(key, value);
-            } catch (JSONException e) {
-                // Intentionally do nothing.
-            }
-            return this;
-        }
-
-        /**
-         * Sets a string value in the config. Returns a reference to the same
-         * config object, so you can chain put calls together.
-         * @return the builder to facilitate chaining.
-         */
-        private Builder putString(String key, String value) {
-            try {
-                mConfig.put(key, value);
-            } catch (JSONException e) {
-                // Intentionally do nothing.
-            }
-            return this;
-        }
-
-        /**
          * Build a {@link CronetEngine} using this builder's configuration.
          */
         public CronetEngine build() {
             CronetEngine engine = createContext(this);
             // Clear MOCK_CERT_VERIFIER reference if there is any, since
             // the ownership has been transferred to the engine.
-            mConfig.remove(CronetEngineBuilderList.MOCK_CERT_VERIFIER);
+            mMockCertVerifier = 0;
             return engine;
         }
     }
@@ -798,7 +819,7 @@
     @Deprecated
     public static CronetEngine createContext(Builder builder) {
         CronetEngine cronetEngine = null;
-        if (builder.getUserAgent().isEmpty()) {
+        if (builder.getUserAgent() == null) {
             builder.setUserAgent(builder.getDefaultUserAgent());
         }
         if (!builder.legacyMode()) {
diff --git a/components/cronet/android/api/src/org/chromium/net/HttpUrlConnectionUrlRequestFactory.java b/components/cronet/android/api/src/org/chromium/net/HttpUrlConnectionUrlRequestFactory.java
index 89e5c01..28b0974 100644
--- a/components/cronet/android/api/src/org/chromium/net/HttpUrlConnectionUrlRequestFactory.java
+++ b/components/cronet/android/api/src/org/chromium/net/HttpUrlConnectionUrlRequestFactory.java
@@ -24,7 +24,7 @@
     public HttpUrlConnectionUrlRequestFactory(Context context, CronetEngine.Builder config) {
         mContext = context;
         String userAgent = config.getUserAgent();
-        if (userAgent.isEmpty()) {
+        if (userAgent == null) {
             // Cannot use config.getDefaultUserAgent() as config.mContext may be null.
             userAgent = new CronetEngine.Builder(mContext).getDefaultUserAgent();
         }
diff --git a/components/cronet/android/chromium_url_request_context.cc b/components/cronet/android/chromium_url_request_context.cc
index 247077d..3969ec0cf 100644
--- a/components/cronet/android/chromium_url_request_context.cc
+++ b/components/cronet/android/chromium_url_request_context.cc
@@ -66,24 +66,11 @@
     const JavaParamRef<jobject>& jcaller,
     const JavaParamRef<jstring>& juser_agent,
     jint jlog_level,
-    const JavaParamRef<jstring>& jconfig) {
+    jlong jconfig) {
   std::string user_agent = ConvertJavaStringToUTF8(env, juser_agent);
 
-  std::string config = ConvertJavaStringToUTF8(env, jconfig);
-
-  scoped_ptr<base::Value> config_value = base::JSONReader::Read(config);
-  if (!config_value || !config_value->IsType(base::Value::TYPE_DICTIONARY)) {
-    DLOG(ERROR) << "Bad JSON: " << config;
-    return 0;
-  }
-
   scoped_ptr<URLRequestContextConfig> context_config(
-      new URLRequestContextConfig());
-  base::JSONValueConverter<URLRequestContextConfig> converter;
-  if (!converter.Convert(*config_value, context_config.get())) {
-    DLOG(ERROR) << "Bad Config: " << config_value;
-    return 0;
-  }
+      reinterpret_cast<URLRequestContextConfig*>(jconfig));
 
   // TODO(mef): MinLogLevel is global, shared by all URLRequestContexts.
   // Revisit this if each URLRequestContext would need an individual log level.
diff --git a/components/cronet/android/cronet_data_reduction_proxy.cc b/components/cronet/android/cronet_data_reduction_proxy.cc
index c4c19df..195ab8e 100644
--- a/components/cronet/android/cronet_data_reduction_proxy.cc
+++ b/components/cronet/android/cronet_data_reduction_proxy.cc
@@ -27,8 +27,12 @@
 namespace cronet {
 namespace {
 
+// Name of the preference that governs enabling the Data Reduction Proxy.
+const char kDataReductionProxyEnabled[] = "data_reduction_proxy.enabled";
+
 scoped_ptr<PrefService> CreatePrefService() {
   scoped_refptr<PrefRegistrySimple> pref_registry(new PrefRegistrySimple());
+  pref_registry->RegisterBooleanPref(kDataReductionProxyEnabled, false);
   data_reduction_proxy::RegisterSimpleProfilePrefs(pref_registry.get());
   base::PrefServiceFactory pref_service_factory;
   pref_service_factory.set_user_prefs(
@@ -120,7 +124,8 @@
   io_data_->SetDataReductionProxyService(
       data_reduction_proxy_service->GetWeakPtr());
   settings_->InitDataReductionProxySettings(
-      prefs_.get(), io_data_.get(), data_reduction_proxy_service.Pass());
+      kDataReductionProxyEnabled, prefs_.get(), io_data_.get(),
+      data_reduction_proxy_service.Pass());
   settings_->SetDataReductionProxyEnabled(enable);
   settings_->MaybeActivateDataReductionProxy(true);
 }
diff --git a/components/cronet/android/cronet_url_request_context_adapter.cc b/components/cronet/android/cronet_url_request_context_adapter.cc
index 6861197..7132f7e 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.cc
+++ b/components/cronet/android/cronet_url_request_context_adapter.cc
@@ -32,6 +32,7 @@
 #include "net/base/net_errors.h"
 #include "net/base/net_util.h"
 #include "net/base/network_delegate_impl.h"
+#include "net/cert/cert_verifier.h"
 #include "net/http/http_auth_handler_factory.h"
 #include "net/http/http_server_properties_manager.h"
 #include "net/log/write_to_file_net_log_observer.h"
@@ -289,7 +290,7 @@
   context_builder.set_proxy_service(
       net::ProxyService::CreateWithoutProxyResolver(
           proxy_config_service_.Pass(), net_log_.get()));
-  config->ConfigureURLRequestContextBuilder(&context_builder);
+  config->ConfigureURLRequestContextBuilder(&context_builder, net_log_.get());
 
   // Set up pref file if storage path is specified.
   if (!config->storage_path.empty()) {
@@ -384,23 +385,10 @@
 
   // Iterate through PKP configuration for every host.
   for (const auto& pkp : config->pkp_list) {
-    // Convert the vector of hash strings from the config to
-    // a vector of HashValue objects.
-    net::HashValueVector hash_value_vector;
-    for (const auto& hash : pkp->pin_hashes) {
-      net::HashValue hash_value;
-      bool good_hash = hash_value.FromString(*hash);
-      if (good_hash) {
-        hash_value_vector.push_back(hash_value);
-      } else {
-        LOG(WARNING) << "Unable to add hash value " << *hash;
-      }
-    }
-
     // Add the host pinning.
     context_->transport_security_state()->AddHPKP(
         pkp->host, pkp->expiration_date, pkp->include_subdomains,
-        hash_value_vector, GURL::EmptyGURL());
+        pkp->pin_hashes, GURL::EmptyGURL());
   }
 
   JNIEnv* env = base::android::AttachCurrentThread();
@@ -548,17 +536,105 @@
       (timestamp - base::TimeTicks::UnixEpoch()).InMilliseconds(), source);
 }
 
+// Create a URLRequestContextConfig from the given parameters.
+static jlong CreateRequestContextConfig(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& jcaller,
+    const JavaParamRef<jstring>& juser_agent,
+    const JavaParamRef<jstring>& jstorage_path,
+    jboolean jquic_enabled,
+    jboolean jhttp2_enabled,
+    jboolean jsdch_enabled,
+    const JavaParamRef<jstring>& jdata_reduction_proxy_key,
+    const JavaParamRef<jstring>& jdata_reduction_proxy_primary_proxy,
+    const JavaParamRef<jstring>& jdata_reduction_proxy_fallback_proxy,
+    const JavaParamRef<jstring>& jdata_reduction_proxy_secure_proxy_check_url,
+    jboolean jdisable_cache,
+    jint jhttp_cache_mode,
+    jlong jhttp_cache_max_size,
+    const JavaParamRef<jstring>& jexperimental_quic_connection_options,
+    jlong jmock_cert_verifier) {
+  return reinterpret_cast<jlong>(new URLRequestContextConfig(
+      jquic_enabled, jhttp2_enabled, jsdch_enabled,
+      static_cast<URLRequestContextConfig::HttpCacheType>(jhttp_cache_mode),
+      jhttp_cache_max_size, jdisable_cache,
+      base::android::ConvertJavaStringToUTF8(env, jstorage_path),
+      base::android::ConvertJavaStringToUTF8(env, juser_agent),
+      base::android::ConvertJavaStringToUTF8(
+          env, jexperimental_quic_connection_options),
+      base::android::ConvertJavaStringToUTF8(env, jdata_reduction_proxy_key),
+      base::android::ConvertJavaStringToUTF8(
+          env, jdata_reduction_proxy_primary_proxy),
+      base::android::ConvertJavaStringToUTF8(
+          env, jdata_reduction_proxy_fallback_proxy),
+      base::android::ConvertJavaStringToUTF8(
+          env, jdata_reduction_proxy_secure_proxy_check_url),
+      make_scoped_ptr(
+          reinterpret_cast<net::CertVerifier*>(jmock_cert_verifier))));
+}
+
+// Add a QUIC hint to a URLRequestContextConfig.
+static void AddQuicHint(JNIEnv* env,
+                        const JavaParamRef<jclass>& jcaller,
+                        jlong jurl_request_context_config,
+                        const JavaParamRef<jstring>& jhost,
+                        jint jport,
+                        jint jalternate_port) {
+  URLRequestContextConfig* config =
+      reinterpret_cast<URLRequestContextConfig*>(jurl_request_context_config);
+  config->quic_hints.push_back(
+      make_scoped_ptr(new URLRequestContextConfig::QuicHint(
+          base::android::ConvertJavaStringToUTF8(env, jhost), jport,
+          jalternate_port)));
+}
+
+// Add a public key pin to URLRequestContextConfig.
+// |jhost| is the host to apply the pin to.
+// |jhashes| is an array of jbyte[32] representing SHA256 key hashes.
+// |jinclude_subdomains| indicates if pin should be applied to subdomains.
+// |jexpiration_time| is the time that the pin expires, in milliseconds since
+// Jan. 1, 1970, midnight GMT.
+static void AddPkp(JNIEnv* env,
+                   const JavaParamRef<jclass>& jcaller,
+                   jlong jurl_request_context_config,
+                   const JavaParamRef<jstring>& jhost,
+                   const JavaParamRef<jobjectArray>& jhashes,
+                   jboolean jinclude_subdomains,
+                   jlong jexpiration_time) {
+  URLRequestContextConfig* config =
+      reinterpret_cast<URLRequestContextConfig*>(jurl_request_context_config);
+  scoped_ptr<URLRequestContextConfig::Pkp> pkp(new URLRequestContextConfig::Pkp(
+      base::android::ConvertJavaStringToUTF8(env, jhost), jinclude_subdomains,
+      base::Time::UnixEpoch() +
+          base::TimeDelta::FromMilliseconds(jexpiration_time)));
+  size_t hash_count = env->GetArrayLength(jhashes);
+  for (size_t i = 0; i < hash_count; ++i) {
+    ScopedJavaLocalRef<jbyteArray> bytes_array(
+        env, static_cast<jbyteArray>(env->GetObjectArrayElement(jhashes, i)));
+    static_assert(std::is_pod<net::SHA256HashValue>::value,
+                  "net::SHA256HashValue is not POD");
+    static_assert(sizeof(net::SHA256HashValue) * CHAR_BIT == 256,
+                  "net::SHA256HashValue contains overhead");
+    if (env->GetArrayLength(bytes_array.obj()) !=
+        sizeof(net::SHA256HashValue)) {
+      LOG(ERROR) << "Unable to add public key hash value.";
+      continue;
+    }
+    jbyte* bytes = env->GetByteArrayElements(bytes_array.obj(), nullptr);
+    net::HashValue hash(*reinterpret_cast<net::SHA256HashValue*>(bytes));
+    pkp->pin_hashes.push_back(hash);
+    env->ReleaseByteArrayElements(bytes_array.obj(), bytes, JNI_ABORT);
+  }
+  config->pkp_list.push_back(std::move(pkp));
+}
+
 // Creates RequestContextAdater if config is valid URLRequestContextConfig,
 // returns 0 otherwise.
 static jlong CreateRequestContextAdapter(JNIEnv* env,
                                          const JavaParamRef<jclass>& jcaller,
-                                         const JavaParamRef<jstring>& jconfig) {
-  std::string config_string =
-      base::android::ConvertJavaStringToUTF8(env, jconfig);
+                                         jlong jconfig) {
   scoped_ptr<URLRequestContextConfig> context_config(
-      new URLRequestContextConfig());
-  if (!context_config->LoadFromJSON(config_string))
-    return 0;
+      reinterpret_cast<URLRequestContextConfig*>(jconfig));
 
   CronetURLRequestContextAdapter* context_adapter =
       new CronetURLRequestContextAdapter(context_config.Pass());
diff --git a/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestContext.java
index 40d6642..9b252fca 100644
--- a/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestContext.java
+++ b/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestContext.java
@@ -36,8 +36,9 @@
     protected ChromiumUrlRequestContext(
             final Context context, String userAgent, CronetEngine.Builder config) {
         CronetLibraryLoader.ensureInitialized(context, config);
-        mChromiumUrlRequestContextAdapter = nativeCreateRequestContextAdapter(
-                userAgent, getLoggingLevel(), config.toJSONString());
+        mChromiumUrlRequestContextAdapter =
+                nativeCreateRequestContextAdapter(userAgent, getLoggingLevel(),
+                        CronetUrlRequestContext.createNativeUrlRequestContextConfig(config));
         if (mChromiumUrlRequestContextAdapter == 0) {
             throw new NullPointerException("Context Adapter creation failed");
         }
@@ -140,7 +141,7 @@
     // Returns an instance ChromiumUrlRequestContextAdapter to be stored in
     // mChromiumUrlRequestContextAdapter.
     private native long nativeCreateRequestContextAdapter(
-            String userAgent, int loggingLevel, String config);
+            String userAgent, int loggingLevel, long config);
 
     private native void nativeReleaseRequestContextAdapter(
             long chromiumUrlRequestContextAdapter);
diff --git a/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestFactory.java b/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestFactory.java
index a8f20ca..9cd98c1 100644
--- a/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestFactory.java
+++ b/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestFactory.java
@@ -25,7 +25,7 @@
     public ChromiumUrlRequestFactory(Context context, CronetEngine.Builder config) {
         if (isEnabled()) {
             String userAgent = config.getUserAgent();
-            if (userAgent.isEmpty()) {
+            if (userAgent == null) {
                 // Cannot use config.getDefaultUserAgent() as config.mContext may be null.
                 userAgent = new CronetEngine.Builder(context).getDefaultUserAgent();
             }
diff --git a/components/cronet/android/java/src/org/chromium/net/CronetEngineBuilderList.template b/components/cronet/android/java/src/org/chromium/net/CronetEngineBuilderList.template
deleted file mode 100644
index f30a09f..0000000
--- a/components/cronet/android/java/src/org/chromium/net/CronetEngineBuilderList.template
+++ /dev/null
@@ -1,14 +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.
-
-package org.chromium.net;
-
-// A simple auto-generated interface used to list config params as used by
-// both org.chromium.net.CronetEngine.Builder and
-// components/cronet/url_request_context_config.h
-public interface CronetEngineBuilderList {
-#define DEFINE_CONTEXT_CONFIG(x) public static final String x = #x;
-#include "components/cronet/url_request_context_config_list.h"
-#undef DEFINE_CONTEXT_CONFIG
-}
diff --git a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
index 227bd41..90f9730 100644
--- a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
+++ b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
@@ -73,7 +73,8 @@
     public CronetUrlRequestContext(CronetEngine.Builder builder) {
         CronetLibraryLoader.ensureInitialized(builder.getContext(), builder);
         nativeSetMinLogLevel(getLoggingLevel());
-        mUrlRequestContextAdapter = nativeCreateRequestContextAdapter(builder.toJSONString());
+        mUrlRequestContextAdapter =
+                nativeCreateRequestContextAdapter(createNativeUrlRequestContextConfig(builder));
         if (mUrlRequestContextAdapter == 0) {
             throw new NullPointerException("Context Adapter creation failed.");
         }
@@ -98,6 +99,25 @@
         }
     }
 
+    static long createNativeUrlRequestContextConfig(CronetEngine.Builder builder) {
+        final long urlRequestContextConfig = nativeCreateRequestContextConfig(
+                builder.getUserAgent(), builder.storagePath(), builder.quicEnabled(),
+                builder.http2Enabled(), builder.sdchEnabled(), builder.dataReductionProxyKey(),
+                builder.dataReductionProxyPrimaryProxy(), builder.dataReductionProxyFallbackProxy(),
+                builder.dataReductionProxySecureProxyCheckUrl(), builder.cacheDisabled(),
+                builder.httpCacheMode(), builder.httpCacheMaxSize(), builder.experimentalOptions(),
+                builder.mockCertVerifier());
+        for (Builder.QuicHint quicHint : builder.quicHints()) {
+            nativeAddQuicHint(urlRequestContextConfig, quicHint.mHost, quicHint.mPort,
+                    quicHint.mAlternatePort);
+        }
+        for (Builder.Pkp pkp : builder.publicKeyPins()) {
+            nativeAddPkp(urlRequestContextConfig, pkp.mHost, pkp.mHashes, pkp.mIncludeSubdomains,
+                    pkp.mExpirationDate.getTime());
+        }
+        return urlRequestContextConfig;
+    }
+
     @Override
     public UrlRequest createRequest(String url, UrlRequest.Callback callback, Executor executor) {
         synchronized (mLock) {
@@ -400,7 +420,20 @@
     }
 
     // Native methods are implemented in cronet_url_request_context_adapter.cc.
-    private static native long nativeCreateRequestContextAdapter(String config);
+    private static native long nativeCreateRequestContextConfig(String userAgent,
+            String storagePath, boolean quicEnabled, boolean http2Enabled, boolean sdchEnabled,
+            String dataReductionProxyKey, String dataReductionProxyPrimaryProxy,
+            String dataReductionProxyFallbackProxy, String dataReductionProxySecureProxyCheckUrl,
+            boolean disableCache, int httpCacheMode, long httpCacheMaxSize,
+            String experimentalOptions, long mockCertVerifier);
+
+    private static native void nativeAddQuicHint(
+            long urlRequestContextConfig, String host, int port, int alternatePort);
+
+    private static native void nativeAddPkp(long urlRequestContextConfig, String host,
+            byte[][] hashes, boolean includeSubdomains, long expirationTime);
+
+    private static native long nativeCreateRequestContextAdapter(long urlRequestContextConfig);
 
     private static native int nativeSetMinLogLevel(int loggingLevel);
 
diff --git a/components/cronet/android/test/cronet_test_jni.cc b/components/cronet/android/test/cronet_test_jni.cc
index 3ef8879c..7a95b9a 100644
--- a/components/cronet/android/test/cronet_test_jni.cc
+++ b/components/cronet/android/test/cronet_test_jni.cc
@@ -8,6 +8,7 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_registrar.h"
 #include "components/cronet/android/cronet_library_loader.h"
+#include "cronet_url_request_context_config_test.h"
 #include "mock_cert_verifier.h"
 #include "mock_url_request_job_factory.h"
 #include "native_test_server.h"
@@ -27,6 +28,8 @@
     {"SdchTestUtil", cronet::RegisterSdchTestUtil},
     {"TestUploadDataStreamHandlerRegisterJni",
      cronet::TestUploadDataStreamHandlerRegisterJni},
+    {"CronetUrlRequestContextConfigTest",
+     cronet::RegisterCronetUrlRequestContextConfigTest},
 };
 
 }  // namespace
diff --git a/components/cronet/android/test/cronet_url_request_context_config_test.cc b/components/cronet/android/test/cronet_url_request_context_config_test.cc
new file mode 100644
index 0000000..c879fe97
--- /dev/null
+++ b/components/cronet/android/test/cronet_url_request_context_config_test.cc
@@ -0,0 +1,52 @@
+// 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 "cronet_url_request_context_config_test.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/logging.h"
+#include "components/cronet/url_request_context_config.h"
+#include "jni/CronetUrlRequestContextTest_jni.h"
+
+namespace cronet {
+
+// Verifies that all the configuration options set by
+// CronetUrlRequestContextTest.testCronetEngineBuilderConfig
+// made it from the CronetEngine.Builder to the URLRequestContextConfig.
+static void VerifyUrlRequestContextConfig(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& jcaller,
+    jlong jurl_request_context_config,
+    const JavaParamRef<jstring>& jstorage_path) {
+  URLRequestContextConfig* config =
+      reinterpret_cast<URLRequestContextConfig*>(jurl_request_context_config);
+  CHECK_EQ(config->enable_spdy, false);
+  CHECK_EQ(config->enable_quic, true);
+  CHECK_EQ(config->enable_sdch, true);
+  CHECK_EQ(config->quic_hints.size(), 1u);
+  CHECK_EQ((*config->quic_hints.begin())->host, "example.com");
+  CHECK_EQ((*config->quic_hints.begin())->port, 12);
+  CHECK_EQ((*config->quic_hints.begin())->alternate_port, 34);
+  CHECK_EQ(config->load_disable_cache, false);
+  CHECK_EQ(config->http_cache, URLRequestContextConfig::HttpCacheType::MEMORY);
+  CHECK_EQ(config->http_cache_max_size, 54321);
+  CHECK_EQ(config->data_reduction_proxy_key, "abcd");
+  CHECK_EQ(config->user_agent, "efgh");
+  CHECK_EQ(config->experimental_options, "ijkl");
+  CHECK_EQ(config->data_reduction_primary_proxy, "mnop");
+  CHECK_EQ(config->data_reduction_fallback_proxy, "qrst");
+  CHECK_EQ(config->data_reduction_secure_proxy_check_url, "uvwx");
+  CHECK_EQ(config->storage_path,
+           base::android::ConvertJavaStringToUTF8(env, jstorage_path));
+}
+
+bool RegisterCronetUrlRequestContextConfigTest(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace cronet
\ No newline at end of file
diff --git a/components/cronet/android/test/cronet_url_request_context_config_test.h b/components/cronet/android/test/cronet_url_request_context_config_test.h
new file mode 100644
index 0000000..ff6f3ac
--- /dev/null
+++ b/components/cronet/android/test/cronet_url_request_context_config_test.h
@@ -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.
+
+#ifndef COMPONENTS_CRONET_ANDROID_TEST_CRONET_URL_REQUEST_CONTEXT_CONFIG_TEST_H_
+#define COMPONENTS_CRONET_ANDROID_TEST_CRONET_URL_REQUEST_CONTEXT_CONFIG_TEST_H_
+
+#include <jni.h>
+
+namespace cronet {
+
+bool RegisterCronetUrlRequestContextConfigTest(JNIEnv* env);
+
+}  // namespace cronet
+
+#endif  // COMPONENTS_CRONET_ANDROID_TEST_CRONET_URL_REQUEST_CONTEXT_CONFIG_TEST_H_
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetTestBase.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetTestBase.java
index bd22a6d..59aad243 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetTestBase.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetTestBase.java
@@ -22,11 +22,14 @@
     private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "cronet_test";
 
     private CronetTestFramework mCronetTestFramework;
+    // {@code true} when test is being run against system HttpURLConnection implementation.
+    private boolean mTestingSystemHttpURLConnection;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
         PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX, getContext());
+        CronetTestFramework.prepareTestStorage(getContext());
     }
 
     /**
@@ -85,8 +88,16 @@
         return mCronetTestFramework;
     }
 
+    /**
+     * Returns {@code true} when test is being run against system HttpURLConnection implementation.
+     */
+    protected boolean testingSystemHttpURLConnection() {
+        return mTestingSystemHttpURLConnection;
+    }
+
     @Override
     protected void runTest() throws Throwable {
+        mTestingSystemHttpURLConnection = false;
         if (!getClass().getPackage().getName().equals(
                 "org.chromium.net.urlconnection")) {
             super.runTest();
@@ -96,8 +107,10 @@
             Method method = getClass().getMethod(getName(), (Class[]) null);
             if (method.isAnnotationPresent(CompareDefaultWithCronet.class)) {
                 // Run with the default HttpURLConnection implementation first.
+                mTestingSystemHttpURLConnection = true;
                 super.runTest();
                 // Use Cronet's implementation, and run the same test.
+                mTestingSystemHttpURLConnection = false;
                 URL.setURLStreamHandlerFactory(mCronetTestFramework.mStreamHandlerFactory);
                 super.runTest();
             } else if (method.isAnnotationPresent(
@@ -114,6 +127,31 @@
         }
     }
 
+    /**
+     * Registers test host resolver for testing with the new API.
+     */
+    protected void registerHostResolver(CronetTestFramework framework) {
+        registerHostResolver(framework, false);
+    }
+
+    /**
+     * Registers test host resolver.
+     *
+     * @param isLegacyAPI true if the test should use the legacy API.
+     */
+    protected void registerHostResolver(CronetTestFramework framework, boolean isLegacyAPI) {
+        long urlRequestContextAdapter;
+        if (isLegacyAPI) {
+            urlRequestContextAdapter = ((ChromiumUrlRequestFactory) framework.mRequestFactory)
+                                               .getRequestContext()
+                                               .getUrlRequestContextAdapter();
+        } else {
+            urlRequestContextAdapter = ((CronetUrlRequestContext) framework.mCronetEngine)
+                                               .getUrlRequestContextAdapter();
+        }
+        NativeTestServer.registerHostResolverProc(urlRequestContextAdapter, isLegacyAPI);
+    }
+
     @Target(ElementType.METHOD)
     @Retention(RetentionPolicy.RUNTIME)
     public @interface CompareDefaultWithCronet {
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
index be329db2..32c28aa 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
@@ -12,6 +12,7 @@
 import android.test.suitebuilder.annotation.SmallTest;
 
 import org.chromium.base.PathUtils;
+import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.test.util.Feature;
 import org.chromium.net.TestUrlRequestCallback.ResponseStep;
 
@@ -26,6 +27,7 @@
 /**
  * Test CronetEngine.
  */
+@JNINamespace("cronet")
 public class CronetUrlRequestContextTest extends CronetTestBase {
     // URLs used for tests.
     private static final String TEST_URL = "http://127.0.0.1:8000";
@@ -791,4 +793,30 @@
         assertTrue(delta2.length != 0);
         assertFalse(Arrays.equals(delta1, delta2));
     }
+
+    @SmallTest
+    @Feature({"Cronet"})
+    public void testCronetEngineBuilderConfig() throws Exception {
+        // This is to prompt load of native library.
+        startCronetTestFramework();
+        // Verify CronetEngine.Builder config is passed down accurately to native code.
+        CronetEngine.Builder builder = new CronetEngine.Builder(getContext());
+        builder.enableHTTP2(false);
+        builder.enableQUIC(true);
+        builder.enableSDCH(true);
+        builder.addQuicHint("example.com", 12, 34);
+        builder.enableHttpCache(CronetEngine.Builder.HTTP_CACHE_IN_MEMORY, 54321);
+        builder.enableDataReductionProxy("abcd");
+        builder.setUserAgent("efgh");
+        builder.setExperimentalOptions("ijkl");
+        builder.setDataReductionProxyOptions("mnop", "qrst", "uvwx");
+        builder.setStoragePath(CronetTestFramework.getTestStorage(getContext()));
+        nativeVerifyUrlRequestContextConfig(
+                CronetUrlRequestContext.createNativeUrlRequestContextConfig(builder),
+                CronetTestFramework.getTestStorage(getContext()));
+    }
+
+    // Verifies that CronetEngine.Builder config from testCronetEngineBuilderConfig() is properly
+    // translated to a native UrlRequestContextConfig.
+    private static native void nativeVerifyUrlRequestContextConfig(long config, String storagePath);
 }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/HttpUrlRequestFactoryTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/HttpUrlRequestFactoryTest.java
index 9defc4a..228efc0a 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/HttpUrlRequestFactoryTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/HttpUrlRequestFactoryTest.java
@@ -179,7 +179,7 @@
             config.enableHttpCache(HttpUrlRequestFactoryConfig.HTTP_CACHE_IN_MEMORY, 0);
             fail("IllegalArgumentException must be thrown");
         } catch (IllegalArgumentException e) {
-            assertEquals("Storage path must be empty", e.getMessage());
+            assertEquals("Storage path must not be set", e.getMessage());
         }
         assertTrue(dir.delete());
     }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/PkpTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/PkpTest.java
index b810c656..1b6107b 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/PkpTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/PkpTest.java
@@ -66,7 +66,7 @@
         byte[] nonMatchingHash = generateSomeSha256();
         addPkpSha256(mServerHost, nonMatchingHash, EXCLUDE_SUBDOMAINS, DISTANT_FUTURE);
         startCronetFramework();
-        registerHostResolver();
+        registerHostResolver(mTestFramework);
         sendRequestAndWaitForResult();
 
         assertErrorResponse();
@@ -87,7 +87,7 @@
 
         addPkpSha256(mServerHost, matchingHash, EXCLUDE_SUBDOMAINS, DISTANT_FUTURE);
         startCronetFramework();
-        registerHostResolver();
+        registerHostResolver(mTestFramework);
         sendRequestAndWaitForResult();
 
         assertSuccessfulResponse();
@@ -106,7 +106,7 @@
         byte[] nonMatchingHash = generateSomeSha256();
         addPkpSha256(mDomain, nonMatchingHash, INCLUDE_SUBDOMAINS, DISTANT_FUTURE);
         startCronetFramework();
-        registerHostResolver();
+        registerHostResolver(mTestFramework);
         sendRequestAndWaitForResult();
 
         assertErrorResponse();
@@ -125,7 +125,7 @@
         byte[] nonMatchingHash = generateSomeSha256();
         addPkpSha256(mDomain, nonMatchingHash, EXCLUDE_SUBDOMAINS, DISTANT_FUTURE);
         startCronetFramework();
-        registerHostResolver();
+        registerHostResolver(mTestFramework);
         sendRequestAndWaitForResult();
 
         assertSuccessfulResponse();
@@ -144,7 +144,7 @@
         byte[] nonMatchingHash = generateSomeSha256();
         addPkpSha256("otherhost.com", nonMatchingHash, INCLUDE_SUBDOMAINS, DISTANT_FUTURE);
         startCronetFramework();
-        registerHostResolver();
+        registerHostResolver(mTestFramework);
         sendRequestAndWaitForResult();
 
         assertSuccessfulResponse();
@@ -163,7 +163,7 @@
         byte[] nonMatchingHash = generateSomeSha256();
         addPkpSha256(mServerHost, nonMatchingHash, EXCLUDE_SUBDOMAINS, tenSecondsAhead);
         startCronetFramework();
-        registerHostResolver();
+        registerHostResolver(mTestFramework);
         sendRequestAndWaitForResult();
 
         assertErrorResponse();
@@ -182,7 +182,7 @@
         byte[] nonMatchingHash = generateSomeSha256();
         addPkpSha256(mServerHost, nonMatchingHash, EXCLUDE_SUBDOMAINS, oneSecondAgo);
         startCronetFramework();
-        registerHostResolver();
+        registerHostResolver(mTestFramework);
         sendRequestAndWaitForResult();
 
         assertSuccessfulResponse();
@@ -199,7 +199,7 @@
         byte[] nonMatchingHash = generateSomeSha256();
         addPkpSha256(mServerHost, nonMatchingHash, EXCLUDE_SUBDOMAINS, DISTANT_FUTURE);
         startCronetFramework();
-        registerHostResolver();
+        registerHostResolver(mTestFramework);
         sendRequestAndWaitForResult();
         assertErrorResponse();
         shutdownCronetEngine();
@@ -208,7 +208,7 @@
         // a successful response is expected.
         createCronetEngineBuilder();
         startCronetFramework();
-        registerHostResolver();
+        registerHostResolver(mTestFramework);
         sendRequestAndWaitForResult();
         assertSuccessfulResponse();
     }
@@ -347,12 +347,6 @@
         }
     }
 
-    private void registerHostResolver() {
-        long urlRequestContextAdapter = ((CronetUrlRequestContext) mTestFramework.mCronetEngine)
-                                                .getUrlRequestContextAdapter();
-        NativeTestServer.registerHostResolverProc(urlRequestContextAdapter, false);
-    }
-
     private byte[] generateSomeSha256() {
         byte[] sha256 = new byte[32];
         Arrays.fill(sha256, (byte) 58);
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
index 0df78f9..902797d 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
@@ -66,11 +66,7 @@
         String[] commandLineArgs = {
                 CronetTestFramework.LIBRARY_INIT_KEY, CronetTestFramework.LibraryInitType.LEGACY};
         mTestFramework = new CronetTestFramework(null, commandLineArgs, getContext(), mBuilder);
-
-        long urlRequestContextAdapter = ((ChromiumUrlRequestFactory) mTestFramework.mRequestFactory)
-                                                .getRequestContext()
-                                                .getUrlRequestContextAdapter();
-        NativeTestServer.registerHostResolverProc(urlRequestContextAdapter, true);
+        registerHostResolver(mTestFramework, true);
         String quicURL = QuicTestServer.getServerURL() + "/simple.txt";
 
         HashMap<String, String> headers = new HashMap<String, String>();
@@ -94,14 +90,8 @@
     @LargeTest
     @Feature({"Cronet"})
     public void testQuicLoadUrl() throws Exception {
-        String[] commandLineArgs = {
-                CronetTestFramework.LIBRARY_INIT_KEY, CronetTestFramework.LibraryInitType.CRONET};
-        mTestFramework = new CronetTestFramework(null, commandLineArgs, getContext(), mBuilder);
-
-        long urlRequestContextAdapter = ((CronetUrlRequestContext) mTestFramework.mCronetEngine)
-                                                .getUrlRequestContextAdapter();
-        NativeTestServer.registerHostResolverProc(urlRequestContextAdapter, false);
-
+        mTestFramework = startCronetTestFrameworkWithUrlAndCronetEngineBuilder(null, mBuilder);
+        registerHostResolver(mTestFramework);
         String quicURL = QuicTestServer.getServerURL() + "/simple.txt";
         TestUrlRequestCallback callback = new TestUrlRequestCallback();
 
@@ -145,13 +135,11 @@
         builder.enableHttpCache(CronetEngine.Builder.HTTP_CACHE_DISK, 1000 * 1024);
         builder.enableQUIC(true);
         builder.setMockCertVerifierForTesting(MockCertVerifier.createMockCertVerifier(CERTS_USED));
-        CronetEngine newEngine = new CronetUrlRequestContext(builder);
-        long newUrlRequestContextAdapter =
-                ((CronetUrlRequestContext) newEngine).getUrlRequestContextAdapter();
-        NativeTestServer.registerHostResolverProc(newUrlRequestContextAdapter, false);
+        mTestFramework = startCronetTestFrameworkWithUrlAndCronetEngineBuilder(null, builder);
+        registerHostResolver(mTestFramework);
         TestUrlRequestCallback callback2 = new TestUrlRequestCallback();
-        requestBuilder =
-                new UrlRequest.Builder(quicURL, callback2, callback2.getExecutor(), newEngine);
+        requestBuilder = new UrlRequest.Builder(
+                quicURL, callback2, callback2.getExecutor(), mTestFramework.mCronetEngine);
         requestBuilder.build().start();
         callback2.blockForDone();
         assertEquals(200, callback2.mResponseInfo.getHttpStatusCode());
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/SdchTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/SdchTest.java
index d7f0932..eaf6265 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/SdchTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/SdchTest.java
@@ -55,10 +55,7 @@
         String[] args = new String[commandLineArgs.size()];
         mTestFramework = startCronetTestFrameworkWithUrlAndCommandLineArgs(
                 null, commandLineArgs.toArray(args));
-        long urlRequestContextAdapter = (api == Api.LEGACY)
-                ? getContextAdapter((ChromiumUrlRequestFactory) mTestFramework.mRequestFactory)
-                : getContextAdapter((CronetUrlRequestContext) mTestFramework.mCronetEngine);
-        NativeTestServer.registerHostResolverProc(urlRequestContextAdapter, api == Api.LEGACY);
+        registerHostResolver(mTestFramework, api == Api.LEGACY);
         // Start NativeTestServer.
         assertTrue(NativeTestServer.startNativeTestServer(getContext()));
     }
@@ -173,11 +170,11 @@
         assertTrue(fileContainsString("local_prefs.json", dictUrl));
 
         // Test persistence.
-        CronetUrlRequestContext newContext =
-                new CronetUrlRequestContext(mTestFramework.getCronetEngineBuilder());
-
+        mTestFramework = startCronetTestFrameworkWithUrlAndCronetEngineBuilder(
+                null, mTestFramework.getCronetEngineBuilder());
+        CronetUrlRequestContext newContext = (CronetUrlRequestContext) mTestFramework.mCronetEngine;
         long newContextAdapter = getContextAdapter(newContext);
-        NativeTestServer.registerHostResolverProc(newContextAdapter, false);
+        registerHostResolver(mTestFramework);
         DictionaryAddedObserver newObserver =
                 new DictionaryAddedObserver(targetUrl, newContextAdapter, false /** Legacy Api */);
         newObserver.waitForDictionaryAdded();
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java
index 33e2afd..012d80bb 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java
@@ -811,11 +811,15 @@
         HttpURLConnection connection =
                 (HttpURLConnection) url.openConnection();
         connection.setInstanceFollowRedirects(false);
-        assertEquals(302, connection.getResponseCode());
-        assertEquals("Found", connection.getResponseMessage());
-        assertEquals("/success.txt", connection.getHeaderField("Location"));
-        assertEquals(NativeTestServer.getFileURL("/redirect.html"),
-                connection.getURL().toString());
+        // Redirect following control broken in Android Marshmallow:
+        // https://code.google.com/p/android/issues/detail?id=194495
+        if (!testingSystemHttpURLConnection() || Build.VERSION.SDK_INT != Build.VERSION_CODES.M) {
+            assertEquals(302, connection.getResponseCode());
+            assertEquals("Found", connection.getResponseMessage());
+            assertEquals("/success.txt", connection.getHeaderField("Location"));
+            assertEquals(
+                    NativeTestServer.getFileURL("/redirect.html"), connection.getURL().toString());
+        }
         connection.disconnect();
     }
 
@@ -827,11 +831,15 @@
         URL url = new URL(NativeTestServer.getFileURL("/redirect.html"));
         HttpURLConnection connection =
                 (HttpURLConnection) url.openConnection();
-        assertEquals(302, connection.getResponseCode());
-        assertEquals("Found", connection.getResponseMessage());
-        assertEquals("/success.txt", connection.getHeaderField("Location"));
-        assertEquals(NativeTestServer.getFileURL("/redirect.html"),
-                connection.getURL().toString());
+        // Redirect following control broken in Android Marshmallow:
+        // https://code.google.com/p/android/issues/detail?id=194495
+        if (!testingSystemHttpURLConnection() || Build.VERSION.SDK_INT != Build.VERSION_CODES.M) {
+            assertEquals(302, connection.getResponseCode());
+            assertEquals("Found", connection.getResponseMessage());
+            assertEquals("/success.txt", connection.getHeaderField("Location"));
+            assertEquals(
+                    NativeTestServer.getFileURL("/redirect.html"), connection.getURL().toString());
+        }
         connection.disconnect();
     }
 
@@ -884,8 +892,16 @@
         connection.setInstanceFollowRedirects(true);
         assertEquals(302, connection.getResponseCode());
         assertEquals("Found", connection.getResponseMessage());
-        // Redirect is not followed, but the url is updated to the Location header.
-        assertEquals("https://127.0.0.1:8000/success.txt", connection.getURL().toString());
+        // Behavior changed in Android Marshmallow to not update the URL.
+        if (testingSystemHttpURLConnection() && Build.VERSION.SDK_INT == Build.VERSION_CODES.M) {
+            // Redirected port is randomized, verify everything but port.
+            assertEquals(url.getProtocol(), connection.getURL().getProtocol());
+            assertEquals(url.getHost(), connection.getURL().getHost());
+            assertEquals(url.getFile(), connection.getURL().getFile());
+        } else {
+            // Redirect is not followed, but the url is updated to the Location header.
+            assertEquals("https://127.0.0.1:8000/success.txt", connection.getURL().toString());
+        }
         connection.disconnect();
     }
 
diff --git a/components/cronet/android/test/src/org/chromium/net/CronetTestFramework.java b/components/cronet/android/test/src/org/chromium/net/CronetTestFramework.java
index a1a759a1..3c625a7 100644
--- a/components/cronet/android/test/src/org/chromium/net/CronetTestFramework.java
+++ b/components/cronet/android/test/src/org/chromium/net/CronetTestFramework.java
@@ -105,7 +105,6 @@
             String appUrl, String[] commandLine, Context context, CronetEngine.Builder builder) {
         mCommandLine = commandLine;
         mContext = context;
-        prepareTestStorage();
 
         // Print out extra arguments passed in starting this activity.
         if (commandLine != null) {
@@ -149,12 +148,12 @@
     /**
      * Prepares the path for the test storage (http cache, QUIC server info).
      */
-    private void prepareTestStorage() {
-        File storage = new File(getTestStorageDirectory(mContext));
+    public static void prepareTestStorage(Context context) {
+        File storage = new File(getTestStorageDirectory(context));
         if (storage.exists()) {
             assertTrue(recursiveDelete(storage));
         }
-        ensureTestStorageExists(mContext);
+        ensureTestStorageExists(context);
     }
 
     /**
@@ -185,7 +184,7 @@
     }
 
     @SuppressFBWarnings("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE")
-    private boolean recursiveDelete(File path) {
+    private static boolean recursiveDelete(File path) {
         if (path.isDirectory()) {
             for (File c : path.listFiles()) {
                 if (!recursiveDelete(c)) {
diff --git a/components/cronet/android/url_request_context_adapter.cc b/components/cronet/android/url_request_context_adapter.cc
index c58bff15..1eaefe1 100644
--- a/components/cronet/android/url_request_context_adapter.cc
+++ b/components/cronet/android/url_request_context_adapter.cc
@@ -150,7 +150,7 @@
   context_builder.set_network_delegate(
       make_scoped_ptr(new BasicNetworkDelegate()));
   context_builder.set_proxy_config_service(proxy_config_service_.Pass());
-  config_->ConfigureURLRequestContextBuilder(&context_builder);
+  config_->ConfigureURLRequestContextBuilder(&context_builder, nullptr);
 
   context_ = context_builder.Build().Pass();
 
diff --git a/components/cronet/cronet_static.gypi b/components/cronet/cronet_static.gypi
index cf62a0a..e659c85 100644
--- a/components/cronet/cronet_static.gypi
+++ b/components/cronet/cronet_static.gypi
@@ -8,7 +8,6 @@
     '../base/base.gyp:base',
     '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
     'cronet_jni_headers',
-    'cronet_engine_builder_list',
     'cronet_url_request_java',
     'cronet_version',
     'cronet_version_header',
diff --git a/components/cronet/url_request_context_config.cc b/components/cronet/url_request_context_config.cc
index 2845bc8..63c25a40 100644
--- a/components/cronet/url_request_context_config.cc
+++ b/components/cronet/url_request_context_config.cc
@@ -4,13 +4,14 @@
 
 #include "components/cronet/url_request_context_config.h"
 
-#include "base/basictypes.h"
 #include "base/json/json_reader.h"
+#include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/values.h"
 #include "net/cert/cert_verifier.h"
+#include "net/dns/host_resolver.h"
 #include "net/quic/quic_protocol.h"
 #include "net/quic/quic_utils.h"
 #include "net/url_request/url_request_context_builder.h"
@@ -29,21 +30,15 @@
     "max_number_of_lossy_connections";
 const char kQuicPacketLossThreshold[] = "packet_loss_threshold";
 
-// Using a reference to scoped_ptr is unavoidable because of the semantics of
-// RegisterCustomField.
-// TODO(xunjieli): Remove this once crbug.com/544976 is fixed.
-bool GetMockCertVerifierFromString(
-    const base::StringPiece& mock_cert_verifier_string,
-    scoped_ptr<net::CertVerifier>* result) {
-  int64 val;
-  bool success = base::StringToInt64(mock_cert_verifier_string, &val);
-  *result = make_scoped_ptr(reinterpret_cast<net::CertVerifier*>(val));
-  return success;
-}
+// AsyncDNS experiment dictionary name.
+const char kAsyncDnsFieldTrialName[] = "AsyncDNS";
+// Name of boolean to enable AsyncDNS experiment.
+const char kAsyncDnsEnable[] = "enable";
 
 void ParseAndSetExperimentalOptions(
     const std::string& experimental_options,
-    net::URLRequestContextBuilder* context_builder) {
+    net::URLRequestContextBuilder* context_builder,
+    net::NetLog* net_log) {
   if (experimental_options.empty())
     return;
 
@@ -101,85 +96,82 @@
           quic_packet_loss_threshold);
     }
   }
-}
 
-bool GetTimeFromDouble(const base::Value* json_value, base::Time* time) {
-  double time_double;
-  bool success = json_value->GetAsDouble(&time_double);
-  if (success) {
-    *time = base::Time::FromDoubleT(time_double);
+  const base::DictionaryValue* async_dns_args = nullptr;
+  if (dict->GetDictionary(kAsyncDnsFieldTrialName, &async_dns_args)) {
+    bool async_dns_enable = false;
+    if (async_dns_args->GetBoolean(kAsyncDnsEnable, &async_dns_enable) &&
+        async_dns_enable) {
+      if (net_log == nullptr) {
+        DCHECK(false) << "AsyncDNS experiment requires NetLog.";
+      } else {
+        scoped_ptr<net::HostResolver> host_resolver(
+            net::HostResolver::CreateDefaultResolver(net_log));
+        host_resolver->SetDnsClientEnabled(true);
+        context_builder->set_host_resolver(std::move(host_resolver));
+      }
+    }
   }
-  return success;
 }
 
 }  // namespace
 
-#define DEFINE_CONTEXT_CONFIG(x) const char REQUEST_CONTEXT_CONFIG_##x[] = #x;
-#include "components/cronet/url_request_context_config_list.h"
-#undef DEFINE_CONTEXT_CONFIG
-
-URLRequestContextConfig::QuicHint::QuicHint() {}
+URLRequestContextConfig::QuicHint::QuicHint(const std::string& host,
+                                            int port,
+                                            int alternate_port)
+    : host(host), port(port), alternate_port(alternate_port) {}
 
 URLRequestContextConfig::QuicHint::~QuicHint() {}
 
-// static
-void URLRequestContextConfig::QuicHint::RegisterJSONConverter(
-    base::JSONValueConverter<URLRequestContextConfig::QuicHint>* converter) {
-  converter->RegisterStringField(REQUEST_CONTEXT_CONFIG_QUIC_HINT_HOST,
-                                 &URLRequestContextConfig::QuicHint::host);
-  converter->RegisterIntField(
-      REQUEST_CONTEXT_CONFIG_QUIC_HINT_PORT,
-      &URLRequestContextConfig::QuicHint::port);
-  converter->RegisterIntField(
-      REQUEST_CONTEXT_CONFIG_QUIC_HINT_ALT_PORT,
-      &URLRequestContextConfig::QuicHint::alternate_port);
-}
-
-URLRequestContextConfig::Pkp::Pkp() {}
+URLRequestContextConfig::Pkp::Pkp(const std::string& host,
+                                  bool include_subdomains,
+                                  const base::Time& expiration_date)
+    : host(host),
+      include_subdomains(include_subdomains),
+      expiration_date(expiration_date) {}
 
 URLRequestContextConfig::Pkp::~Pkp() {}
 
-// static
-void URLRequestContextConfig::Pkp::RegisterJSONConverter(
-    base::JSONValueConverter<URLRequestContextConfig::Pkp>* converter) {
-  converter->RegisterStringField(REQUEST_CONTEXT_CONFIG_PKP_HOST,
-                                 &URLRequestContextConfig::Pkp::host);
-  converter->RegisterRepeatedString(REQUEST_CONTEXT_CONFIG_PKP_PIN_HASHES,
-                                    &URLRequestContextConfig::Pkp::pin_hashes);
-  converter->RegisterBoolField(
-      REQUEST_CONTEXT_CONFIG_PKP_INCLUDE_SUBDOMAINS,
-      &URLRequestContextConfig::Pkp::include_subdomains);
-  converter->RegisterCustomValueField<base::Time>(
-      REQUEST_CONTEXT_CONFIG_PKP_EXPIRATION_DATE,
-      &URLRequestContextConfig::Pkp::expiration_date, &GetTimeFromDouble);
-}
-
-URLRequestContextConfig::URLRequestContextConfig() {}
+URLRequestContextConfig::URLRequestContextConfig(
+    bool enable_quic,
+    bool enable_spdy,
+    bool enable_sdch,
+    HttpCacheType http_cache,
+    int http_cache_max_size,
+    bool load_disable_cache,
+    const std::string& storage_path,
+    const std::string& user_agent,
+    const std::string& experimental_options,
+    const std::string& data_reduction_proxy_key,
+    const std::string& data_reduction_primary_proxy,
+    const std::string& data_reduction_fallback_proxy,
+    const std::string& data_reduction_secure_proxy_check_url,
+    scoped_ptr<net::CertVerifier> mock_cert_verifier)
+    : enable_quic(enable_quic),
+      enable_spdy(enable_spdy),
+      enable_sdch(enable_sdch),
+      http_cache(http_cache),
+      http_cache_max_size(http_cache_max_size),
+      load_disable_cache(load_disable_cache),
+      storage_path(storage_path),
+      user_agent(user_agent),
+      experimental_options(experimental_options),
+      data_reduction_proxy_key(data_reduction_proxy_key),
+      data_reduction_primary_proxy(data_reduction_primary_proxy),
+      data_reduction_fallback_proxy(data_reduction_fallback_proxy),
+      data_reduction_secure_proxy_check_url(
+          data_reduction_secure_proxy_check_url),
+      mock_cert_verifier(std::move(mock_cert_verifier)) {}
 
 URLRequestContextConfig::~URLRequestContextConfig() {}
 
-bool URLRequestContextConfig::LoadFromJSON(const std::string& config_string) {
-  scoped_ptr<base::Value> config_value = base::JSONReader::Read(config_string);
-  if (!config_value || !config_value->IsType(base::Value::TYPE_DICTIONARY)) {
-    DLOG(ERROR) << "Bad JSON: " << config_string;
-    return false;
-  }
-
-  base::JSONValueConverter<URLRequestContextConfig> converter;
-  if (!converter.Convert(*config_value, this)) {
-    DLOG(ERROR) << "Bad Config: " << config_value;
-    return false;
-  }
-  return true;
-}
-
 void URLRequestContextConfig::ConfigureURLRequestContextBuilder(
-    net::URLRequestContextBuilder* context_builder) {
+    net::URLRequestContextBuilder* context_builder,
+    net::NetLog* net_log) {
   std::string config_cache;
-  if (http_cache != REQUEST_CONTEXT_CONFIG_HTTP_CACHE_DISABLED) {
+  if (http_cache != DISABLED) {
     net::URLRequestContextBuilder::HttpCacheParams cache_params;
-    if (http_cache == REQUEST_CONTEXT_CONFIG_HTTP_CACHE_DISK &&
-        !storage_path.empty()) {
+    if (http_cache == DISK && !storage_path.empty()) {
       cache_params.type = net::URLRequestContextBuilder::HttpCacheParams::DISK;
       cache_params.path = base::FilePath(storage_path);
     } else {
@@ -195,57 +187,12 @@
   context_builder->SetSpdyAndQuicEnabled(enable_spdy, enable_quic);
   context_builder->set_sdch_enabled(enable_sdch);
 
-  ParseAndSetExperimentalOptions(experimental_options, context_builder);
+  ParseAndSetExperimentalOptions(experimental_options, context_builder,
+                                 net_log);
 
   if (mock_cert_verifier)
     context_builder->SetCertVerifier(mock_cert_verifier.Pass());
   // TODO(mef): Use |config| to set cookies.
 }
 
-// static
-void URLRequestContextConfig::RegisterJSONConverter(
-    base::JSONValueConverter<URLRequestContextConfig>* converter) {
-  converter->RegisterStringField(REQUEST_CONTEXT_CONFIG_USER_AGENT,
-                                 &URLRequestContextConfig::user_agent);
-  converter->RegisterStringField(REQUEST_CONTEXT_CONFIG_STORAGE_PATH,
-                                 &URLRequestContextConfig::storage_path);
-  converter->RegisterBoolField(REQUEST_CONTEXT_CONFIG_ENABLE_QUIC,
-                               &URLRequestContextConfig::enable_quic);
-  converter->RegisterBoolField(REQUEST_CONTEXT_CONFIG_ENABLE_SPDY,
-                               &URLRequestContextConfig::enable_spdy);
-  converter->RegisterBoolField(REQUEST_CONTEXT_CONFIG_ENABLE_SDCH,
-                               &URLRequestContextConfig::enable_sdch);
-  converter->RegisterStringField(REQUEST_CONTEXT_CONFIG_HTTP_CACHE,
-                                 &URLRequestContextConfig::http_cache);
-  converter->RegisterBoolField(REQUEST_CONTEXT_CONFIG_LOAD_DISABLE_CACHE,
-                               &URLRequestContextConfig::load_disable_cache);
-  converter->RegisterIntField(REQUEST_CONTEXT_CONFIG_HTTP_CACHE_MAX_SIZE,
-                              &URLRequestContextConfig::http_cache_max_size);
-  converter->RegisterRepeatedMessage(REQUEST_CONTEXT_CONFIG_QUIC_HINTS,
-                                     &URLRequestContextConfig::quic_hints);
-  converter->RegisterStringField(
-      REQUEST_CONTEXT_CONFIG_EXPERIMENTAL_OPTIONS,
-      &URLRequestContextConfig::experimental_options);
-  converter->RegisterStringField(
-      REQUEST_CONTEXT_CONFIG_DATA_REDUCTION_PRIMARY_PROXY,
-      &URLRequestContextConfig::data_reduction_primary_proxy);
-  converter->RegisterStringField(
-      REQUEST_CONTEXT_CONFIG_DATA_REDUCTION_FALLBACK_PROXY,
-      &URLRequestContextConfig::data_reduction_fallback_proxy);
-  converter->RegisterStringField(
-      REQUEST_CONTEXT_CONFIG_DATA_REDUCTION_SECURE_PROXY_CHECK_URL,
-      &URLRequestContextConfig::data_reduction_secure_proxy_check_url);
-  converter->RegisterStringField(
-      REQUEST_CONTEXT_CONFIG_DATA_REDUCTION_PROXY_KEY,
-      &URLRequestContextConfig::data_reduction_proxy_key);
-  converter->RegisterRepeatedMessage(REQUEST_CONTEXT_CONFIG_PKP_LIST,
-                                     &URLRequestContextConfig::pkp_list);
-
-  // For Testing.
-  converter->RegisterCustomField<scoped_ptr<net::CertVerifier>>(
-      REQUEST_CONTEXT_CONFIG_MOCK_CERT_VERIFIER,
-      &URLRequestContextConfig::mock_cert_verifier,
-      &GetMockCertVerifierFromString);
-}
-
 }  // namespace cronet
diff --git a/components/cronet/url_request_context_config.h b/components/cronet/url_request_context_config.h
index cf49138..29e1c85a 100644
--- a/components/cronet/url_request_context_config.h
+++ b/components/cronet/url_request_context_config.h
@@ -7,36 +7,44 @@
 
 #include <string>
 
-#include "base/json/json_value_converter.h"
 #include "base/macros.h"
 #include "base/memory/scoped_vector.h"
 #include "base/time/time.h"
+#include "net/base/hash_value.h"
 
 namespace net {
 class CertVerifier;
+class NetLog;
 class URLRequestContextBuilder;
 }  // namespace net
 
 namespace cronet {
 
 // Common configuration parameters used by Cronet to configure
-// URLRequestContext. Can be parsed from JSON string passed through JNI.
+// URLRequestContext.
 struct URLRequestContextConfig {
+  // Type of HTTP cache.
+  // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.net
+  enum HttpCacheType {
+    // No HTTP cache.
+    DISABLED,
+    // HTTP cache persisted to disk.
+    DISK,
+    // HTTP cache kept in memory.
+    MEMORY,
+  };
+
   // App-provided hint that server supports QUIC.
   struct QuicHint {
-    QuicHint();
+    QuicHint(const std::string& host, int port, int alternate_port);
     ~QuicHint();
 
-    // Register |converter| for use in converter.Convert().
-    static void RegisterJSONConverter(
-        base::JSONValueConverter<QuicHint>* converter);
-
     // Host name of the server that supports QUIC.
-    std::string host;
+    const std::string host;
     // Port of the server that supports QUIC.
-    int port;
+    const int port;
     // Alternate protocol port.
-    int alternate_port;
+    const int alternate_port;
 
    private:
     DISALLOW_COPY_AND_ASSIGN(QuicHint);
@@ -44,77 +52,100 @@
 
   // Public-Key-Pinning configuration structure.
   struct Pkp {
-    Pkp();
+    Pkp(const std::string& host,
+        bool include_subdomains,
+        const base::Time& expiration_date);
     ~Pkp();
 
-    // Register |converter| for use in converter.Convert().
-    static void RegisterJSONConverter(base::JSONValueConverter<Pkp>* converter);
-
     // Host name.
-    std::string host;
+    const std::string host;
     // Pin hashes (currently SHA256 only).
-    ScopedVector<std::string> pin_hashes;
+    net::HashValueVector pin_hashes;
     // Indicates whether the pinning should apply to the pinned host subdomains.
-    bool include_subdomains;
+    const bool include_subdomains;
     // Expiration date for the pins.
-    base::Time expiration_date;
+    const base::Time expiration_date;
 
    private:
     DISALLOW_COPY_AND_ASSIGN(Pkp);
   };
 
-  URLRequestContextConfig();
+  URLRequestContextConfig(
+      // Enable QUIC.
+      bool enable_quic,
+      // Enable SPDY.
+      bool enable_spdy,
+      // Enable SDCH.
+      bool enable_sdch,
+      // Type of http cache.
+      HttpCacheType http_cache,
+      // Max size of http cache in bytes.
+      int http_cache_max_size,
+      // Disable caching for HTTP responses. Other information may be stored in
+      // the cache.
+      bool load_disable_cache,
+      // Storage path for http cache and cookie storage.
+      const std::string& storage_path,
+      // User-Agent request header field.
+      const std::string& user_agent,
+      // JSON encoded experimental options.
+      const std::string& experimental_options,
+      // Data reduction proxy key.
+      const std::string& data_reduction_proxy_key,
+      // Data reduction proxy.
+      const std::string& data_reduction_primary_proxy,
+      // Fallback data reduction proxy.
+      const std::string& data_reduction_fallback_proxy,
+      // Data reduction proxy secure proxy check URL.
+      const std::string& data_reduction_secure_proxy_check_url,
+      // MockCertVerifier to use for testing purposes.
+      scoped_ptr<net::CertVerifier> mock_cert_verifier);
   ~URLRequestContextConfig();
 
-  // Load config values from JSON format.
-  bool LoadFromJSON(const std::string& config_string);
-
   // Configure |context_builder| based on |this|.
   void ConfigureURLRequestContextBuilder(
-      net::URLRequestContextBuilder* context_builder);
-
-  // Register |converter| for use in converter.Convert().
-  static void RegisterJSONConverter(
-      base::JSONValueConverter<URLRequestContextConfig>* converter);
+      net::URLRequestContextBuilder* context_builder,
+      net::NetLog* net_log);
 
   // Enable QUIC.
-  bool enable_quic;
+  const bool enable_quic;
   // Enable SPDY.
-  bool enable_spdy;
+  const bool enable_spdy;
   // Enable SDCH.
-  bool enable_sdch;
-  // Type of http cache: "HTTP_CACHE_DISABLED", "HTTP_CACHE_DISK" or
-  // "HTTP_CACHE_IN_MEMORY".
-  std::string http_cache;
+  const bool enable_sdch;
+  // Type of http cache.
+  const HttpCacheType http_cache;
   // Max size of http cache in bytes.
-  int http_cache_max_size;
+  const int http_cache_max_size;
   // Disable caching for HTTP responses. Other information may be stored in
   // the cache.
-  bool load_disable_cache;
+  const bool load_disable_cache;
   // Storage path for http cache and cookie storage.
-  std::string storage_path;
+  const std::string storage_path;
   // User-Agent request header field.
-  std::string user_agent;
-  // App-provided list of servers that support QUIC.
-  ScopedVector<QuicHint> quic_hints;
+  const std::string user_agent;
   // Experimental options encoded as a string in a JSON format containing
   // experiments and their corresponding configuration options. The format
   // is a JSON object with the name of the experiment as the key, and the
   // configuration options as the value. An example:
   //   {"experiment1": {"option1": "option_value1", "option2": "option_value2",
   //    ...}, "experiment2: {"option3", "option_value3", ...}, ...}
-  std::string experimental_options;
+  const std::string experimental_options;
   // Enable Data Reduction Proxy with authentication key.
-  std::string data_reduction_proxy_key;
-  std::string data_reduction_primary_proxy;
-  std::string data_reduction_fallback_proxy;
-  std::string data_reduction_secure_proxy_check_url;
-  // The list of public key pins.
-  ScopedVector<Pkp> pkp_list;
+  const std::string data_reduction_proxy_key;
+  const std::string data_reduction_primary_proxy;
+  const std::string data_reduction_fallback_proxy;
+  const std::string data_reduction_secure_proxy_check_url;
 
   // Certificate verifier for testing.
   scoped_ptr<net::CertVerifier> mock_cert_verifier;
 
+  // App-provided list of servers that support QUIC.
+  ScopedVector<QuicHint> quic_hints;
+
+  // The list of public key pins.
+  ScopedVector<Pkp> pkp_list;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(URLRequestContextConfig);
 };
diff --git a/components/cronet/url_request_context_config_list.h b/components/cronet/url_request_context_config_list.h
deleted file mode 100644
index 53ded8b..0000000
--- a/components/cronet/url_request_context_config_list.h
+++ /dev/null
@@ -1,56 +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.
-
-// This file intentionally does not have header guards, it's included
-// inside a macro to generate enum values.
-#ifndef DEFINE_CONTEXT_CONFIG
-#error "DEFINE_CONTEXT_CONFIG should be defined before including this file"
-#endif
-// See CronetEngine.Builder class in CronetEngine.java for description of these
-// parameters.
-DEFINE_CONTEXT_CONFIG(USER_AGENT)
-DEFINE_CONTEXT_CONFIG(STORAGE_PATH)
-DEFINE_CONTEXT_CONFIG(ENABLE_LEGACY_MODE)
-DEFINE_CONTEXT_CONFIG(NATIVE_LIBRARY_NAME)
-DEFINE_CONTEXT_CONFIG(ENABLE_QUIC)
-DEFINE_CONTEXT_CONFIG(ENABLE_SPDY)
-DEFINE_CONTEXT_CONFIG(ENABLE_SDCH)
-DEFINE_CONTEXT_CONFIG(DATA_REDUCTION_PROXY_KEY)
-DEFINE_CONTEXT_CONFIG(DATA_REDUCTION_PRIMARY_PROXY)
-DEFINE_CONTEXT_CONFIG(DATA_REDUCTION_FALLBACK_PROXY)
-DEFINE_CONTEXT_CONFIG(DATA_REDUCTION_SECURE_PROXY_CHECK_URL)
-DEFINE_CONTEXT_CONFIG(HTTP_CACHE)
-DEFINE_CONTEXT_CONFIG(HTTP_CACHE_MAX_SIZE)
-
-DEFINE_CONTEXT_CONFIG(HTTP_CACHE_DISABLED)
-DEFINE_CONTEXT_CONFIG(HTTP_CACHE_DISK)
-DEFINE_CONTEXT_CONFIG(HTTP_CACHE_MEMORY)
-DEFINE_CONTEXT_CONFIG(LOAD_DISABLE_CACHE)
-
-DEFINE_CONTEXT_CONFIG(QUIC_HINTS)
-DEFINE_CONTEXT_CONFIG(QUIC_HINT_HOST)
-DEFINE_CONTEXT_CONFIG(QUIC_HINT_PORT)
-DEFINE_CONTEXT_CONFIG(QUIC_HINT_ALT_PORT)
-
-DEFINE_CONTEXT_CONFIG(EXPERIMENTAL_OPTIONS)
-
-// The list of PKP info for multiple hosts. Each member of the list pins a
-// single host and contains the following nested JSON elements: PKP_HOST,
-// PKP_PIN_HASHES, PKP_INCLUDE_SUBDOMAINS and PKP_EXPIRATION_DATE.
-DEFINE_CONTEXT_CONFIG(PKP_LIST)
-// Name of the host to which public keys should be pinned. See PKP_LIST.
-DEFINE_CONTEXT_CONFIG(PKP_HOST)
-// The list of PKP pins. Each pin is BASE64 encoded SHA-256 cryptographic
-// hash of DER-encoded ASN.1 representation of Subject Public Key Info (SPKI)
-// of the host X.509 certificate. The pins are prepended with "sha256/" prefix.
-// See PKP_LIST.
-DEFINE_CONTEXT_CONFIG(PKP_PIN_HASHES)
-// Indicates whether the pinning policy should be applied to subdomains of
-// PKP_HOST. See PKP_LIST.
-DEFINE_CONTEXT_CONFIG(PKP_INCLUDE_SUBDOMAINS)
-// Specifies the expiration date for the pins. See PKP_LIST.
-DEFINE_CONTEXT_CONFIG(PKP_EXPIRATION_DATE)
-
-// For Testing.
-DEFINE_CONTEXT_CONFIG(MOCK_CERT_VERIFIER)
diff --git a/components/cronet/url_request_context_config_unittest.cc b/components/cronet/url_request_context_config_unittest.cc
index ac4ace5..24bbfaa 100644
--- a/components/cronet/url_request_context_config_unittest.cc
+++ b/components/cronet/url_request_context_config_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "components/cronet/url_request_context_config.h"
 
+#include "net/cert/cert_verifier.h"
 #include "net/http/http_network_session.h"
 #include "net/proxy/proxy_config.h"
 #include "net/proxy/proxy_config_service_fixed.h"
@@ -14,27 +15,45 @@
 namespace cronet {
 
 TEST(URLRequestContextConfigTest, SetQuicExperimentalOptions) {
-  URLRequestContextConfig config;
+  URLRequestContextConfig config(
+      // Enable QUIC.
+      true,
+      // Enable SPDY.
+      true,
+      // Enable SDCH.
+      false,
+      // Type of http cache.
+      URLRequestContextConfig::HttpCacheType::DISK,
+      // Max size of http cache in bytes.
+      1024000,
+      // Disable caching for HTTP responses. Other information may be stored in
+      // the cache.
+      false,
+      // Storage path for http cache and cookie storage.
+      "/data/data/org.chromium.net/app_cronet_test/test_storage",
+      // User-Agent request header field.
+      "fake agent",
+      // JSON encoded experimental options.
+      "{\"QUIC\":{\"store_server_configs_in_properties\":true,"
+      "\"delay_tcp_race\":true,"
+      "\"max_number_of_lossy_connections\":10,"
+      "\"packet_loss_threshold\":0.5,"
+      "\"connection_options\":\"TIME,TBBR,REJ\"},"
+      "\"AsyncDNS\":{\"enable\":true}}",
+      // Data reduction proxy key.
+      "",
+      // Data reduction proxy.
+      "",
+      // Fallback data reduction proxy.
+      "",
+      // Data reduction proxy secure proxy check URL.
+      "",
+      // MockCertVerifier to use for testing purposes.
+      scoped_ptr<net::CertVerifier>());
 
-  std::string args =
-      "{\"QUIC_HINTS\":[{\"QUIC_HINT_ALT_PORT\":6121,\"QUIC_HINT_PORT\":6121,"
-      "\"QUIC_HINT_HOST\":\"test.example.com\"}],"
-      "\"HTTP_CACHE\":\"HTTP_CACHE_DISK\",\"ENABLE_SDCH\":false,"
-      "\"ENABLE_LEGACY_MODE\":false,\"HTTP_CACHE_MAX_SIZE\":1024000,"
-      "\"NATIVE_LIBRARY_NAME\":\"cronet_tests\",\"USER_AGENT\":\"fake agent\","
-      "\"STORAGE_PATH\":"
-      "\"\\/data\\/data\\/org.chromium.net\\/app_cronet_test\\/test_storage\","
-      "\"ENABLE_SPDY\":true,"
-      "\"ENABLE_QUIC\":true,\"LOAD_DISABLE_CACHE\":true,"
-      "\"EXPERIMENTAL_OPTIONS\":"
-      "\"{\\\"QUIC\\\":{\\\"store_server_configs_in_properties\\\":true,"
-      "\\\"delay_tcp_race\\\":true,"
-      "\\\"max_number_of_lossy_connections\\\":10,"
-      "\\\"packet_loss_threshold\\\":0.5,"
-      "\\\"connection_options\\\":\\\"TIME,TBBR,REJ\\\"}}\"}";
-  config.LoadFromJSON(args);
   net::URLRequestContextBuilder builder;
-  config.ConfigureURLRequestContextBuilder(&builder);
+  net::NetLog net_log;
+  config.ConfigureURLRequestContextBuilder(&builder, &net_log);
   // Set a ProxyConfigService to avoid DCHECK failure when building.
   builder.set_proxy_config_service(make_scoped_ptr(
       new net::ProxyConfigServiceFixed(net::ProxyConfig::CreateDirect())));
@@ -57,6 +76,9 @@
   // Check max_number_of_lossy_connections and packet_loss_threshold.
   EXPECT_EQ(10, params->quic_max_number_of_lossy_connections);
   EXPECT_FLOAT_EQ(0.5f, params->quic_packet_loss_threshold);
+
+  // Check AsyncDNS resolver is enabled.
+  EXPECT_NE(nullptr, context->host_resolver()->GetDnsConfigAsValue());
 }
 
 }  // namespace cronet
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h
index a47aa787..3f0adb26 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h
@@ -109,7 +109,7 @@
   // Given |data_reduction_proxy_enabled|, a |request|, and the
   // |data_reduction_proxy_config| records the number of bypassed bytes for that
   // |request| into UMAs based on bypass type. |data_reduction_proxy_enabled|
-  // tells us the state of the kDataReductionProxyEnabled preference.
+  // tells us the state of the Data Reduction Proxy enabling preference.
   void RecordBypassedBytesHistograms(
       const net::URLRequest& request,
       bool data_reduction_proxy_enabled,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
index b8f90f8..6634f67 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
@@ -82,12 +82,12 @@
 
     // Create a test job that will fill in the given response headers for the
     // |fake_request|.
-    scoped_refptr<net::URLRequestTestJob> test_job(new net::URLRequestTestJob(
+    scoped_ptr<net::URLRequestTestJob> test_job(new net::URLRequestTestJob(
         fake_request.get(), context_.network_delegate(), response_headers,
         std::string(), true));
 
     // Configure the interceptor to use the test job to handle the next request.
-    test_job_interceptor_->set_main_intercept_job(test_job.get());
+    test_job_interceptor_->set_main_intercept_job(std::move(test_job));
     fake_request->Start();
     test_context_->RunUntilIdle();
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc
index a1e25a4..b8b888e 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc
@@ -450,6 +450,10 @@
     return drp_test_context_->data_reduction_proxy_service();
   }
 
+  bool IsDataReductionProxyEnabled() {
+    return drp_test_context_->IsDataReductionProxyEnabled();
+  }
+
  private:
   base::MessageLoopForUI loop_;
   scoped_ptr<DataReductionProxyTestContext> drp_test_context_;
@@ -579,29 +583,23 @@
   const int64 kReceivedLength = 100;
 
   compression_stats()->UpdateContentLengths(
-      kReceivedLength, kOriginalLength,
-      pref_service()->GetBoolean(
-          data_reduction_proxy::prefs::kDataReductionProxyEnabled),
+      kReceivedLength, kOriginalLength, IsDataReductionProxyEnabled(),
       UNKNOWN_TYPE, std::string(), std::string());
 
   EXPECT_EQ(kReceivedLength,
             GetInt64(data_reduction_proxy::prefs::kHttpReceivedContentLength));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      data_reduction_proxy::prefs::kDataReductionProxyEnabled));
+  EXPECT_FALSE(IsDataReductionProxyEnabled());
   EXPECT_EQ(kOriginalLength,
             GetInt64(data_reduction_proxy::prefs::kHttpOriginalContentLength));
 
   // Record the same numbers again, and total lengths should be doubled.
   compression_stats()->UpdateContentLengths(
-      kReceivedLength, kOriginalLength,
-      pref_service()->GetBoolean(
-          data_reduction_proxy::prefs::kDataReductionProxyEnabled),
+      kReceivedLength, kOriginalLength, IsDataReductionProxyEnabled(),
       UNKNOWN_TYPE, std::string(), std::string());
 
   EXPECT_EQ(kReceivedLength * 2,
             GetInt64(data_reduction_proxy::prefs::kHttpReceivedContentLength));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      data_reduction_proxy::prefs::kDataReductionProxyEnabled));
+  EXPECT_FALSE(IsDataReductionProxyEnabled());
   EXPECT_EQ(kOriginalLength * 2,
             GetInt64(data_reduction_proxy::prefs::kHttpOriginalContentLength));
 }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc
index fb73d556..dd974117 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc
@@ -30,7 +30,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
-
 // Used only to verify that a wrapped network delegate gets called.
 class CountingNetworkDelegate : public net::NetworkDelegateImpl {
  public:
@@ -161,8 +160,7 @@
           .SkipSettingsInitialization()
           .Build();
 
-  drp_test_context->pref_service()->SetBoolean(
-      prefs::kDataReductionProxyEnabled, true);
+  drp_test_context->SetDataReductionProxyEnabled(true);
   drp_test_context->InitSettings();
   DataReductionProxyIOData* io_data = drp_test_context->io_data();
   std::vector<net::ProxyServer> proxies;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
index 89276ff8..f739eac 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
@@ -30,7 +30,6 @@
 // Make sure any changes here that have the potential to impact android_webview
 // are reflected in RegisterSimpleProfilePrefs.
 void RegisterSyncableProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
-  registry->RegisterBooleanPref(prefs::kDataReductionProxyEnabled, false);
   registry->RegisterBooleanPref(prefs::kDataReductionProxyWasEnabledBefore,
                                 false);
 
@@ -111,8 +110,6 @@
 
 void RegisterSimpleProfilePrefs(PrefRegistrySimple* registry) {
   registry->RegisterBooleanPref(
-      prefs::kDataReductionProxyEnabled, false);
-  registry->RegisterBooleanPref(
       prefs::kDataReductionProxyWasEnabledBefore, false);
 
   registry->RegisterBooleanPref(prefs::kDataUsageReportingEnabled, false);
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
index 6c3b9740..fb91f44 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
@@ -45,6 +45,7 @@
       promo_allowed_(false),
       lo_fi_mode_active_(false),
       lo_fi_load_image_requested_(false),
+      data_reduction_proxy_enabled_pref_name_(),
       prefs_(NULL),
       config_(nullptr) {
   lo_fi_user_requests_for_images_per_session_ =
@@ -63,8 +64,7 @@
 void DataReductionProxySettings::InitPrefMembers() {
   DCHECK(thread_checker_.CalledOnValidThread());
   spdy_proxy_auth_enabled_.Init(
-      prefs::kDataReductionProxyEnabled,
-      GetOriginalProfilePrefs(),
+      data_reduction_proxy_enabled_pref_name_, GetOriginalProfilePrefs(),
       base::Bind(&DataReductionProxySettings::OnProxyEnabledPrefChange,
                  base::Unretained(this)));
 }
@@ -76,14 +76,18 @@
 }
 
 void DataReductionProxySettings::InitDataReductionProxySettings(
+    const std::string& data_reduction_proxy_enabled_pref_name,
     PrefService* prefs,
     DataReductionProxyIOData* io_data,
     scoped_ptr<DataReductionProxyService> data_reduction_proxy_service) {
   DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(!data_reduction_proxy_enabled_pref_name.empty());
   DCHECK(prefs);
   DCHECK(io_data);
   DCHECK(io_data->config());
   DCHECK(data_reduction_proxy_service.get());
+  data_reduction_proxy_enabled_pref_name_ =
+      data_reduction_proxy_enabled_pref_name;
   prefs_ = prefs;
   config_ = io_data->config();
   data_reduction_proxy_service_ = data_reduction_proxy_service.Pass();
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
index 26e5e45..7d6f674 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
@@ -75,10 +75,12 @@
   DataReductionProxySettings();
   virtual ~DataReductionProxySettings();
 
-  // Initializes the data reduction proxy with profile prefs and a
-  // |DataReductionProxyIOData|. The caller must ensure that all parameters
-  // remain alive for the lifetime of the |DataReductionProxySettings| instance.
+  // Initializes the Data Reduction Proxy with the name of the preference that
+  // controls enabling it, profile prefs and a |DataReductionProxyIOData|. The
+  // caller must ensure that all parameters remain alive for the lifetime of
+  // the |DataReductionProxySettings| instance.
   void InitDataReductionProxySettings(
+      const std::string& data_reduction_proxy_enabled_pref_name,
       PrefService* prefs,
       DataReductionProxyIOData* io_data,
       scoped_ptr<DataReductionProxyService> data_reduction_proxy_service);
@@ -267,6 +269,13 @@
   // Update IO thread objects in response to UI thread changes.
   void UpdateIOData(bool at_startup);
 
+  // For tests.
+  void set_data_reduction_proxy_enabled_pref_name_for_test(
+      const std::string& data_reduction_proxy_enabled_pref_name) {
+    data_reduction_proxy_enabled_pref_name_ =
+        data_reduction_proxy_enabled_pref_name;
+  }
+
   bool unreachable_;
 
   // A call to MaybeActivateDataReductionProxy may take place before the
@@ -303,6 +312,10 @@
 
   scoped_ptr<DataReductionProxyService> data_reduction_proxy_service_;
 
+  // The name of the preference that controls enabling and disabling the Data
+  // Reduction Proxy.
+  std::string data_reduction_proxy_enabled_pref_name_;
+
   PrefService* prefs_;
 
   // The caller must ensure that the |config_| outlives this instance.
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc
index b67b81d8..50e72ab 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc
@@ -46,10 +46,10 @@
           .SkipSettingsInitialization()
           .Build();
 
+  test_context_->SetDataReductionProxyEnabled(false);
   TestingPrefServiceSimple* pref_service = test_context_->pref_service();
   pref_service->SetInt64(prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
   pref_service->registry()->RegisterDictionaryPref(kProxy);
-  pref_service->SetBoolean(prefs::kDataReductionProxyEnabled, false);
   pref_service->SetBoolean(prefs::kDataReductionProxyWasEnabledBefore, false);
 
   //AddProxyToCommandLine();
@@ -125,10 +125,10 @@
   ExpectSetProxyPrefs(expected_enabled, false);
   if (managed) {
     test_context_->pref_service()->SetManagedPref(
-        prefs::kDataReductionProxyEnabled, new base::FundamentalValue(enabled));
+        test_context_->GetDataReductionProxyEnabledPrefName(),
+        new base::FundamentalValue(enabled));
   } else {
-    test_context_->pref_service()->SetBoolean(prefs::kDataReductionProxyEnabled,
-                                              enabled);
+    test_context_->SetDataReductionProxyEnabled(enabled);
   }
   test_context_->RunUntilIdle();
   // Never expect the proxy to be restricted for pref change tests.
@@ -137,6 +137,7 @@
 void DataReductionProxySettingsTestBase::InitDataReductionProxy(
     bool enabled_at_startup) {
   settings_->InitDataReductionProxySettings(
+      test_context_->GetDataReductionProxyEnabledPrefName(),
       test_context_->pref_service(), test_context_->io_data(),
       test_context_->CreateDataReductionProxyService(settings_.get()));
   settings_->data_reduction_proxy_service()->SetIOData(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
index 824674cc..b8cb6160e 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/md5.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_samples.h"
+#include "base/prefs/pref_registry_simple.h"
 #include "base/test/histogram_tester.h"
 #include "base/test/mock_entropy_provider.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
@@ -36,18 +37,23 @@
                                             bool expected_enabled,
                                             bool expected_restricted,
                                             bool expected_fallback_restricted) {
-    test_context_->pref_service()->SetBoolean(prefs::kDataReductionProxyEnabled,
-                                              initially_enabled);
+    test_context_->SetDataReductionProxyEnabled(initially_enabled);
     test_context_->config()->SetStateForTest(initially_enabled,
                                              request_succeeded);
     ExpectSetProxyPrefs(expected_enabled, false);
     settings_->MaybeActivateDataReductionProxy(false);
     test_context_->RunUntilIdle();
   }
+
+  void InitPrefMembers() {
+    settings_->set_data_reduction_proxy_enabled_pref_name_for_test(
+        test_context_->GetDataReductionProxyEnabledPrefName());
+    settings_->InitPrefMembers();
+  }
 };
 
 TEST_F(DataReductionProxySettingsTest, TestIsProxyEnabledOrManaged) {
-  settings_->InitPrefMembers();
+  InitPrefMembers();
   // The proxy is disabled initially.
   test_context_->config()->SetStateForTest(false, true);
 
@@ -66,7 +72,7 @@
 }
 
 TEST_F(DataReductionProxySettingsTest, TestCanUseDataReductionProxy) {
-  settings_->InitPrefMembers();
+  InitPrefMembers();
   // The proxy is disabled initially.
   test_context_->config()->SetStateForTest(false, true);
 
@@ -188,8 +194,7 @@
     context.Init();
 
     // Start with the Data Reduction Proxy disabled.
-    drp_test_context->pref_service()->SetBoolean(
-        prefs::kDataReductionProxyEnabled, false);
+    drp_test_context->SetDataReductionProxyEnabled(false);
     drp_test_context->InitSettings();
 
     net::MockRead mock_reads[] = {
@@ -202,8 +207,7 @@
     mock_socket_factory.AddSocketDataProvider(&socket_data_provider);
 
     // Toggle the pref to trigger the secure proxy check.
-    drp_test_context->pref_service()->SetBoolean(
-            prefs::kDataReductionProxyEnabled, true);
+    drp_test_context->SetDataReductionProxyEnabled(true);
     drp_test_context->RunUntilIdle();
 
     EXPECT_EQ(test_case.expected_restricted,
@@ -231,13 +235,11 @@
 
   // The pref is disabled, so correspondingly should be the proxy.
   EXPECT_CALL(*mock_service, SetProxyPrefs(false, false));
-  drp_test_context->pref_service()->SetBoolean(
-      prefs::kDataReductionProxyEnabled, false);
+  drp_test_context->SetDataReductionProxyEnabled(false);
 
   // The pref is enabled, so correspondingly should be the proxy.
   EXPECT_CALL(*mock_service, SetProxyPrefs(true, false));
-  drp_test_context->pref_service()->SetBoolean(
-      prefs::kDataReductionProxyEnabled, true);
+  drp_test_context->SetDataReductionProxyEnabled(true);
 }
 
 TEST_F(DataReductionProxySettingsTest, TestMaybeActivateDataReductionProxy) {
@@ -245,7 +247,7 @@
   // so it won't trigger MaybeActivateDataReductionProxy when the pref value
   // is set.
   settings_->spdy_proxy_auth_enabled_.Init(
-      prefs::kDataReductionProxyEnabled,
+      test_context_->GetDataReductionProxyEnabledPrefName(),
       settings_->GetOriginalProfilePrefs());
 
   // TODO(bengr): Test enabling/disabling while a secure proxy check is
@@ -266,8 +268,7 @@
   MockSettings* settings = static_cast<MockSettings*>(settings_.get());
   EXPECT_CALL(*settings, RecordStartupState(PROXY_ENABLED));
 
-  test_context_->pref_service()->SetBoolean(prefs::kDataReductionProxyEnabled,
-                                            true);
+  test_context_->SetDataReductionProxyEnabled(true);
   InitDataReductionProxy(true);
   CheckDataReductionProxySyntheticTrial(true);
 }
@@ -278,8 +279,7 @@
   MockSettings* settings = static_cast<MockSettings*>(settings_.get());
   EXPECT_CALL(*settings, RecordStartupState(PROXY_DISABLED));
 
-  test_context_->pref_service()->SetBoolean(prefs::kDataReductionProxyEnabled,
-                                            false);
+  test_context_->SetDataReductionProxyEnabled(false);
   InitDataReductionProxy(false);
   CheckDataReductionProxySyntheticTrial(false);
 }
@@ -297,8 +297,7 @@
 TEST_F(DataReductionProxySettingsTest, TestSetDataReductionProxyEnabled) {
   MockSettings* settings = static_cast<MockSettings*>(settings_.get());
   EXPECT_CALL(*settings, RecordStartupState(PROXY_ENABLED));
-  test_context_->pref_service()->SetBoolean(prefs::kDataReductionProxyEnabled,
-                                            true);
+  test_context_->SetDataReductionProxyEnabled(true);
   settings->SetLoFiModeActiveOnMainFrame(true);
   InitDataReductionProxy(true);
 
@@ -317,8 +316,7 @@
 TEST_F(DataReductionProxySettingsTest, TestEnableLoFiSyntheticTrial) {
   MockSettings* settings = static_cast<MockSettings*>(settings_.get());
   EXPECT_CALL(*settings, RecordStartupState(PROXY_ENABLED));
-  test_context_->pref_service()->SetBoolean(prefs::kDataReductionProxyEnabled,
-                                            true);
+  test_context_->SetDataReductionProxyEnabled(true);
   InitDataReductionProxy(true);
 
   // The Lo-Fi field trial will be set to "Disabled" until the first main frame
@@ -335,7 +333,7 @@
 }
 
 TEST_F(DataReductionProxySettingsTest, TestLoFiImplicitOptOutClicksPerSession) {
-  settings_->InitPrefMembers();
+  InitPrefMembers();
   settings_->data_reduction_proxy_service_->SetIOData(
       test_context_->io_data()->GetWeakPtr());
   test_context_->config()->ResetLoFiStatusForTest();
@@ -424,7 +422,7 @@
 
 TEST_F(DataReductionProxySettingsTest,
        TestLoFiImplicitOptOutConsecutiveSessions) {
-  settings_->InitPrefMembers();
+  InitPrefMembers();
   settings_->data_reduction_proxy_service_->SetIOData(
       test_context_->io_data()->GetWeakPtr());
   test_context_->config()->ResetLoFiStatusForTest();
@@ -486,7 +484,7 @@
   const char kUMALoFiImplicitOptOutAction[] =
       "DataReductionProxy.LoFi.ImplicitOptOutAction.Unknown";
   base::HistogramTester histogram_tester;
-  settings_->InitPrefMembers();
+  InitPrefMembers();
   settings_->data_reduction_proxy_service_->SetIOData(
       test_context_->io_data()->GetWeakPtr());
 
@@ -528,7 +526,7 @@
 TEST_F(DataReductionProxySettingsTest, TestLoFiSessionStateHistograms) {
   const char kUMALoFiSessionState[] = "DataReductionProxy.LoFi.SessionState";
   base::HistogramTester histogram_tester;
-  settings_->InitPrefMembers();
+  InitPrefMembers();
   settings_->data_reduction_proxy_service_->SetIOData(
       test_context_->io_data()->GetWeakPtr());
 
@@ -622,7 +620,7 @@
   const char kUMAEnabledState[] = "DataReductionProxy.EnabledState";
   base::HistogramTester histogram_tester;
 
-  settings_->InitPrefMembers();
+  InitPrefMembers();
   settings_->data_reduction_proxy_service_->SetIOData(
       test_context_->io_data()->GetWeakPtr());
 
@@ -671,6 +669,7 @@
   EXPECT_CALL(*settings, RecordStartupState(PROXY_NOT_AVAILABLE));
 
   settings_->InitDataReductionProxySettings(
+      test_context_->GetDataReductionProxyEnabledPrefName(),
       test_context_->pref_service(), test_context_->io_data(),
       test_context_->CreateDataReductionProxyService(settings_.get()));
   settings_->SetCallbackToRegisterSyntheticFieldTrial(
@@ -718,6 +717,7 @@
     EXPECT_CALL(*settings, RecordStartupState(PROXY_NOT_AVAILABLE));
 
     settings_->InitDataReductionProxySettings(
+        test_context_->GetDataReductionProxyEnabledPrefName(),
         test_context_->pref_service(), test_context_->io_data(),
         test_context_->CreateDataReductionProxyService(settings_.get()));
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
index e8f8f54b..7a0c9f1 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
@@ -6,6 +6,7 @@
 
 #include <map>
 
+#include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/testing_pref_service.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h"
@@ -35,6 +36,9 @@
 
 const char kTestKey[] = "test-key";
 
+// Name of the preference that governs enabling the Data Reduction Proxy.
+const char kDataReductionProxyEnabled[] = "data_reduction_proxy.enabled";
+
 const net::BackoffEntry::Policy kTestBackoffPolicy = {
     0,               // num_errors_to_ignore
     10 * 1000,       // initial_delay_ms
@@ -436,12 +440,17 @@
 
   scoped_ptr<DataReductionProxySettings> settings(
       new DataReductionProxySettings());
-  if (skip_settings_initialization_)
+  if (skip_settings_initialization_) {
+    settings->set_data_reduction_proxy_enabled_pref_name_for_test(
+        kDataReductionProxyEnabled);
     test_context_flags |= SKIP_SETTINGS_INITIALIZATION;
+  }
 
   if (use_mock_service_)
     test_context_flags |= USE_MOCK_SERVICE;
 
+  pref_service->registry()->RegisterBooleanPref(kDataReductionProxyEnabled,
+                                                false);
   RegisterSimpleProfilePrefs(pref_service->registry());
 
   scoped_ptr<DataReductionProxyExperimentsStats> experiments_stats(
@@ -496,6 +505,24 @@
   DestroySettings();
 }
 
+const char*
+DataReductionProxyTestContext::GetDataReductionProxyEnabledPrefName() const {
+  return kDataReductionProxyEnabled;
+}
+
+void DataReductionProxyTestContext::RegisterDataReductionProxyEnabledPref() {
+  simple_pref_service_->registry()->RegisterBooleanPref(
+      kDataReductionProxyEnabled, false);
+}
+
+void DataReductionProxyTestContext::SetDataReductionProxyEnabled(bool enabled) {
+  simple_pref_service_->SetBoolean(kDataReductionProxyEnabled, enabled);
+}
+
+bool DataReductionProxyTestContext::IsDataReductionProxyEnabled() const {
+  return simple_pref_service_->GetBoolean(kDataReductionProxyEnabled);
+}
+
 void DataReductionProxyTestContext::RunUntilIdle() {
   base::MessageLoop::current()->RunUntilIdle();
 }
@@ -517,7 +544,7 @@
 
 void DataReductionProxyTestContext::InitSettingsWithoutCheck() {
   settings_->InitDataReductionProxySettings(
-      simple_pref_service_.get(), io_data_.get(),
+      kDataReductionProxyEnabled, simple_pref_service_.get(), io_data_.get(),
       CreateDataReductionProxyServiceInternal(settings_.get()));
   storage_delegate_->SetStorageDelegate(
       settings_->data_reduction_proxy_service()->event_store());
@@ -591,7 +618,7 @@
   mock_socket_factory_->AddSocketDataProvider(&socket_data_provider);
 
   // Set the pref to cause the secure proxy check to be issued.
-  pref_service()->SetBoolean(prefs::kDataReductionProxyEnabled, true);
+  pref_service()->SetBoolean(kDataReductionProxyEnabled, true);
   RunUntilIdle();
 }
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
index 1549d6e..324e783 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
@@ -303,6 +303,16 @@
 
   virtual ~DataReductionProxyTestContext();
 
+  // Returns the name of the preference used to enable the Data Reduction
+  // Proxy.
+  const char* GetDataReductionProxyEnabledPrefName() const;
+
+  // Registers, sets, and gets the preference used to enable the Data Reduction
+  // Proxy, respectively.
+  void RegisterDataReductionProxyEnabledPref();
+  void SetDataReductionProxyEnabled(bool enabled);
+  bool IsDataReductionProxyEnabled() const;
+
   // Waits while executing all tasks on the current SingleThreadTaskRunner.
   void RunUntilIdle();
 
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
index f3522de..0c60c73d 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
@@ -175,9 +175,6 @@
 // String that specifies a persisted Data Reduction Proxy configuration.
 const char kDataReductionProxyConfig[] = "data_reduction.config";
 
-// A boolean specifying whether the data reduction proxy is enabled.
-const char kDataReductionProxyEnabled[] = "spdy_proxy.enabled";
-
 // A boolean specifying whether data usage should be collected for reporting.
 const char kDataUsageReportingEnabled[] = "data_usage_reporting.enabled";
 
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
index 81c9afe..d358f04b 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
@@ -45,7 +45,6 @@
     kDailyOriginalContentLengthWithDataReductionProxyEnabledUnknown[];
 extern const char kDataReductionProxy[];
 extern const char kDataReductionProxyConfig[];
-extern const char kDataReductionProxyEnabled[];
 extern const char kDataUsageReportingEnabled[];
 extern const char kDataReductionProxyWasEnabledBefore[];
 extern const char kHttpOriginalContentLength[];
diff --git a/components/dialog_strings.grdp b/components/dialog_strings.grdp
new file mode 100644
index 0000000..adadaaa1
--- /dev/null
+++ b/components/dialog_strings.grdp
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+  <!-- HTTP POST Warning -->
+  <message name="IDS_HTTP_POST_WARNING_TITLE" desc="Title for dialog that warns users about a navigation that results in a repost">
+    Confirm Form Resubmission
+  </message>
+  <message name="IDS_HTTP_POST_WARNING" desc="Re-navigation to page that leads to HTTP POST" formatter_data="android_java">
+    The page that you're looking for used information that you entered. Returning to that page might cause any action you took to be repeated. Do you want to continue?
+  </message>
+  <message name="IDS_HTTP_POST_WARNING_RESEND" desc="Resend button for post warning" formatter_data="android_java">
+    Continue
+  </message>
+</grit-part>
diff --git a/components/domain_reliability/context.cc b/components/domain_reliability/context.cc
index f0ce6c5..2cf5dde 100644
--- a/components/domain_reliability/context.cc
+++ b/components/domain_reliability/context.cc
@@ -89,6 +89,8 @@
   }
   // TODO(ttuttle): Histogram HTTP response code?
 
+  // Allow beacons about reports, but don't schedule an upload for more than
+  // one layer of recursion, to avoid infinite report loops.
   if (beacon->upload_depth <= kMaxUploadDepthToSchedule)
     scheduler_.OnBeaconAdded();
   beacons_.push_back(beacon.release());
diff --git a/components/exo.gypi b/components/exo.gypi
index dbc92db..f5fb24b 100644
--- a/components/exo.gypi
+++ b/components/exo.gypi
@@ -30,6 +30,9 @@
         'exo/buffer.h',
         'exo/display.cc',
         'exo/display.h',
+        'exo/keyboard.cc',
+        'exo/keyboard.h',
+        'exo/keyboard_delegate.h',
         'exo/pointer.cc',
         'exo/pointer.h',
         'exo/pointer_delegate.h',
@@ -43,6 +46,9 @@
         'exo/surface.h',
         'exo/surface_delegate.h',
         'exo/surface_observer.h',
+        'exo/touch.cc',
+        'exo/touch.h',
+        'exo/touch_delegate.h',
       ],
     },
   ],
@@ -57,10 +63,12 @@
             '..',
           ],
           'dependencies': [
-             '../base/base.gyp:base',
+            '../base/base.gyp:base',
             '../skia/skia.gyp:skia',
-            '../third_party/wayland/wayland.gyp:wayland_server',
             '../third_party/wayland-protocols/wayland-protocols.gyp:xdg_shell_protocol',
+            '../third_party/wayland/wayland.gyp:wayland_server',
+            '../ui/events/events.gyp:dom_keycode_converter',
+            '../ui/events/events.gyp:events_base',
             'exo',
           ],
           'sources': [
@@ -76,6 +84,14 @@
                 '../third_party/mesa/mesa.gyp:wayland_drm_protocol',
               ],
             }],
+            ['use_xkbcommon==1', {
+              'dependencies': [
+                '../build/linux/system.gyp:xkbcommon',
+              ],
+              'defines': [
+                'USE_XKBCOMMON',
+              ],
+            }],
           ],
         },
       ],
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn
index 8cd2dc0..6d2689f 100644
--- a/components/exo/BUILD.gn
+++ b/components/exo/BUILD.gn
@@ -11,6 +11,9 @@
     "buffer.h",
     "display.cc",
     "display.h",
+    "keyboard.cc",
+    "keyboard.h",
+    "keyboard_delegate.h",
     "pointer.cc",
     "pointer.h",
     "pointer_delegate.h",
@@ -24,6 +27,9 @@
     "surface.h",
     "surface_delegate.h",
     "surface_observer.h",
+    "touch.cc",
+    "touch.h",
+    "touch_delegate.h",
   ]
 
   deps = [
@@ -70,11 +76,13 @@
   sources = [
     "buffer_unittest.cc",
     "display_unittest.cc",
+    "keyboard_unittest.cc",
     "pointer_unittest.cc",
     "shared_memory_unittest.cc",
     "shell_surface_unittest.cc",
     "sub_surface_unittest.cc",
     "surface_unittest.cc",
+    "touch_unittest.cc",
   ]
 
   deps = [
@@ -89,6 +97,7 @@
     "//testing/gmock",
     "//testing/gtest",
     "//ui/aura",
+    "//ui/events:dom_keycode_converter",
     "//ui/events:test_support",
     "//ui/gfx",
     "//ui/keyboard",
diff --git a/components/exo/keyboard.cc b/components/exo/keyboard.cc
new file mode 100644
index 0000000..4a7c5c37
--- /dev/null
+++ b/components/exo/keyboard.cc
@@ -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.
+
+#include "components/exo/keyboard.h"
+
+#include "ash/shell.h"
+#include "components/exo/keyboard_delegate.h"
+#include "components/exo/surface.h"
+#include "ui/aura/client/focus_client.h"
+#include "ui/aura/window.h"
+#include "ui/events/event.h"
+
+namespace exo {
+
+////////////////////////////////////////////////////////////////////////////////
+// Keyboard, public:
+
+Keyboard::Keyboard(KeyboardDelegate* delegate)
+    : delegate_(delegate), focus_(nullptr), modifier_flags_(0) {
+  ash::Shell::GetInstance()->AddPreTargetHandler(this);
+  aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow())
+      ->AddObserver(this);
+}
+
+Keyboard::~Keyboard() {
+  delegate_->OnKeyboardDestroying(this);
+  if (focus_)
+    focus_->RemoveSurfaceObserver(this);
+  aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow())
+      ->RemoveObserver(this);
+  ash::Shell::GetInstance()->RemovePreTargetHandler(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ui::EventHandler overrides:
+
+void Keyboard::OnKeyEvent(ui::KeyEvent* event) {
+  const int kModifierMask = ui::EF_CAPS_LOCK_DOWN | ui::EF_SHIFT_DOWN |
+                            ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN |
+                            ui::EF_COMMAND_DOWN | ui::EF_ALTGR_DOWN |
+                            ui::EF_MOD3_DOWN | ui::EF_NUM_LOCK_DOWN;
+  int modifier_flags = event->flags() & kModifierMask;
+  if (modifier_flags != modifier_flags_) {
+    modifier_flags_ = modifier_flags;
+    if (focus_)
+      delegate_->OnKeyboardModifiers(modifier_flags_);
+  }
+
+  switch (event->type()) {
+    case ui::ET_KEY_PRESSED: {
+      auto it =
+          std::find(pressed_keys_.begin(), pressed_keys_.end(), event->code());
+      if (it == pressed_keys_.end()) {
+        if (focus_)
+          delegate_->OnKeyboardKey(event->time_stamp(), event->code(), true);
+
+        pressed_keys_.push_back(event->code());
+      }
+    } break;
+    case ui::ET_KEY_RELEASED: {
+      auto it =
+          std::find(pressed_keys_.begin(), pressed_keys_.end(), event->code());
+      if (it != pressed_keys_.end()) {
+        if (focus_)
+          delegate_->OnKeyboardKey(event->time_stamp(), event->code(), false);
+
+        pressed_keys_.erase(it);
+      }
+    } break;
+    default:
+      NOTREACHED();
+      break;
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// aura::client::FocusChangeObserver overrides:
+
+void Keyboard::OnWindowFocused(aura::Window* gained_focus,
+                               aura::Window* lost_focus) {
+  Surface* gained_focus_surface =
+      gained_focus ? GetEffectiveFocus(gained_focus) : nullptr;
+  if (gained_focus_surface != focus_) {
+    if (focus_) {
+      delegate_->OnKeyboardLeave(focus_);
+      focus_->RemoveSurfaceObserver(this);
+      focus_ = nullptr;
+    }
+    if (gained_focus_surface) {
+      delegate_->OnKeyboardModifiers(modifier_flags_);
+      delegate_->OnKeyboardEnter(gained_focus_surface, pressed_keys_);
+      focus_ = gained_focus_surface;
+      focus_->AddSurfaceObserver(this);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// SurfaceObserver overrides:
+
+void Keyboard::OnSurfaceDestroying(Surface* surface) {
+  DCHECK(surface == focus_);
+  focus_ = nullptr;
+  surface->RemoveSurfaceObserver(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Keyboard, private:
+
+Surface* Keyboard::GetEffectiveFocus(aura::Window* window) const {
+  Surface* focus = Surface::AsSurface(window);
+  if (!focus)
+    return nullptr;
+
+  return delegate_->CanAcceptKeyboardEventsForSurface(focus) ? focus : nullptr;
+}
+
+}  // namespace exo
diff --git a/components/exo/keyboard.h b/components/exo/keyboard.h
new file mode 100644
index 0000000..51d3084
--- /dev/null
+++ b/components/exo/keyboard.h
@@ -0,0 +1,65 @@
+// 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_EXO_KEYBOARD_H_
+#define COMPONENTS_EXO_KEYBOARD_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "components/exo/surface_observer.h"
+#include "ui/aura/client/focus_change_observer.h"
+#include "ui/events/event_handler.h"
+
+namespace ui {
+enum class DomCode;
+class Event;
+class KeyEvent;
+}
+
+namespace exo {
+class KeyboardDelegate;
+class Surface;
+
+// This class implements a client keyboard that represents one or more keyboard
+// devices.
+class Keyboard : public ui::EventHandler,
+                 public aura::client::FocusChangeObserver,
+                 public SurfaceObserver {
+ public:
+  explicit Keyboard(KeyboardDelegate* delegate);
+  ~Keyboard() override;
+
+  // Overridden from ui::EventHandler:
+  void OnKeyEvent(ui::KeyEvent* event) override;
+
+  // Overridden aura::client::FocusChangeObserver:
+  void OnWindowFocused(aura::Window* gained_focus,
+                       aura::Window* lost_focus) override;
+
+  // Overridden from SurfaceObserver:
+  void OnSurfaceDestroying(Surface* surface) override;
+
+ private:
+  // Returns the effective focus for |window|.
+  Surface* GetEffectiveFocus(aura::Window* window) const;
+
+  // The delegate instance that all events are dispatched to.
+  KeyboardDelegate* delegate_;
+
+  // The current focus surface for the keyboard.
+  Surface* focus_;
+
+  // Vector of currently pressed keys.
+  std::vector<ui::DomCode> pressed_keys_;
+
+  // Current set of modifier flags.
+  int modifier_flags_;
+
+  DISALLOW_COPY_AND_ASSIGN(Keyboard);
+};
+
+}  // namespace exo
+
+#endif  // COMPONENTS_EXO_KEYBOARD_H_
diff --git a/components/exo/keyboard_delegate.h b/components/exo/keyboard_delegate.h
new file mode 100644
index 0000000..e68d429
--- /dev/null
+++ b/components/exo/keyboard_delegate.h
@@ -0,0 +1,54 @@
+// 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_EXO_KEYBOARD_DELEGATE_H_
+#define COMPONENTS_EXO_KEYBOARD_DELEGATE_H_
+
+#include <vector>
+
+#include "base/time/time.h"
+
+namespace ui {
+enum class DomCode;
+}
+
+namespace exo {
+class Keyboard;
+class Surface;
+
+// Handles events on keyboards in context-specific ways.
+class KeyboardDelegate {
+ public:
+  // Called at the top of the keyboard's destructor, to give observers a
+  // chance to remove themselves.
+  virtual void OnKeyboardDestroying(Keyboard* keyboard) = 0;
+
+  // This should return true if |surface| is a valid target for this keyboard.
+  // E.g. the surface is owned by the same client as the keyboard.
+  virtual bool CanAcceptKeyboardEventsForSurface(Surface* surface) const = 0;
+
+  // Called when keyboard focus enters a new valid target surface.
+  virtual void OnKeyboardEnter(
+      Surface* surface,
+      const std::vector<ui::DomCode>& pressed_keys) = 0;
+
+  // Called when keyboard focus leaves a valid target surface.
+  virtual void OnKeyboardLeave(Surface* surface) = 0;
+
+  // Called when pkeyboard key state changed. |pressed| is true when |key|
+  // was pressed and false if it was released.
+  virtual void OnKeyboardKey(base::TimeDelta time_stamp,
+                             ui::DomCode key,
+                             bool pressed) = 0;
+
+  // Called when keyboard modifier state changed.
+  virtual void OnKeyboardModifiers(int modifier_flags) = 0;
+
+ protected:
+  virtual ~KeyboardDelegate() {}
+};
+
+}  // namespace exo
+
+#endif  // COMPONENTS_EXO_KEYBOARD_DELEGATE_H_
diff --git a/components/exo/keyboard_unittest.cc b/components/exo/keyboard_unittest.cc
new file mode 100644
index 0000000..32427f7
--- /dev/null
+++ b/components/exo/keyboard_unittest.cc
@@ -0,0 +1,192 @@
+// 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 "ash/shell.h"
+#include "components/exo/buffer.h"
+#include "components/exo/keyboard.h"
+#include "components/exo/keyboard_delegate.h"
+#include "components/exo/shell_surface.h"
+#include "components/exo/surface.h"
+#include "components/exo/test/exo_test_base.h"
+#include "components/exo/test/exo_test_helper.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/khronos/GLES2/gl2.h"
+#include "ui/aura/client/focus_client.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/test/event_generator.h"
+
+namespace exo {
+namespace {
+
+using KeyboardTest = test::ExoTestBase;
+
+class MockKeyboardDelegate : public KeyboardDelegate {
+ public:
+  MockKeyboardDelegate() {}
+
+  // Overridden from KeyboardDelegate:
+  MOCK_METHOD1(OnKeyboardDestroying, void(Keyboard*));
+  MOCK_CONST_METHOD1(CanAcceptKeyboardEventsForSurface, bool(Surface*));
+  MOCK_METHOD2(OnKeyboardEnter,
+               void(Surface*, const std::vector<ui::DomCode>&));
+  MOCK_METHOD1(OnKeyboardLeave, void(Surface*));
+  MOCK_METHOD3(OnKeyboardKey, void(base::TimeDelta, ui::DomCode, bool));
+  MOCK_METHOD1(OnKeyboardModifiers, void(int));
+};
+
+TEST_F(KeyboardTest, OnKeyboardEnter) {
+  scoped_ptr<Surface> surface(new Surface);
+  scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+  shell_surface->SetToplevel();
+  gfx::Size buffer_size(10, 10);
+  scoped_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(),
+                 GL_TEXTURE_2D));
+  surface->Attach(buffer.get());
+  surface->Commit();
+
+  MockKeyboardDelegate delegate;
+  scoped_ptr<Keyboard> keyboard(new Keyboard(&delegate));
+
+  ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+  generator.PressKey(ui::VKEY_A, 0);
+
+  aura::client::FocusClient* focus_client =
+      aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
+  EXPECT_CALL(delegate, CanAcceptKeyboardEventsForSurface(surface.get()))
+      .WillOnce(testing::Return(false));
+  focus_client->FocusWindow(surface.get());
+
+  EXPECT_CALL(delegate, CanAcceptKeyboardEventsForSurface(surface.get()))
+      .WillOnce(testing::Return(true));
+  ui::DomCode expected_pressed_keys[] = {ui::DomCode::KEY_A};
+  EXPECT_CALL(delegate, OnKeyboardModifiers(0));
+  EXPECT_CALL(delegate,
+              OnKeyboardEnter(surface.get(),
+                              std::vector<ui::DomCode>(
+                                  expected_pressed_keys,
+                                  expected_pressed_keys +
+                                      arraysize(expected_pressed_keys))));
+  focus_client->FocusWindow(nullptr);
+  focus_client->FocusWindow(surface.get());
+
+  EXPECT_CALL(delegate, OnKeyboardDestroying(keyboard.get()));
+  keyboard.reset();
+}
+
+TEST_F(KeyboardTest, OnKeyboardLeave) {
+  scoped_ptr<Surface> surface(new Surface);
+  scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+  shell_surface->SetToplevel();
+  gfx::Size buffer_size(10, 10);
+  scoped_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(),
+                 GL_TEXTURE_2D));
+  surface->Attach(buffer.get());
+  surface->Commit();
+
+  MockKeyboardDelegate delegate;
+  scoped_ptr<Keyboard> keyboard(new Keyboard(&delegate));
+
+  aura::client::FocusClient* focus_client =
+      aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
+  EXPECT_CALL(delegate, CanAcceptKeyboardEventsForSurface(surface.get()))
+      .WillOnce(testing::Return(true));
+  EXPECT_CALL(delegate, OnKeyboardModifiers(0));
+  EXPECT_CALL(delegate,
+              OnKeyboardEnter(surface.get(), std::vector<ui::DomCode>()));
+  focus_client->FocusWindow(surface.get());
+
+  EXPECT_CALL(delegate, OnKeyboardLeave(surface.get()));
+  focus_client->FocusWindow(nullptr);
+
+  EXPECT_CALL(delegate, OnKeyboardDestroying(keyboard.get()));
+  keyboard.reset();
+}
+
+TEST_F(KeyboardTest, OnKeyboardKey) {
+  scoped_ptr<Surface> surface(new Surface);
+  scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+  shell_surface->SetToplevel();
+  gfx::Size buffer_size(10, 10);
+  scoped_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(),
+                 GL_TEXTURE_2D));
+  surface->Attach(buffer.get());
+  surface->Commit();
+
+  MockKeyboardDelegate delegate;
+  scoped_ptr<Keyboard> keyboard(new Keyboard(&delegate));
+
+  aura::client::FocusClient* focus_client =
+      aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
+  EXPECT_CALL(delegate, CanAcceptKeyboardEventsForSurface(surface.get()))
+      .WillOnce(testing::Return(true));
+  EXPECT_CALL(delegate, OnKeyboardModifiers(0));
+  EXPECT_CALL(delegate,
+              OnKeyboardEnter(surface.get(), std::vector<ui::DomCode>()));
+  focus_client->FocusWindow(surface.get());
+
+  ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+  // This should only generate one press event for KEY_A.
+  EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::KEY_A, true));
+  generator.PressKey(ui::VKEY_A, 0);
+  generator.PressKey(ui::VKEY_A, 0);
+  generator.ReleaseKey(ui::VKEY_B, 0);
+
+  // This should only generate one release event for KEY_A.
+  EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::KEY_A, false));
+  generator.ReleaseKey(ui::VKEY_A, 0);
+  generator.ReleaseKey(ui::VKEY_A, 0);
+
+  EXPECT_CALL(delegate, OnKeyboardDestroying(keyboard.get()));
+  keyboard.reset();
+}
+
+TEST_F(KeyboardTest, OnKeyboardModifiers) {
+  scoped_ptr<Surface> surface(new Surface);
+  scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+  shell_surface->SetToplevel();
+  gfx::Size buffer_size(10, 10);
+  scoped_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(),
+                 GL_TEXTURE_2D));
+  surface->Attach(buffer.get());
+  surface->Commit();
+
+  MockKeyboardDelegate delegate;
+  scoped_ptr<Keyboard> keyboard(new Keyboard(&delegate));
+
+  aura::client::FocusClient* focus_client =
+      aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
+  EXPECT_CALL(delegate, CanAcceptKeyboardEventsForSurface(surface.get()))
+      .WillOnce(testing::Return(true));
+  EXPECT_CALL(delegate, OnKeyboardModifiers(0));
+  EXPECT_CALL(delegate,
+              OnKeyboardEnter(surface.get(), std::vector<ui::DomCode>()));
+  focus_client->FocusWindow(surface.get());
+
+  ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+  // This should generate a modifier event.
+  EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::KEY_A, true));
+  EXPECT_CALL(delegate, OnKeyboardModifiers(ui::EF_SHIFT_DOWN));
+  generator.PressKey(ui::VKEY_A, ui::EF_SHIFT_DOWN);
+
+  // This should generate another modifier event.
+  EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::KEY_B, true));
+  EXPECT_CALL(delegate,
+              OnKeyboardModifiers(ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN));
+  generator.PressKey(ui::VKEY_B, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN);
+
+  // This should generate a third modifier event.
+  EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::KEY_B, false));
+  EXPECT_CALL(delegate, OnKeyboardModifiers(0));
+  generator.ReleaseKey(ui::VKEY_B, 0);
+
+  EXPECT_CALL(delegate, OnKeyboardDestroying(keyboard.get()));
+  keyboard.reset();
+}
+
+}  // namespace
+}  // namespace exo
diff --git a/components/exo/pointer.h b/components/exo/pointer.h
index 1ba2af98..13aa47f9 100644
--- a/components/exo/pointer.h
+++ b/components/exo/pointer.h
@@ -20,7 +20,7 @@
 class PointerDelegate;
 class Surface;
 
-// This class implementes a client pointer that represents one or more input
+// This class implements a client pointer that represents one or more input
 // devices, such as mice, which control the pointer location and pointer focus.
 class Pointer : public ui::EventHandler, public SurfaceObserver {
  public:
diff --git a/components/exo/touch.cc b/components/exo/touch.cc
new file mode 100644
index 0000000..89fbda6f
--- /dev/null
+++ b/components/exo/touch.cc
@@ -0,0 +1,149 @@
+// 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/exo/touch.h"
+
+#include "ash/shell.h"
+#include "components/exo/surface.h"
+#include "components/exo/touch_delegate.h"
+#include "ui/aura/window.h"
+#include "ui/events/event.h"
+
+namespace exo {
+namespace {
+
+// Helper function that returns an iterator to the first item in |vector|
+// with |value|.
+template <typename T, typename U>
+typename T::iterator FindVectorItem(T& vector, U value) {
+  return std::find(vector.begin(), vector.end(), value);
+}
+
+// Helper function that returns true if |vector| contains an item with |value|.
+template <typename T, typename U>
+bool VectorContainsItem(T& vector, U value) {
+  return FindVectorItem(vector, value) != vector.end();
+}
+
+}  // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// Touch, public:
+
+Touch::Touch(TouchDelegate* delegate) : delegate_(delegate), focus_(nullptr) {
+  ash::Shell::GetInstance()->AddPreTargetHandler(this);
+}
+
+Touch::~Touch() {
+  delegate_->OnTouchDestroying(this);
+  if (focus_)
+    focus_->RemoveSurfaceObserver(this);
+  ash::Shell::GetInstance()->RemovePreTargetHandler(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ui::EventHandler overrides:
+
+void Touch::OnTouchEvent(ui::TouchEvent* event) {
+  switch (event->type()) {
+    case ui::ET_TOUCH_PRESSED: {
+      // Early out if event doesn't contain a valid target for touch device.
+      Surface* target = GetEffectiveTargetForEvent(event);
+      if (!target)
+        return;
+
+      // If this is the first touch point then target becomes the focus surface
+      // until all touch points have been released.
+      if (touch_points_.empty()) {
+        DCHECK(!focus_);
+        focus_ = target;
+        focus_->AddSurfaceObserver(this);
+      }
+
+      DCHECK(!VectorContainsItem(touch_points_, event->touch_id()));
+      touch_points_.push_back(event->touch_id());
+
+      // Convert location to focus surface coordinate space.
+      DCHECK(focus_);
+      gfx::Point location = event->location();
+      aura::Window::ConvertPointToTarget(target, focus_, &location);
+
+      // Generate a touch down event for the focus surface. Note that this can
+      // be different from the target surface.
+      delegate_->OnTouchDown(focus_, event->time_stamp(), event->touch_id(),
+                             location);
+    } break;
+    case ui::ET_TOUCH_RELEASED: {
+      auto it = FindVectorItem(touch_points_, event->touch_id());
+      if (it != touch_points_.end()) {
+        touch_points_.erase(it);
+
+        // Reset focus surface if this is the last touch point.
+        if (touch_points_.empty()) {
+          DCHECK(focus_);
+          focus_->RemoveSurfaceObserver(this);
+          focus_ = nullptr;
+        }
+
+        delegate_->OnTouchUp(event->time_stamp(), event->touch_id());
+      }
+    } break;
+    case ui::ET_TOUCH_MOVED: {
+      auto it = FindVectorItem(touch_points_, event->touch_id());
+      if (it != touch_points_.end()) {
+        DCHECK(focus_);
+        // Convert location to focus surface coordinate space.
+        gfx::Point location = event->location();
+        aura::Window::ConvertPointToTarget(
+            static_cast<aura::Window*>(event->target()), focus_, &location);
+
+        delegate_->OnTouchMotion(event->time_stamp(), event->touch_id(),
+                                 location);
+      }
+    } break;
+    case ui::ET_TOUCH_CANCELLED: {
+      auto it = FindVectorItem(touch_points_, event->touch_id());
+      if (it != touch_points_.end()) {
+        DCHECK(focus_);
+        focus_->RemoveSurfaceObserver(this);
+        focus_ = nullptr;
+
+        // Cancel the full set of touch sequences as soon as one is canceled.
+        touch_points_.clear();
+        delegate_->OnTouchCancel();
+      }
+    } break;
+    default:
+      NOTREACHED();
+      break;
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// SurfaceObserver overrides:
+
+void Touch::OnSurfaceDestroying(Surface* surface) {
+  DCHECK(surface == focus_);
+  focus_ = nullptr;
+  surface->RemoveSurfaceObserver(this);
+
+  // Cancel touch sequences.
+  DCHECK_NE(touch_points_.size(), 0u);
+  touch_points_.clear();
+  delegate_->OnTouchCancel();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Touch, private:
+
+Surface* Touch::GetEffectiveTargetForEvent(ui::Event* event) const {
+  Surface* target =
+      Surface::AsSurface(static_cast<aura::Window*>(event->target()));
+  if (!target)
+    return nullptr;
+
+  return delegate_->CanAcceptTouchEventsForSurface(target) ? target : nullptr;
+}
+
+}  // namespace exo
diff --git a/components/exo/touch.h b/components/exo/touch.h
new file mode 100644
index 0000000..664a3e62
--- /dev/null
+++ b/components/exo/touch.h
@@ -0,0 +1,52 @@
+// 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_EXO_TOUCH_H_
+#define COMPONENTS_EXO_TOUCH_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "components/exo/surface_observer.h"
+#include "ui/events/event_handler.h"
+
+namespace ui {
+class TouchEvent;
+}
+
+namespace exo {
+class TouchDelegate;
+
+// This class implements a client touch device that represents one or more
+// touch devices.
+class Touch : public ui::EventHandler, public SurfaceObserver {
+ public:
+  explicit Touch(TouchDelegate* delegate);
+  ~Touch() override;
+
+  // Overridden from ui::EventHandler:
+  void OnTouchEvent(ui::TouchEvent* event) override;
+
+  // Overridden from SurfaceObserver:
+  void OnSurfaceDestroying(Surface* surface) override;
+
+ private:
+  // Returns the effective target for |event|.
+  Surface* GetEffectiveTargetForEvent(ui::Event* event) const;
+
+  // The delegate instance that all events are dispatched to.
+  TouchDelegate* delegate_;
+
+  // The current focus surface for the touch device.
+  Surface* focus_;
+
+  // Vector of touch points in focus surface.
+  std::vector<int> touch_points_;
+
+  DISALLOW_COPY_AND_ASSIGN(Touch);
+};
+
+}  // namespace exo
+
+#endif  // COMPONENTS_EXO_TOUCH_H_
diff --git a/components/exo/touch_delegate.h b/components/exo/touch_delegate.h
new file mode 100644
index 0000000..d51c04c
--- /dev/null
+++ b/components/exo/touch_delegate.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 COMPONENTS_EXO_TOUCH_DELEGATE_H_
+#define COMPONENTS_EXO_TOUCH_DELEGATE_H_
+
+#include "base/time/time.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace exo {
+class Surface;
+class Touch;
+
+// Handles events on touch devices in context-specific ways.
+class TouchDelegate {
+ public:
+  // Called at the top of the touch device's destructor, to give observers a
+  // chance to remove themselves.
+  virtual void OnTouchDestroying(Touch* touch) = 0;
+
+  // This should return true if |surface| is a valid target for this touch
+  // device. E.g. the surface is owned by the same client as the touch device.
+  virtual bool CanAcceptTouchEventsForSurface(Surface* surface) const = 0;
+
+  // Called when a new touch point has appeared on the surface. This touch
+  // point is assigned a unique ID. Future events from this touch point
+  // reference this ID. |location| is the initial location of touch point
+  // relative to the origin of the surface.
+  virtual void OnTouchDown(Surface* surface,
+                           base::TimeDelta time_stamp,
+                           int id,
+                           const gfx::Point& location) = 0;
+
+  // Called when a touch point has disappeared. No further events will be sent
+  // for this touch point.
+  virtual void OnTouchUp(base::TimeDelta time_stamp, int id) = 0;
+
+  // Called when a touch point has changed coordinates.
+  virtual void OnTouchMotion(base::TimeDelta time_stamp,
+                             int id,
+                             const gfx::Point& location) = 0;
+
+  // Called when the touch session has been canceled. Touch cancellation
+  // applies to all touch points currently active.
+  virtual void OnTouchCancel() = 0;
+
+ protected:
+  virtual ~TouchDelegate() {}
+};
+
+}  // namespace exo
+
+#endif  // COMPONENTS_EXO_TOUCH_DELEGATE_H_
diff --git a/components/exo/touch_unittest.cc b/components/exo/touch_unittest.cc
new file mode 100644
index 0000000..afe8fcb
--- /dev/null
+++ b/components/exo/touch_unittest.cc
@@ -0,0 +1,196 @@
+// 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 "ash/shell.h"
+#include "ash/wm/window_positioner.h"
+#include "ash/wm/window_util.h"
+#include "components/exo/buffer.h"
+#include "components/exo/shell_surface.h"
+#include "components/exo/surface.h"
+#include "components/exo/test/exo_test_base.h"
+#include "components/exo/test/exo_test_helper.h"
+#include "components/exo/touch.h"
+#include "components/exo/touch_delegate.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/khronos/GLES2/gl2.h"
+#include "ui/events/test/event_generator.h"
+#include "ui/views/widget/widget.h"
+
+namespace exo {
+namespace {
+
+using TouchTest = test::ExoTestBase;
+
+class MockTouchDelegate : public TouchDelegate {
+ public:
+  MockTouchDelegate() {}
+
+  // Overridden from TouchDelegate:
+  MOCK_METHOD1(OnTouchDestroying, void(Touch*));
+  MOCK_CONST_METHOD1(CanAcceptTouchEventsForSurface, bool(Surface*));
+  MOCK_METHOD4(OnTouchDown,
+               void(Surface*, base::TimeDelta, int, const gfx::Point&));
+  MOCK_METHOD2(OnTouchUp, void(base::TimeDelta, int));
+  MOCK_METHOD3(OnTouchMotion, void(base::TimeDelta, int, const gfx::Point&));
+  MOCK_METHOD0(OnTouchCancel, void());
+};
+
+TEST_F(TouchTest, OnTouchDown) {
+  ash::WindowPositioner::DisableAutoPositioning(true);
+
+  scoped_ptr<Surface> bottom_surface(new Surface);
+  scoped_ptr<ShellSurface> bottom_shell_surface(
+      new ShellSurface(bottom_surface.get()));
+  bottom_shell_surface->SetToplevel();
+  gfx::Size bottom_buffer_size(10, 10);
+  scoped_ptr<Buffer> bottom_buffer(new Buffer(
+      exo_test_helper()->CreateGpuMemoryBuffer(bottom_buffer_size).Pass(),
+      GL_TEXTURE_2D));
+  bottom_surface->Attach(bottom_buffer.get());
+  bottom_surface->Commit();
+  ash::wm::CenterWindow(bottom_shell_surface->GetWidget()->GetNativeWindow());
+
+  scoped_ptr<Surface> top_surface(new Surface);
+  scoped_ptr<ShellSurface> top_shell_surface(
+      new ShellSurface(top_surface.get()));
+  top_shell_surface->SetToplevel();
+  gfx::Size top_buffer_size(8, 8);
+  scoped_ptr<Buffer> top_buffer(new Buffer(
+      exo_test_helper()->CreateGpuMemoryBuffer(top_buffer_size).Pass(),
+      GL_TEXTURE_2D));
+  top_surface->Attach(top_buffer.get());
+  top_surface->Commit();
+  ash::wm::CenterWindow(top_shell_surface->GetWidget()->GetNativeWindow());
+
+  MockTouchDelegate delegate;
+  scoped_ptr<Touch> touch(new Touch(&delegate));
+  ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+
+  EXPECT_CALL(delegate, CanAcceptTouchEventsForSurface(top_surface.get()))
+      .WillRepeatedly(testing::Return(true));
+  EXPECT_CALL(delegate,
+              OnTouchDown(top_surface.get(), testing::_, 1, gfx::Point()));
+  generator.set_current_location(top_surface->GetBoundsInScreen().origin());
+  generator.PressTouchId(1);
+
+  EXPECT_CALL(delegate, CanAcceptTouchEventsForSurface(bottom_surface.get()))
+      .WillRepeatedly(testing::Return(true));
+  // Second touch point should be relative to the focus surface.
+  EXPECT_CALL(delegate, OnTouchDown(top_surface.get(), testing::_, 2,
+                                    gfx::Point(-1, -1)));
+  generator.set_current_location(bottom_surface->GetBoundsInScreen().origin());
+  generator.PressTouchId(2);
+
+  EXPECT_CALL(delegate, OnTouchDestroying(touch.get()));
+  touch.reset();
+}
+
+TEST_F(TouchTest, OnTouchUp) {
+  scoped_ptr<Surface> surface(new Surface);
+  scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+  shell_surface->SetToplevel();
+  gfx::Size buffer_size(10, 10);
+  scoped_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(),
+                 GL_TEXTURE_2D));
+  surface->Attach(buffer.get());
+  surface->Commit();
+
+  MockTouchDelegate delegate;
+  scoped_ptr<Touch> touch(new Touch(&delegate));
+  ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+
+  EXPECT_CALL(delegate, CanAcceptTouchEventsForSurface(surface.get()))
+      .WillRepeatedly(testing::Return(true));
+  EXPECT_CALL(delegate,
+              OnTouchDown(surface.get(), testing::_, testing::_, gfx::Point()))
+      .Times(2);
+  generator.set_current_location(surface->GetBoundsInScreen().origin());
+  generator.PressTouchId(1);
+  generator.PressTouchId(2);
+
+  EXPECT_CALL(delegate, OnTouchUp(testing::_, 1));
+  generator.ReleaseTouchId(1);
+  EXPECT_CALL(delegate, OnTouchUp(testing::_, 2));
+  generator.ReleaseTouchId(2);
+
+  EXPECT_CALL(delegate, OnTouchDestroying(touch.get()));
+  touch.reset();
+}
+
+TEST_F(TouchTest, OnTouchMotion) {
+  scoped_ptr<Surface> surface(new Surface);
+  scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+  shell_surface->SetToplevel();
+  gfx::Size buffer_size(10, 10);
+  scoped_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(),
+                 GL_TEXTURE_2D));
+  surface->Attach(buffer.get());
+  surface->Commit();
+
+  MockTouchDelegate delegate;
+  scoped_ptr<Touch> touch(new Touch(&delegate));
+  ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+
+  EXPECT_CALL(delegate, CanAcceptTouchEventsForSurface(surface.get()))
+      .WillRepeatedly(testing::Return(true));
+  EXPECT_CALL(delegate,
+              OnTouchDown(surface.get(), testing::_, testing::_, gfx::Point()));
+  EXPECT_CALL(delegate,
+              OnTouchMotion(testing::_, testing::_, gfx::Point(5, 5)));
+  EXPECT_CALL(delegate, OnTouchUp(testing::_, testing::_));
+  generator.set_current_location(surface->GetBoundsInScreen().origin());
+  generator.PressMoveAndReleaseTouchBy(5, 5);
+
+  // Check if touch point motion outside focus surface is reported properly to
+  // the focus surface.
+  EXPECT_CALL(delegate,
+              OnTouchDown(surface.get(), testing::_, testing::_, gfx::Point()));
+  EXPECT_CALL(delegate,
+              OnTouchMotion(testing::_, testing::_, gfx::Point(100, 100)));
+  EXPECT_CALL(delegate, OnTouchUp(testing::_, testing::_));
+  generator.set_current_location(surface->GetBoundsInScreen().origin());
+  generator.PressMoveAndReleaseTouchBy(100, 100);
+
+  EXPECT_CALL(delegate, OnTouchDestroying(touch.get()));
+  touch.reset();
+}
+
+TEST_F(TouchTest, OnTouchCancel) {
+  scoped_ptr<Surface> surface(new Surface);
+  scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+  shell_surface->SetToplevel();
+  gfx::Size buffer_size(10, 10);
+  scoped_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(),
+                 GL_TEXTURE_2D));
+  surface->Attach(buffer.get());
+  surface->Commit();
+
+  MockTouchDelegate delegate;
+  scoped_ptr<Touch> touch(new Touch(&delegate));
+  ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+
+  EXPECT_CALL(delegate, CanAcceptTouchEventsForSurface(surface.get()))
+      .WillRepeatedly(testing::Return(true));
+  EXPECT_CALL(delegate,
+              OnTouchDown(surface.get(), testing::_, testing::_, gfx::Point()))
+      .Times(2);
+  generator.set_current_location(surface->GetBoundsInScreen().origin());
+  generator.PressTouchId(1);
+  generator.PressTouchId(2);
+
+  // One touch point being canceled is enough for OnTouchCancel to be called.
+  EXPECT_CALL(delegate, OnTouchCancel());
+  ui::TouchEvent cancel_event(ui::ET_TOUCH_CANCELLED, gfx::Point(), 1,
+                              generator.Now());
+  generator.Dispatch(&cancel_event);
+
+  EXPECT_CALL(delegate, OnTouchDestroying(touch.get()));
+  touch.reset();
+}
+
+}  // namespace
+}  // namespace exo
diff --git a/components/exo/wayland/BUILD.gn b/components/exo/wayland/BUILD.gn
index 1d07dd5..4b184088 100644
--- a/components/exo/wayland/BUILD.gn
+++ b/components/exo/wayland/BUILD.gn
@@ -2,8 +2,15 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/linux/pkg_config.gni")
 import("//build/config/ui.gni")
 
+if (use_xkbcommon) {
+  pkg_config("xkbcommon") {
+    packages = [ "xkbcommon" ]
+  }
+}
+
 source_set("wayland") {
   sources = [
     "scoped_wl.cc",
@@ -20,11 +27,19 @@
     "//skia",
     "//third_party/wayland:wayland_server",
     "//third_party/wayland-protocols:xdg_shell_protocol",
+    "//ui/events:dom_keycode_converter",
+    "//ui/events:events_base",
   ]
 
   if (use_ozone) {
     deps += [ "//third_party/mesa:wayland_drm_protocol" ]
   }
+
+  if (use_xkbcommon) {
+    configs += [ ":xkbcommon" ]
+
+    defines += [ "USE_XKBCOMMON" ]
+  }
 }
 
 source_set("unit_tests") {
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc
index abd703b..2bb39324 100644
--- a/components/exo/wayland/server.cc
+++ b/components/exo/wayland/server.cc
@@ -16,19 +16,29 @@
 #include "base/strings/utf_string_conversions.h"
 #include "components/exo/buffer.h"
 #include "components/exo/display.h"
+#include "components/exo/keyboard.h"
+#include "components/exo/keyboard_delegate.h"
 #include "components/exo/pointer.h"
 #include "components/exo/pointer_delegate.h"
 #include "components/exo/shared_memory.h"
 #include "components/exo/shell_surface.h"
 #include "components/exo/sub_surface.h"
 #include "components/exo/surface.h"
+#include "components/exo/touch.h"
+#include "components/exo/touch_delegate.h"
 #include "third_party/skia/include/core/SkRegion.h"
 #include "ui/aura/window_property.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
 
 #if defined(USE_OZONE)
 #include <wayland-drm-server-protocol.h>
 #endif
 
+#if defined(USE_XKBCOMMON)
+#include <xkbcommon/xkbcommon.h>
+#include "ui/events/keycodes/scoped_xkb.h"
+#endif
+
 DECLARE_WINDOW_PROPERTY_TYPE(wl_resource*);
 
 namespace exo {
@@ -382,10 +392,11 @@
     wl_shm_send_format(resource, supported_format.shm_format);
 }
 
+#if defined(USE_OZONE)
+
 ////////////////////////////////////////////////////////////////////////////////
 // wl_drm_interface:
 
-#if defined(USE_OZONE)
 const struct drm_supported_format {
   uint32_t drm_format;
   gfx::BufferFormat buffer_format;
@@ -1081,6 +1092,228 @@
 const struct wl_pointer_interface pointer_implementation = {pointer_set_cursor,
                                                             pointer_release};
 
+#if defined(USE_XKBCOMMON)
+
+////////////////////////////////////////////////////////////////////////////////
+// wl_keyboard_interface:
+
+// Keyboard delegate class that accepts events for surfaces owned by the same
+// client as a keyboard resource.
+class WaylandKeyboardDelegate : public KeyboardDelegate {
+ public:
+  explicit WaylandKeyboardDelegate(wl_resource* keyboard_resource)
+      : keyboard_resource_(keyboard_resource),
+        xkb_context_(xkb_context_new(XKB_CONTEXT_NO_FLAGS)),
+        // TODO(reveman): Keep keymap synchronized with the keymap used by
+        // chromium and the host OS.
+        xkb_keymap_(xkb_keymap_new_from_names(xkb_context_.get(),
+                                              nullptr,
+                                              XKB_KEYMAP_COMPILE_NO_FLAGS)),
+        xkb_state_(xkb_state_new(xkb_keymap_.get())) {
+    scoped_ptr<char, base::FreeDeleter> keymap_string(
+        xkb_keymap_get_as_string(xkb_keymap_.get(), XKB_KEYMAP_FORMAT_TEXT_V1));
+    DCHECK(keymap_string.get());
+    size_t keymap_size = strlen(keymap_string.get()) + 1;
+    base::SharedMemory shared_keymap;
+    bool rv = shared_keymap.CreateAndMapAnonymous(keymap_size);
+    DCHECK(rv);
+    memcpy(shared_keymap.memory(), keymap_string.get(), keymap_size);
+    wl_keyboard_send_keymap(keyboard_resource_,
+                            WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
+                            shared_keymap.handle().fd, keymap_size);
+  }
+
+  // Overridden from KeyboardDelegate:
+  void OnKeyboardDestroying(Keyboard* keyboard) override { delete this; }
+  bool CanAcceptKeyboardEventsForSurface(Surface* surface) const override {
+    wl_resource* surface_resource = surface->GetProperty(kSurfaceResourceKey);
+    // We can accept events for this surface if the client is the same as the
+    // keyboard.
+    return surface_resource &&
+           wl_resource_get_client(surface_resource) == client();
+  }
+  void OnKeyboardEnter(Surface* surface,
+                       const std::vector<ui::DomCode>& pressed_keys) override {
+    wl_resource* surface_resource = surface->GetProperty(kSurfaceResourceKey);
+    DCHECK(surface_resource);
+    wl_array keys;
+    wl_array_init(&keys);
+    for (auto key : pressed_keys) {
+      uint32_t* value =
+          static_cast<uint32_t*>(wl_array_add(&keys, sizeof(uint32_t)));
+      DCHECK(value);
+      *value = DomCodeToKey(key);
+    }
+    wl_keyboard_send_enter(keyboard_resource_, next_serial(), surface_resource,
+                           &keys);
+    wl_array_release(&keys);
+    wl_client_flush(client());
+  }
+  void OnKeyboardLeave(Surface* surface) override {
+    wl_resource* surface_resource = surface->GetProperty(kSurfaceResourceKey);
+    DCHECK(surface_resource);
+    wl_keyboard_send_leave(keyboard_resource_, next_serial(), surface_resource);
+    wl_client_flush(client());
+  }
+  void OnKeyboardKey(base::TimeDelta time_stamp,
+                     ui::DomCode key,
+                     bool pressed) override {
+    wl_keyboard_send_key(keyboard_resource_, next_serial(),
+                         time_stamp.InMilliseconds(), DomCodeToKey(key),
+                         pressed ? WL_KEYBOARD_KEY_STATE_PRESSED
+                                 : WL_KEYBOARD_KEY_STATE_RELEASED);
+    wl_client_flush(client());
+  }
+  void OnKeyboardModifiers(int modifier_flags) override {
+    xkb_state_update_mask(xkb_state_.get(),
+                          ModifierFlagsToXkbModifiers(modifier_flags), 0, 0, 0,
+                          0, 0);
+    wl_keyboard_send_modifiers(
+        keyboard_resource_, next_serial(),
+        xkb_state_serialize_mods(xkb_state_.get(), XKB_STATE_MODS_DEPRESSED),
+        xkb_state_serialize_mods(xkb_state_.get(), XKB_STATE_MODS_LOCKED),
+        xkb_state_serialize_mods(xkb_state_.get(), XKB_STATE_MODS_LATCHED),
+        xkb_state_serialize_layout(xkb_state_.get(),
+                                   XKB_STATE_LAYOUT_EFFECTIVE));
+    wl_client_flush(client());
+  }
+
+ private:
+  // Returns the corresponding key given a dom code.
+  uint32_t DomCodeToKey(ui::DomCode code) const {
+    // This assumes KeycodeConverter has been built with evdev/xkb codes.
+    xkb_keycode_t xkb_keycode = static_cast<xkb_keycode_t>(
+        ui::KeycodeConverter::DomCodeToNativeKeycode(code));
+
+    // Keycodes are offset by 8 in Xkb.
+    DCHECK_GE(xkb_keycode, 8u);
+    return xkb_keycode - 8;
+  }
+
+  // Returns a set of Xkb modififers given a set of modifier flags.
+  uint32_t ModifierFlagsToXkbModifiers(int modifier_flags) {
+    struct {
+      ui::EventFlags flag;
+      const char* xkb_name;
+    } modifiers[] = {
+        {ui::EF_SHIFT_DOWN, XKB_MOD_NAME_SHIFT},
+        {ui::EF_CAPS_LOCK_DOWN, XKB_MOD_NAME_CAPS},
+        {ui::EF_CONTROL_DOWN, XKB_MOD_NAME_CTRL},
+        {ui::EF_ALT_DOWN, XKB_MOD_NAME_ALT},
+        {ui::EF_NUM_LOCK_DOWN, XKB_MOD_NAME_NUM},
+        {ui::EF_MOD3_DOWN, "Mod3"},
+        {ui::EF_COMMAND_DOWN, XKB_MOD_NAME_LOGO},
+        {ui::EF_ALTGR_DOWN, "Mod5"},
+    };
+    uint32_t xkb_modifiers = 0;
+    for (auto modifier : modifiers) {
+      if (modifier_flags & modifier.flag) {
+        xkb_modifiers |=
+            1 << xkb_keymap_mod_get_index(xkb_keymap_.get(), modifier.xkb_name);
+      }
+    }
+    return xkb_modifiers;
+  }
+
+  // The client who own this keyboard instance.
+  wl_client* client() const {
+    return wl_resource_get_client(keyboard_resource_);
+  }
+
+  // Returns the next serial to use for keyboard events.
+  uint32_t next_serial() const {
+    return wl_display_next_serial(wl_client_get_display(client()));
+  }
+
+  // The keyboard resource associated with the keyboard.
+  wl_resource* const keyboard_resource_;
+
+  // The Xkb state used for the keyboard.
+  scoped_ptr<xkb_context, ui::XkbContextDeleter> xkb_context_;
+  scoped_ptr<xkb_keymap, ui::XkbKeymapDeleter> xkb_keymap_;
+  scoped_ptr<xkb_state, ui::XkbStateDeleter> xkb_state_;
+
+  DISALLOW_COPY_AND_ASSIGN(WaylandKeyboardDelegate);
+};
+
+void keyboard_release(wl_client* client, wl_resource* resource) {
+  wl_resource_destroy(resource);
+}
+
+const struct wl_keyboard_interface keyboard_implementation = {keyboard_release};
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// wl_touch_interface:
+
+// Touch delegate class that accepts events for surfaces owned by the same
+// client as a touch resource.
+class WaylandTouchDelegate : public TouchDelegate {
+ public:
+  explicit WaylandTouchDelegate(wl_resource* touch_resource)
+      : touch_resource_(touch_resource) {}
+
+  // Overridden from TouchDelegate:
+  void OnTouchDestroying(Touch* touch) override { delete this; }
+  bool CanAcceptTouchEventsForSurface(Surface* surface) const override {
+    wl_resource* surface_resource = surface->GetProperty(kSurfaceResourceKey);
+    // We can accept events for this surface if the client is the same as the
+    // touch resource.
+    return surface_resource &&
+           wl_resource_get_client(surface_resource) == client();
+  }
+  void OnTouchDown(Surface* surface,
+                   base::TimeDelta time_stamp,
+                   int id,
+                   const gfx::Point& location) override {
+    wl_resource* surface_resource = surface->GetProperty(kSurfaceResourceKey);
+    DCHECK(surface_resource);
+    wl_touch_send_down(touch_resource_, next_serial(),
+                       time_stamp.InMilliseconds(), surface_resource, id,
+                       wl_fixed_from_int(location.x()),
+                       wl_fixed_from_int(location.y()));
+    wl_client_flush(client());
+  }
+  void OnTouchUp(base::TimeDelta time_stamp, int id) override {
+    wl_touch_send_up(touch_resource_, next_serial(),
+                     time_stamp.InMilliseconds(), id);
+    wl_client_flush(client());
+  }
+  void OnTouchMotion(base::TimeDelta time_stamp,
+                     int id,
+                     const gfx::Point& location) override {
+    wl_touch_send_motion(touch_resource_, time_stamp.InMilliseconds(), id,
+                         wl_fixed_from_int(location.x()),
+                         wl_fixed_from_int(location.y()));
+    wl_client_flush(client());
+  }
+  void OnTouchCancel() override {
+    wl_touch_send_cancel(touch_resource_);
+    wl_client_flush(client());
+  }
+
+ private:
+  // The client who own this touch instance.
+  wl_client* client() const { return wl_resource_get_client(touch_resource_); }
+
+  // Returns the next serial to use for keyboard events.
+  uint32_t next_serial() const {
+    return wl_display_next_serial(wl_client_get_display(client()));
+  }
+
+  // The touch resource associated with the touch.
+  wl_resource* const touch_resource_;
+
+  DISALLOW_COPY_AND_ASSIGN(WaylandTouchDelegate);
+};
+
+void touch_release(wl_client* client, wl_resource* resource) {
+  wl_resource_destroy(resource);
+}
+
+const struct wl_touch_interface touch_implementation = {touch_release};
+
 ////////////////////////////////////////////////////////////////////////////////
 // wl_seat_interface:
 
@@ -1098,11 +1331,38 @@
 }
 
 void seat_get_keyboard(wl_client* client, wl_resource* resource, uint32_t id) {
+#if defined(USE_XKBCOMMON)
+  uint32_t version = wl_resource_get_version(resource);
+  wl_resource* keyboard_resource =
+      wl_resource_create(client, &wl_keyboard_interface, version, id);
+  if (!keyboard_resource) {
+    wl_resource_post_no_memory(resource);
+    return;
+  }
+
+  SetImplementation(keyboard_resource, &keyboard_implementation,
+                    make_scoped_ptr(new Keyboard(
+                        new WaylandKeyboardDelegate(keyboard_resource))));
+
+  // TODO(reveman): Keep repeat info synchronized with chromium and the host OS.
+  if (version >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
+    wl_keyboard_send_repeat_info(keyboard_resource, 40, 500);
+#else
   NOTIMPLEMENTED();
+#endif
 }
 
 void seat_get_touch(wl_client* client, wl_resource* resource, uint32_t id) {
-  NOTIMPLEMENTED();
+  wl_resource* touch_resource = wl_resource_create(
+      client, &wl_touch_interface, wl_resource_get_version(resource), id);
+  if (!touch_resource) {
+    wl_resource_post_no_memory(resource);
+    return;
+  }
+
+  SetImplementation(
+      touch_resource, &touch_implementation,
+      make_scoped_ptr(new Touch(new WaylandTouchDelegate(touch_resource))));
 }
 
 const struct wl_seat_interface seat_implementation = {
@@ -1123,7 +1383,11 @@
   if (version >= WL_SEAT_NAME_SINCE_VERSION)
     wl_seat_send_name(resource, "default");
 
-  wl_seat_send_capabilities(resource, WL_SEAT_CAPABILITY_POINTER);
+  uint32_t capabilities = WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_TOUCH;
+#if defined(USE_XKBCOMMON)
+  capabilities |= WL_SEAT_CAPABILITY_KEYBOARD;
+#endif
+  wl_seat_send_capabilities(resource, capabilities);
 }
 
 }  // namespace
diff --git a/components/guest_view/OWNERS b/components/guest_view/OWNERS
index f63f04f..434ce080 100644
--- a/components/guest_view/OWNERS
+++ b/components/guest_view/OWNERS
@@ -1,4 +1,5 @@
 fsamuel@chromium.org
-lazyboy@chromium.org
 hanxi@chromium.org
+lazyboy@chromium.org
+lfg@chromium.org
 wjmaclean@chromium.org
diff --git a/components/metrics.gypi b/components/metrics.gypi
index ef38c378..e889923 100644
--- a/components/metrics.gypi
+++ b/components/metrics.gypi
@@ -240,6 +240,34 @@
         },
       ],
     }],
+    ['chromeos==1', {
+      'targets': [
+        {
+          # GN version: //components/metrics:leak_detector
+          'target_name': 'metrics_leak_detector',
+          'type': 'static_library',
+          'dependencies': [
+            '../base/base.gyp:base',
+          ],
+          'sources': [
+            'metrics/leak_detector/call_stack_manager.cc',
+            'metrics/leak_detector/call_stack_manager.h',
+            'metrics/leak_detector/call_stack_table.cc',
+            'metrics/leak_detector/call_stack_table.h',
+            'metrics/leak_detector/custom_allocator.cc',
+            'metrics/leak_detector/custom_allocator.h',
+            'metrics/leak_detector/leak_analyzer.cc',
+            'metrics/leak_detector/leak_analyzer.h',
+            'metrics/leak_detector/leak_detector_impl.cc',
+            'metrics/leak_detector/leak_detector_impl.h',
+            'metrics/leak_detector/leak_detector_value_type.cc',
+            'metrics/leak_detector/leak_detector_value_type.h',
+            'metrics/leak_detector/ranked_list.cc',
+            'metrics/leak_detector/ranked_list.h',
+          ],
+        },
+      ],
+    }],
     ['OS!="ios"', {
       'targets': [
         {
diff --git a/components/metrics/BUILD.gn b/components/metrics/BUILD.gn
index d321dee..2fe3be5 100644
--- a/components/metrics/BUILD.gn
+++ b/components/metrics/BUILD.gn
@@ -109,6 +109,32 @@
   }
 }
 
+if (is_chromeos) {
+  # GYP version: components/metrics.gypi:metrics_leak_detector
+  source_set("leak_detector") {
+    sources = [
+      "leak_detector/call_stack_manager.cc",
+      "leak_detector/call_stack_manager.h",
+      "leak_detector/call_stack_table.cc",
+      "leak_detector/call_stack_table.h",
+      "leak_detector/custom_allocator.cc",
+      "leak_detector/custom_allocator.h",
+      "leak_detector/leak_analyzer.cc",
+      "leak_detector/leak_analyzer.h",
+      "leak_detector/leak_detector_impl.cc",
+      "leak_detector/leak_detector_impl.h",
+      "leak_detector/leak_detector_value_type.cc",
+      "leak_detector/leak_detector_value_type.h",
+      "leak_detector/ranked_list.cc",
+      "leak_detector/ranked_list.h",
+    ]
+
+    deps = [
+      "//base",
+    ]
+  }
+}
+
 # GYP version: components/metrics.gypi:metrics_net
 static_library("net") {
   sources = [
@@ -249,6 +275,25 @@
   }
 }
 
+if (is_chromeos) {
+  source_set("leak_detector_unit_tests") {
+    testonly = true
+    sources = [
+      "leak_detector/call_stack_manager_unittest.cc",
+      "leak_detector/call_stack_table_unittest.cc",
+      "leak_detector/leak_analyzer_unittest.cc",
+      "leak_detector/leak_detector_impl_unittest.cc",
+      "leak_detector/ranked_list_unittest.cc",
+    ]
+
+    deps = [
+      ":leak_detector",
+      "//base",
+      "//testing/gtest",
+    ]
+  }
+}
+
 source_set("unit_tests") {
   testonly = true
   sources = [
@@ -290,5 +335,9 @@
     sources += [ "serialization/serialization_utils_unittest.cc" ]
     deps += [ ":serialization" ]
   }
+
+  if (is_chromeos) {
+    deps += [ ":leak_detector_unit_tests" ]
+  }
 }
 # TODO(GYP): metrics_chromeos
diff --git a/components/metrics/leak_detector/OWNERS b/components/metrics/leak_detector/OWNERS
new file mode 100644
index 0000000..d8bfc45
--- /dev/null
+++ b/components/metrics/leak_detector/OWNERS
@@ -0,0 +1,2 @@
+sque@chromium.org
+wfh@chromium.org
diff --git a/components/metrics/leak_detector/call_stack_manager.cc b/components/metrics/leak_detector/call_stack_manager.cc
new file mode 100644
index 0000000..dfebd3c7
--- /dev/null
+++ b/components/metrics/leak_detector/call_stack_manager.cc
@@ -0,0 +1,72 @@
+// 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/metrics/leak_detector/call_stack_manager.h"
+
+#include <algorithm>  // For std::copy.
+#include <new>
+
+#include "base/hash.h"
+#include "components/metrics/leak_detector/custom_allocator.h"
+
+namespace metrics {
+namespace leak_detector {
+
+CallStackManager::CallStackManager() {}
+
+CallStackManager::~CallStackManager() {
+  // Free all call stack objects and clear |call_stacks_|. Make sure to save the
+  // CallStack object pointer and remove it from the container before freeing
+  // the CallStack memory.
+  while (!call_stacks_.empty()) {
+    CallStack* call_stack = *call_stacks_.begin();
+    call_stacks_.erase(call_stacks_.begin());
+
+    CustomAllocator::Free(call_stack->stack,
+                          call_stack->depth * sizeof(*call_stack->stack));
+    call_stack->stack = nullptr;
+    call_stack->depth = 0;
+
+    CustomAllocator::Free(call_stack, sizeof(CallStack));
+  }
+}
+
+const CallStack* CallStackManager::GetCallStack(size_t depth,
+                                                const void* const stack[]) {
+  // Temporarily create a call stack object for lookup in |call_stacks_|.
+  CallStack temp;
+  temp.depth = depth;
+  temp.stack = const_cast<const void**>(stack);
+  // This is the only place where the call stack's hash is computed. This value
+  // can be reused in the created object to avoid further hash computation.
+  temp.hash =
+      base::Hash(reinterpret_cast<const char*>(stack), sizeof(*stack) * depth);
+
+  auto iter = call_stacks_.find(&temp);
+  if (iter != call_stacks_.end())
+    return *iter;
+
+  // Since |call_stacks_| stores CallStack pointers rather than actual objects,
+  // create new call objects manually here.
+  CallStack* call_stack =
+      new (CustomAllocator::Allocate(sizeof(CallStack))) CallStack;
+  call_stack->depth = depth;
+  call_stack->hash = temp.hash;  // Don't run the hash function again.
+  call_stack->stack = reinterpret_cast<const void**>(
+      CustomAllocator::Allocate(sizeof(*stack) * depth));
+  std::copy(stack, stack + depth, call_stack->stack);
+
+  call_stacks_.insert(call_stack);
+  return call_stack;
+}
+
+bool CallStackManager::CallStackPointerEqual::operator()(
+    const CallStack* c1,
+    const CallStack* c2) const {
+  return c1->depth == c2->depth && c1->hash == c2->hash &&
+         std::equal(c1->stack, c1->stack + c1->depth, c2->stack);
+}
+
+}  // namespace leak_detector
+}  // namespace metrics
diff --git a/components/metrics/leak_detector/call_stack_manager.h b/components/metrics/leak_detector/call_stack_manager.h
new file mode 100644
index 0000000..6ea7d3c
--- /dev/null
+++ b/components/metrics/leak_detector/call_stack_manager.h
@@ -0,0 +1,101 @@
+// 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_METRICS_LEAK_DETECTOR_CALL_STACK_MANAGER_H_
+#define COMPONENTS_METRICS_LEAK_DETECTOR_CALL_STACK_MANAGER_H_
+
+#include <stdint.h>
+
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "components/metrics/leak_detector/custom_allocator.h"
+#include "components/metrics/leak_detector/stl_allocator.h"
+
+// Summary of structures:
+//
+// struct CallStack:
+//   Represents a unique call stack, defined by its raw call stack (array of
+//   pointers), and hash value. All CallStack objects are owned by class
+//   CallStackManager. Other classes may hold pointers to them but should not
+//   attempt to create or modify any CallStack objects.
+//
+// class CallStackManager:
+//   Creates CallStack objects to represent unique call stacks. Owns all
+//   CallStack objects that it creates, storing them internally.
+//
+//   Returns the call stacks as const pointers because no caller should take
+//   ownership of them and modify or delete them. The lifetime of all CallStack
+//   objects is limited to that of the CallStackManager object that created
+//   them. When the CallStackManager is destroyed, the CallStack objects will be
+//   invalidated. Hence the caller should make sure that it does not use
+//   CallStack objects beyond the lifetime of the CallStackManager that created
+//   them.
+
+namespace metrics {
+namespace leak_detector {
+
+// Struct to represent a call stack.
+struct CallStack {
+  // Call stack as an array of pointers, |stack|. The array length is stored in
+  // |depth|. There is no null terminator.
+  const void** stack;
+  size_t depth;
+
+  // Hash of call stack. It is cached here so that it doesn not have to be
+  // recomputed each time.
+  size_t hash;
+};
+
+// Maintains and owns all unique call stack objects.
+// Not thread-safe.
+class CallStackManager {
+ public:
+  CallStackManager();
+  ~CallStackManager();
+
+  // Returns a CallStack object for a given raw call stack. The first time a
+  // particular raw call stack is passed into this function, it will create a
+  // new CallStack object to hold the raw call stack data, and then return it.
+  // The CallStack object is stored internally.
+  //
+  // On subsequent calls with the same raw call stack, this function will return
+  // the previously created CallStack object.
+  const CallStack* GetCallStack(size_t depth, const void* const stack[]);
+
+  size_t size() const { return call_stacks_.size(); }
+
+ private:
+  // Allocator class for unique call stacks. Uses CustomAllocator to avoid
+  // recursive malloc hook invocation when analyzing allocs and frees.
+  using CallStackPointerAllocator = STLAllocator<CallStack*, CustomAllocator>;
+
+  // Hash operator for call stack object given as a pointer.
+  // Does not actually compute the hash. Instead, returns the already computed
+  // hash value stored in a CallStack object.
+  struct CallStackPointerStoredHash {
+    size_t operator()(const CallStack* call_stack) const {
+      return call_stack->hash;
+    }
+  };
+
+  // Equality comparator for call stack objects given as pointers. Compares
+  // their stack trace contents.
+  struct CallStackPointerEqual {
+    bool operator()(const CallStack* c1, const CallStack* c2) const;
+  };
+
+  // Holds all call stack objects. Each object is allocated elsewhere and stored
+  // as a pointer because the container may rearrange itself internally.
+  base::hash_set<CallStack*,
+                 CallStackPointerStoredHash,
+                 CallStackPointerEqual,
+                 CallStackPointerAllocator> call_stacks_;
+
+  DISALLOW_COPY_AND_ASSIGN(CallStackManager);
+};
+
+}  // namespace leak_detector
+}  // namespace metrics
+
+#endif  // COMPONENTS_METRICS_LEAK_DETECTOR_CALL_STACK_MANAGER_H_
diff --git a/components/metrics/leak_detector/call_stack_manager_unittest.cc b/components/metrics/leak_detector/call_stack_manager_unittest.cc
new file mode 100644
index 0000000..f71bbff
--- /dev/null
+++ b/components/metrics/leak_detector/call_stack_manager_unittest.cc
@@ -0,0 +1,260 @@
+// 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/metrics/leak_detector/call_stack_manager.h"
+
+#include <stdint.h>
+
+#include <algorithm>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "components/metrics/leak_detector/custom_allocator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+namespace leak_detector {
+
+namespace {
+
+// Some test call stacks. The addresses are 64-bit but they should automatically
+// be truncated to 32 bits on a 32-bit machine.
+const void* kRawStack0[] = {
+    reinterpret_cast<const void*>(0x8899aabbccddeeff),
+    reinterpret_cast<const void*>(0x0000112233445566),
+    reinterpret_cast<const void*>(0x5566778899aabbcc),
+    reinterpret_cast<const void*>(0x9988776655443322),
+};
+// This is similar to kRawStack0, differing only in one address by 1. It should
+// still produce a distinct CallStack object and hash.
+const void* kRawStack1[] = {
+    kRawStack0[0], kRawStack0[1],
+    reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(kRawStack0[2]) +
+                                  1),
+    kRawStack0[3],
+};
+const void* kRawStack2[] = {
+    reinterpret_cast<const void*>(0x900df00dcab58888),
+    reinterpret_cast<const void*>(0x00001337cafedeed),
+    reinterpret_cast<const void*>(0x0000deafbabe1234),
+};
+const void* kRawStack3[] = {
+    reinterpret_cast<const void*>(0x0000000012345678),
+    reinterpret_cast<const void*>(0x00000000abcdef01),
+    reinterpret_cast<const void*>(0x00000000fdecab98),
+    reinterpret_cast<const void*>(0x0000deadbeef0001),
+    reinterpret_cast<const void*>(0x0000900ddeed0002),
+    reinterpret_cast<const void*>(0x0000f00dcafe0003),
+    reinterpret_cast<const void*>(0x0000f00d900d0004),
+    reinterpret_cast<const void*>(0xdeedcafebabe0005),
+};
+
+// Creates a copy of a call stack as a scoped_ptr to a raw stack. The depth is
+// the same as the original stack, but it is not stored in the result.
+scoped_ptr<const void* []> CopyStack(const CallStack* stack) {
+  scoped_ptr<const void* []> stack_copy(new const void*[stack->depth]);
+  std::copy(stack->stack, stack->stack + stack->depth, stack_copy.get());
+  return stack_copy;
+}
+
+}  // namespace
+
+class CallStackManagerTest : public ::testing::Test {
+ public:
+  CallStackManagerTest() {}
+
+  void SetUp() override { CustomAllocator::Initialize(); }
+  void TearDown() override { EXPECT_TRUE(CustomAllocator::Shutdown()); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CallStackManagerTest);
+};
+
+TEST_F(CallStackManagerTest, NewStacks) {
+  CallStackManager manager;
+  EXPECT_EQ(0U, manager.size());
+
+  // Request some new stacks and make sure their creation is reflected in the
+  // size of |manager|.
+  const CallStack* stack0 =
+      manager.GetCallStack(arraysize(kRawStack0), kRawStack0);
+  EXPECT_EQ(arraysize(kRawStack0), stack0->depth);
+  EXPECT_EQ(1U, manager.size());
+
+  const CallStack* stack1 =
+      manager.GetCallStack(arraysize(kRawStack1), kRawStack1);
+  EXPECT_EQ(arraysize(kRawStack1), stack1->depth);
+  EXPECT_EQ(2U, manager.size());
+
+  const CallStack* stack2 =
+      manager.GetCallStack(arraysize(kRawStack2), kRawStack2);
+  EXPECT_EQ(arraysize(kRawStack2), stack2->depth);
+  EXPECT_EQ(3U, manager.size());
+
+  const CallStack* stack3 =
+      manager.GetCallStack(arraysize(kRawStack3), kRawStack3);
+  EXPECT_EQ(arraysize(kRawStack3), stack3->depth);
+  EXPECT_EQ(4U, manager.size());
+
+  // Call stack objects should be unique.
+  EXPECT_NE(stack0, stack1);
+  EXPECT_NE(stack0, stack2);
+  EXPECT_NE(stack0, stack3);
+  EXPECT_NE(stack1, stack2);
+  EXPECT_NE(stack1, stack3);
+  EXPECT_NE(stack2, stack3);
+}
+
+TEST_F(CallStackManagerTest, Hashes) {
+  CallStackManager manager;
+
+  const CallStack* stack0 =
+      manager.GetCallStack(arraysize(kRawStack0), kRawStack0);
+  const CallStack* stack1 =
+      manager.GetCallStack(arraysize(kRawStack1), kRawStack1);
+  const CallStack* stack2 =
+      manager.GetCallStack(arraysize(kRawStack2), kRawStack2);
+  const CallStack* stack3 =
+      manager.GetCallStack(arraysize(kRawStack3), kRawStack3);
+
+  // Hash values should be unique. This test is not designed to make sure the
+  // hash function is generating unique hashes, but that CallStackManager is
+  // properly storing the hashes in CallStack structs.
+  EXPECT_NE(stack0->hash, stack1->hash);
+  EXPECT_NE(stack0->hash, stack2->hash);
+  EXPECT_NE(stack0->hash, stack3->hash);
+  EXPECT_NE(stack1->hash, stack2->hash);
+  EXPECT_NE(stack1->hash, stack3->hash);
+  EXPECT_NE(stack2->hash, stack3->hash);
+}
+
+TEST_F(CallStackManagerTest, MultipleManagersHashes) {
+  CallStackManager manager1;
+  const CallStack* stack10 =
+      manager1.GetCallStack(arraysize(kRawStack0), kRawStack0);
+  const CallStack* stack11 =
+      manager1.GetCallStack(arraysize(kRawStack1), kRawStack1);
+  const CallStack* stack12 =
+      manager1.GetCallStack(arraysize(kRawStack2), kRawStack2);
+  const CallStack* stack13 =
+      manager1.GetCallStack(arraysize(kRawStack3), kRawStack3);
+
+  CallStackManager manager2;
+  const CallStack* stack20 =
+      manager2.GetCallStack(arraysize(kRawStack0), kRawStack0);
+  const CallStack* stack21 =
+      manager2.GetCallStack(arraysize(kRawStack1), kRawStack1);
+  const CallStack* stack22 =
+      manager2.GetCallStack(arraysize(kRawStack2), kRawStack2);
+  const CallStack* stack23 =
+      manager2.GetCallStack(arraysize(kRawStack3), kRawStack3);
+
+  // Different CallStackManagers should still generate the same hashes.
+  EXPECT_EQ(stack10->hash, stack20->hash);
+  EXPECT_EQ(stack11->hash, stack21->hash);
+  EXPECT_EQ(stack12->hash, stack22->hash);
+  EXPECT_EQ(stack13->hash, stack23->hash);
+}
+
+TEST_F(CallStackManagerTest, HashWithReducedDepth) {
+  CallStackManager manager;
+  const CallStack* stack =
+      manager.GetCallStack(arraysize(kRawStack3), kRawStack3);
+
+  // Hash function should only operate on the first |CallStack::depth| elements
+  // of CallStack::stack. To test this, reduce the depth value of one of the
+  // stacks and make sure the hash changes.
+  EXPECT_NE(stack->hash,
+            manager.GetCallStack(stack->depth - 1, stack->stack)->hash);
+  EXPECT_NE(stack->hash,
+            manager.GetCallStack(stack->depth - 2, stack->stack)->hash);
+  EXPECT_NE(stack->hash,
+            manager.GetCallStack(stack->depth - 3, stack->stack)->hash);
+  EXPECT_NE(stack->hash,
+            manager.GetCallStack(stack->depth - 4, stack->stack)->hash);
+
+  // Also try subsets of the stack that don't start from the beginning.
+  EXPECT_NE(stack->hash,
+            manager.GetCallStack(stack->depth - 1, stack->stack + 1)->hash);
+  EXPECT_NE(stack->hash,
+            manager.GetCallStack(stack->depth - 2, stack->stack + 2)->hash);
+  EXPECT_NE(stack->hash,
+            manager.GetCallStack(stack->depth - 3, stack->stack + 3)->hash);
+  EXPECT_NE(stack->hash,
+            manager.GetCallStack(stack->depth - 4, stack->stack + 4)->hash);
+}
+
+TEST_F(CallStackManagerTest, DuplicateStacks) {
+  CallStackManager manager;
+  EXPECT_EQ(0U, manager.size());
+
+  // Calling manager.GetCallStack() multiple times with the same raw stack
+  // arguments will not result in creation of new call stack objects after the
+  // first call. Instead, the previously created object will be returned, and
+  // the size of |manager| will remain unchanged.
+  //
+  // Thus a call to GetCallStack() will always return the same result, given the
+  // same inputs.
+
+  // Add stack0.
+  const CallStack* stack0 =
+      manager.GetCallStack(arraysize(kRawStack0), kRawStack0);
+
+  scoped_ptr<const void* []> rawstack0_duplicate0 = CopyStack(stack0);
+  const CallStack* stack0_duplicate0 =
+      manager.GetCallStack(arraysize(kRawStack0), rawstack0_duplicate0.get());
+  EXPECT_EQ(1U, manager.size());
+  EXPECT_EQ(stack0, stack0_duplicate0);
+
+  // Add stack1.
+  const CallStack* stack1 =
+      manager.GetCallStack(arraysize(kRawStack1), kRawStack1);
+  EXPECT_EQ(2U, manager.size());
+
+  scoped_ptr<const void* []> rawstack0_duplicate1 = CopyStack(stack0);
+  const CallStack* stack0_duplicate1 =
+      manager.GetCallStack(arraysize(kRawStack0), rawstack0_duplicate1.get());
+  EXPECT_EQ(2U, manager.size());
+  EXPECT_EQ(stack0, stack0_duplicate1);
+
+  scoped_ptr<const void* []> rawstack1_duplicate0 = CopyStack(stack1);
+  const CallStack* stack1_duplicate0 =
+      manager.GetCallStack(arraysize(kRawStack1), rawstack1_duplicate0.get());
+  EXPECT_EQ(2U, manager.size());
+  EXPECT_EQ(stack1, stack1_duplicate0);
+
+  // Add stack2 and stack3.
+  const CallStack* stack2 =
+      manager.GetCallStack(arraysize(kRawStack2), kRawStack2);
+  const CallStack* stack3 =
+      manager.GetCallStack(arraysize(kRawStack3), kRawStack3);
+  EXPECT_EQ(4U, manager.size());
+
+  scoped_ptr<const void* []> rawstack1_duplicate1 = CopyStack(stack1);
+  const CallStack* stack1_duplicate1 =
+      manager.GetCallStack(arraysize(kRawStack1), rawstack1_duplicate1.get());
+  EXPECT_EQ(4U, manager.size());
+  EXPECT_EQ(stack1, stack1_duplicate1);
+
+  scoped_ptr<const void* []> rawstack0_duplicate2 = CopyStack(stack0);
+  const CallStack* stack0_duplicate2 =
+      manager.GetCallStack(arraysize(kRawStack0), rawstack0_duplicate2.get());
+  EXPECT_EQ(4U, manager.size());
+  EXPECT_EQ(stack0, stack0_duplicate2);
+
+  scoped_ptr<const void* []> rawstack3_duplicate0 = CopyStack(stack3);
+  const CallStack* stack3_duplicate0 =
+      manager.GetCallStack(arraysize(kRawStack3), rawstack3_duplicate0.get());
+  EXPECT_EQ(4U, manager.size());
+  EXPECT_EQ(stack3, stack3_duplicate0);
+
+  scoped_ptr<const void* []> rawstack2_duplicate0 = CopyStack(stack2);
+  const CallStack* stack2_duplicate0 =
+      manager.GetCallStack(arraysize(kRawStack2), rawstack2_duplicate0.get());
+  EXPECT_EQ(4U, manager.size());
+  EXPECT_EQ(stack2, stack2_duplicate0);
+}
+
+}  // namespace leak_detector
+}  // namespace metrics
diff --git a/components/metrics/leak_detector/call_stack_table.cc b/components/metrics/leak_detector/call_stack_table.cc
new file mode 100644
index 0000000..61218286
--- /dev/null
+++ b/components/metrics/leak_detector/call_stack_table.cc
@@ -0,0 +1,80 @@
+// 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/metrics/leak_detector/call_stack_table.h"
+
+#include <algorithm>
+
+#include "components/metrics/leak_detector/call_stack_manager.h"
+
+namespace metrics {
+namespace leak_detector {
+
+namespace {
+
+using ValueType = LeakDetectorValueType;
+
+// During leak analysis, we only want to examine the top
+// |kMaxCountOfSuspciousStacks| entries.
+const int kMaxCountOfSuspciousStacks = 16;
+
+const int kInitialHashTableSize = 1999;
+
+}  // namespace
+
+size_t CallStackTable::StoredHash::operator()(
+    const CallStack* call_stack) const {
+  // The call stack object should already have a hash computed when it was
+  // created.
+  //
+  // This is NOT the actual hash computation function for a new call stack.
+  return call_stack->hash;
+}
+
+CallStackTable::CallStackTable(int call_stack_suspicion_threshold)
+    : num_allocs_(0),
+      num_frees_(0),
+      entry_map_(kInitialHashTableSize),
+      leak_analyzer_(kMaxCountOfSuspciousStacks,
+                     call_stack_suspicion_threshold) {}
+
+CallStackTable::~CallStackTable() {}
+
+void CallStackTable::Add(const CallStack* call_stack) {
+  Entry* entry = &entry_map_[call_stack];
+
+  ++entry->net_num_allocs;
+  ++num_allocs_;
+}
+
+void CallStackTable::Remove(const CallStack* call_stack) {
+  auto iter = entry_map_.find(call_stack);
+  if (iter == entry_map_.end())
+    return;
+  Entry* entry = &iter->second;
+  --entry->net_num_allocs;
+  ++num_frees_;
+
+  // Delete zero-alloc entries to free up space.
+  if (entry->net_num_allocs == 0)
+    entry_map_.erase(iter);
+}
+
+void CallStackTable::TestForLeaks() {
+  // Add all entries to the ranked list.
+  RankedList ranked_list(kMaxCountOfSuspciousStacks);
+
+  for (const auto& entry_pair : entry_map_) {
+    const Entry& entry = entry_pair.second;
+    // Assumes that |entry.net_num_allocs| is always > 0. If that changes
+    // elsewhere in this class, this code should be updated to only pass values
+    // > 0 to |ranked_list|.
+    LeakDetectorValueType call_stack_value(entry_pair.first);
+    ranked_list.Add(call_stack_value, entry.net_num_allocs);
+  }
+  leak_analyzer_.AddSample(std::move(ranked_list));
+}
+
+}  // namespace leak_detector
+}  // namespace metrics
diff --git a/components/metrics/leak_detector/call_stack_table.h b/components/metrics/leak_detector/call_stack_table.h
new file mode 100644
index 0000000..8772e31
--- /dev/null
+++ b/components/metrics/leak_detector/call_stack_table.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 COMPONENTS_METRICS_LEAK_DETECTOR_CALL_STACK_TABLE_H_
+#define COMPONENTS_METRICS_LEAK_DETECTOR_CALL_STACK_TABLE_H_
+
+#include <stdint.h>
+
+#include <functional>  // For std::equal_to.
+
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "components/metrics/leak_detector/custom_allocator.h"
+#include "components/metrics/leak_detector/leak_analyzer.h"
+#include "components/metrics/leak_detector/stl_allocator.h"
+
+namespace metrics {
+namespace leak_detector {
+
+struct CallStack;
+
+// Contains a hash table where the key is the call stack and the value is the
+// number of allocations from that call stack.
+// Not thread-safe.
+class CallStackTable {
+ public:
+  struct StoredHash {
+    size_t operator()(const CallStack* call_stack) const;
+  };
+
+  explicit CallStackTable(int call_stack_suspicion_threshold);
+  ~CallStackTable();
+
+  // Add/Remove an allocation for the given call stack.
+  // Note that this class does NOT own the CallStack objects. Instead, it
+  // identifies different CallStacks by their hashes.
+  void Add(const CallStack* call_stack);
+  void Remove(const CallStack* call_stack);
+
+  // Check for leak patterns in the allocation data.
+  void TestForLeaks();
+
+  const LeakAnalyzer& leak_analyzer() const { return leak_analyzer_; }
+
+  size_t size() const { return entry_map_.size(); }
+  bool empty() const { return entry_map_.empty(); }
+
+  uint32_t num_allocs() const { return num_allocs_; }
+  uint32_t num_frees() const { return num_frees_; }
+
+ private:
+  // Hash table entry used to track allocation stats for a given call stack.
+  struct Entry {
+    // Net number of allocs (allocs minus frees).
+    uint32_t net_num_allocs;
+  };
+
+  // Total number of allocs and frees in this table.
+  uint32_t num_allocs_;
+  uint32_t num_frees_;
+
+  // Hash table containing entries. Uses CustomAllocator to avoid recursive
+  // malloc hook invocation when analyzing allocs and frees.
+  using TableEntryAllocator =
+      STLAllocator<std::pair<const CallStack*, Entry>, CustomAllocator>;
+  base::hash_map<const CallStack*,
+                 Entry,
+                 StoredHash,
+                 std::equal_to<const CallStack*>,
+                 TableEntryAllocator> entry_map_;
+
+  // For detecting leak patterns in incoming allocations.
+  LeakAnalyzer leak_analyzer_;
+
+  DISALLOW_COPY_AND_ASSIGN(CallStackTable);
+};
+
+}  // namespace leak_detector
+}  // namespace metrics
+
+#endif  // COMPONENTS_METRICS_LEAK_DETECTOR_CALL_STACK_TABLE_H_
diff --git a/components/metrics/leak_detector/call_stack_table_unittest.cc b/components/metrics/leak_detector/call_stack_table_unittest.cc
new file mode 100644
index 0000000..c455f37
--- /dev/null
+++ b/components/metrics/leak_detector/call_stack_table_unittest.cc
@@ -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.
+
+#include "components/metrics/leak_detector/call_stack_table.h"
+
+#include <set>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "components/metrics/leak_detector/call_stack_manager.h"
+#include "components/metrics/leak_detector/custom_allocator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+namespace leak_detector {
+
+namespace {
+
+// Default threshold used for leak analysis.
+const int kDefaultLeakThreshold = 5;
+
+// Some test call stacks.
+const void* kRawStack0[] = {
+    reinterpret_cast<const void*>(0xaabbccdd),
+    reinterpret_cast<const void*>(0x11223344),
+    reinterpret_cast<const void*>(0x55667788),
+    reinterpret_cast<const void*>(0x99887766),
+};
+const void* kRawStack1[] = {
+    reinterpret_cast<const void*>(0xdeadbeef),
+    reinterpret_cast<const void*>(0x900df00d),
+    reinterpret_cast<const void*>(0xcafedeed),
+    reinterpret_cast<const void*>(0xdeafbabe),
+};
+const void* kRawStack2[] = {
+    reinterpret_cast<const void*>(0x12345678),
+    reinterpret_cast<const void*>(0xabcdef01),
+    reinterpret_cast<const void*>(0xfdecab98),
+};
+const void* kRawStack3[] = {
+    reinterpret_cast<const void*>(0xdead0001),
+    reinterpret_cast<const void*>(0xbeef0002),
+    reinterpret_cast<const void*>(0x900d0003),
+    reinterpret_cast<const void*>(0xf00d0004),
+    reinterpret_cast<const void*>(0xcafe0005),
+    reinterpret_cast<const void*>(0xdeed0006),
+    reinterpret_cast<const void*>(0xdeaf0007),
+    reinterpret_cast<const void*>(0xbabe0008),
+};
+
+}  // namespace
+
+class CallStackTableTest : public ::testing::Test {
+ public:
+  CallStackTableTest()
+      : stack0_(nullptr),
+        stack1_(nullptr),
+        stack2_(nullptr),
+        stack3_(nullptr) {}
+
+  void SetUp() override {
+    CustomAllocator::Initialize();
+
+    manager_.reset(new CallStackManager);
+
+    // The unit tests expect a certain order to the call stack pointers. It is
+    // an important detail when checking the output of LeakAnalyzer's suspected
+    // leaks, which are ordered by the leak value (call stack pointer). Use a
+    // set to sort the pointers as they are created.
+    std::set<const CallStack*> stacks;
+    stacks.insert(manager_->GetCallStack(arraysize(kRawStack0), kRawStack0));
+    stacks.insert(manager_->GetCallStack(arraysize(kRawStack1), kRawStack1));
+    stacks.insert(manager_->GetCallStack(arraysize(kRawStack2), kRawStack2));
+    stacks.insert(manager_->GetCallStack(arraysize(kRawStack3), kRawStack3));
+    ASSERT_EQ(4U, stacks.size());
+
+    std::set<const CallStack*>::const_iterator iter = stacks.begin();
+    stack0_ = *iter++;
+    stack1_ = *iter++;
+    stack2_ = *iter++;
+    stack3_ = *iter++;
+  }
+
+  void TearDown() override {
+    // All call stacks generated by |manager_| will be invalidated when it is
+    // destroyed.
+    stack0_ = nullptr;
+    stack1_ = nullptr;
+    stack2_ = nullptr;
+    stack3_ = nullptr;
+
+    // Destroy the call stack manager before shutting down the allocator.
+    manager_.reset();
+
+    EXPECT_TRUE(CustomAllocator::Shutdown());
+  }
+
+ protected:
+  // Unit tests should directly reference these pointers to CallStack objects.
+  const CallStack* stack0_;
+  const CallStack* stack1_;
+  const CallStack* stack2_;
+  const CallStack* stack3_;
+
+ private:
+  scoped_ptr<CallStackManager> manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(CallStackTableTest);
+};
+
+TEST_F(CallStackTableTest, PointerOrder) {
+  EXPECT_LT(stack0_, stack1_);
+  EXPECT_LT(stack1_, stack2_);
+  EXPECT_LT(stack2_, stack3_);
+}
+
+TEST_F(CallStackTableTest, EmptyTable) {
+  CallStackTable table(kDefaultLeakThreshold);
+  EXPECT_TRUE(table.empty());
+
+  EXPECT_EQ(0U, table.num_allocs());
+  EXPECT_EQ(0U, table.num_frees());
+
+  // The table should be able to gracefully handle an attempt to remove a call
+  // stack entry when none exists.
+  table.Remove(stack0_);
+  table.Remove(stack1_);
+  table.Remove(stack2_);
+  table.Remove(stack3_);
+
+  EXPECT_EQ(0U, table.num_allocs());
+  EXPECT_EQ(0U, table.num_frees());
+}
+
+TEST_F(CallStackTableTest, InsertionAndRemoval) {
+  CallStackTable table(kDefaultLeakThreshold);
+
+  table.Add(stack0_);
+  EXPECT_EQ(1U, table.size());
+  EXPECT_EQ(1U, table.num_allocs());
+  table.Add(stack1_);
+  EXPECT_EQ(2U, table.size());
+  EXPECT_EQ(2U, table.num_allocs());
+  table.Add(stack2_);
+  EXPECT_EQ(3U, table.size());
+  EXPECT_EQ(3U, table.num_allocs());
+  table.Add(stack3_);
+  EXPECT_EQ(4U, table.size());
+  EXPECT_EQ(4U, table.num_allocs());
+
+  // Add some call stacks that have already been added. There should be no
+  // change in the number of entries, as they are aggregated by call stack.
+  table.Add(stack2_);
+  EXPECT_EQ(4U, table.size());
+  EXPECT_EQ(5U, table.num_allocs());
+  table.Add(stack3_);
+  EXPECT_EQ(4U, table.size());
+  EXPECT_EQ(6U, table.num_allocs());
+
+  // Start removing entries.
+  EXPECT_EQ(0U, table.num_frees());
+
+  table.Remove(stack0_);
+  EXPECT_EQ(3U, table.size());
+  EXPECT_EQ(1U, table.num_frees());
+  table.Remove(stack1_);
+  EXPECT_EQ(2U, table.size());
+  EXPECT_EQ(2U, table.num_frees());
+
+  // Removing call stacks with multiple counts will not reduce the overall
+  // number of table entries, until the count reaches 0.
+  table.Remove(stack2_);
+  EXPECT_EQ(2U, table.size());
+  EXPECT_EQ(3U, table.num_frees());
+  table.Remove(stack3_);
+  EXPECT_EQ(2U, table.size());
+  EXPECT_EQ(4U, table.num_frees());
+
+  table.Remove(stack2_);
+  EXPECT_EQ(1U, table.size());
+  EXPECT_EQ(5U, table.num_frees());
+  table.Remove(stack3_);
+  EXPECT_EQ(0U, table.size());
+  EXPECT_EQ(6U, table.num_frees());
+
+  // Now the table should be empty, but attempt to remove some more and make
+  // sure nothing breaks.
+  table.Remove(stack0_);
+  table.Remove(stack1_);
+  table.Remove(stack2_);
+  table.Remove(stack3_);
+
+  EXPECT_TRUE(table.empty());
+  EXPECT_EQ(6U, table.num_allocs());
+  EXPECT_EQ(6U, table.num_frees());
+}
+
+TEST_F(CallStackTableTest, MassiveInsertionAndRemoval) {
+  CallStackTable table(kDefaultLeakThreshold);
+
+  for (int i = 0; i < 100; ++i)
+    table.Add(stack3_);
+  EXPECT_EQ(1U, table.size());
+  EXPECT_EQ(100U, table.num_allocs());
+
+  for (int i = 0; i < 100; ++i)
+    table.Add(stack2_);
+  EXPECT_EQ(2U, table.size());
+  EXPECT_EQ(200U, table.num_allocs());
+
+  for (int i = 0; i < 100; ++i)
+    table.Add(stack1_);
+  EXPECT_EQ(3U, table.size());
+  EXPECT_EQ(300U, table.num_allocs());
+
+  for (int i = 0; i < 100; ++i)
+    table.Add(stack0_);
+  EXPECT_EQ(4U, table.size());
+  EXPECT_EQ(400U, table.num_allocs());
+
+  // Remove them in a different order, by removing one of each stack during one
+  // iteration. The size should not decrease until the last iteration.
+  EXPECT_EQ(0U, table.num_frees());
+
+  for (int i = 0; i < 100; ++i) {
+    table.Remove(stack0_);
+    EXPECT_EQ(4U * i + 1, table.num_frees());
+
+    table.Remove(stack1_);
+    EXPECT_EQ(4U * i + 2, table.num_frees());
+
+    table.Remove(stack2_);
+    EXPECT_EQ(4U * i + 3, table.num_frees());
+
+    table.Remove(stack3_);
+    EXPECT_EQ(4U * i + 4, table.num_frees());
+  }
+  EXPECT_EQ(400U, table.num_frees());
+  EXPECT_TRUE(table.empty());
+
+  // Try to remove some more from an empty table and make sure nothing breaks.
+  table.Remove(stack0_);
+  table.Remove(stack1_);
+  table.Remove(stack2_);
+  table.Remove(stack3_);
+
+  EXPECT_TRUE(table.empty());
+  EXPECT_EQ(400U, table.num_allocs());
+  EXPECT_EQ(400U, table.num_frees());
+}
+
+TEST_F(CallStackTableTest, DetectLeak) {
+  CallStackTable table(kDefaultLeakThreshold);
+
+  // Add some base number of entries.
+  for (int i = 0; i < 60; ++i)
+    table.Add(stack0_);
+  for (int i = 0; i < 50; ++i)
+    table.Add(stack1_);
+  for (int i = 0; i < 64; ++i)
+    table.Add(stack2_);
+  for (int i = 0; i < 72; ++i)
+    table.Add(stack3_);
+
+  table.TestForLeaks();
+  EXPECT_TRUE(table.leak_analyzer().suspected_leaks().empty());
+
+  // Use the following scheme:
+  // - stack0_: increase by 4 each time -- leak suspect
+  // - stack1_: increase by 3 each time -- leak suspect
+  // - stack2_: increase by 1 each time -- not a suspect
+  // - stack3_: alternate between increasing and decreasing - not a suspect
+  bool increase_kstack3 = true;
+  for (int i = 0; i < kDefaultLeakThreshold; ++i) {
+    EXPECT_TRUE(table.leak_analyzer().suspected_leaks().empty());
+
+    for (int j = 0; j < 4; ++j)
+      table.Add(stack0_);
+
+    for (int j = 0; j < 3; ++j)
+      table.Add(stack1_);
+
+    table.Add(stack2_);
+
+    // Alternate between adding and removing.
+    if (increase_kstack3)
+      table.Add(stack3_);
+    else
+      table.Remove(stack3_);
+    increase_kstack3 = !increase_kstack3;
+
+    table.TestForLeaks();
+  }
+
+  // Check that the correct leak values have been detected.
+  const auto& leaks = table.leak_analyzer().suspected_leaks();
+  ASSERT_EQ(2U, leaks.size());
+  // Suspected leaks are reported in increasing leak value -- in this case, the
+  // CallStack object's address.
+  EXPECT_EQ(stack0_, leaks[0].call_stack());
+  EXPECT_EQ(stack1_, leaks[1].call_stack());
+}
+
+}  // namespace leak_detector
+}  // namespace metrics
diff --git a/components/metrics/leak_detector/custom_allocator.cc b/components/metrics/leak_detector/custom_allocator.cc
new file mode 100644
index 0000000..1f80a971
--- /dev/null
+++ b/components/metrics/leak_detector/custom_allocator.cc
@@ -0,0 +1,61 @@
+// 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/metrics/leak_detector/custom_allocator.h"
+
+#include <stddef.h>
+
+namespace metrics {
+namespace leak_detector {
+
+namespace {
+
+// Wrappers around new and delete.
+void* DefaultAlloc(size_t size) {
+  return new char[size];
+}
+void DefaultFree(void* ptr, size_t /* size */) {
+  delete[] reinterpret_cast<char*>(ptr);
+}
+
+CustomAllocator::AllocFunc g_alloc_func = nullptr;
+CustomAllocator::FreeFunc g_free_func = nullptr;
+
+}  // namespace
+
+// static
+void CustomAllocator::Initialize() {
+  Initialize(&DefaultAlloc, &DefaultFree);
+}
+
+// static
+void CustomAllocator::Initialize(AllocFunc alloc_func, FreeFunc free_func) {
+  g_alloc_func = alloc_func;
+  g_free_func = free_func;
+}
+
+// static
+bool CustomAllocator::Shutdown() {
+  g_alloc_func = nullptr;
+  g_free_func = nullptr;
+  return true;
+}
+
+// static
+bool CustomAllocator::IsInitialized() {
+  return g_alloc_func && g_free_func;
+}
+
+// static
+void* CustomAllocator::Allocate(size_t size) {
+  return g_alloc_func(size);
+}
+
+// static
+void CustomAllocator::Free(void* ptr, size_t size) {
+  g_free_func(ptr, size);
+}
+
+}  // namespace leak_detector
+}  // namespace metrics
diff --git a/components/metrics/leak_detector/custom_allocator.h b/components/metrics/leak_detector/custom_allocator.h
new file mode 100644
index 0000000..fdbfc77
--- /dev/null
+++ b/components/metrics/leak_detector/custom_allocator.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 COMPONENTS_METRICS_LEAK_DETECTOR_CUSTOM_ALLOCATOR_H_
+#define COMPONENTS_METRICS_LEAK_DETECTOR_CUSTOM_ALLOCATOR_H_
+
+#include <stddef.h>
+
+#include <type_traits>
+
+namespace metrics {
+namespace leak_detector {
+
+// Custom allocator class to be passed to STLAllocator as a template argument.
+//
+// By default, CustomAllocator uses the default allocator (new/delete), but the
+// caller of Initialize ()can provide a pair of alternative alloc/ free
+// functions to use as an external allocator.
+//
+// This is a stateless class, but there is static data within the module that
+// needs to be created and deleted.
+//
+// Not thread-safe.
+class CustomAllocator {
+ public:
+  using AllocFunc = std::add_pointer<void*(size_t)>::type;
+  using FreeFunc = std::add_pointer<void(void*, size_t)>::type;
+
+  // Initialize CustomAllocator to use the default allocator.
+  static void Initialize();
+
+  // Initialize CustomAllocator to use the given alloc/free functions.
+  static void Initialize(AllocFunc alloc_func, FreeFunc free_func);
+
+  // Performs any cleanup required, e.g. unset custom functions. Returns true
+  // on success or false if something failed.
+  static bool Shutdown();
+
+  static bool IsInitialized();
+
+  // These functions must match the specifications in STLAllocator.
+  static void* Allocate(size_t size);
+  static void Free(void* ptr, size_t size);
+};
+
+}  // namespace leak_detector
+}  // namespace metrics
+
+#endif  // COMPONENTS_METRICS_LEAK_DETECTOR_CUSTOM_ALLOCATOR_H_
diff --git a/components/metrics/leak_detector/leak_analyzer.cc b/components/metrics/leak_detector/leak_analyzer.cc
new file mode 100644
index 0000000..773622cc
--- /dev/null
+++ b/components/metrics/leak_detector/leak_analyzer.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 "components/metrics/leak_detector/leak_analyzer.h"
+
+#include <set>
+
+namespace metrics {
+namespace leak_detector {
+
+namespace {
+
+using RankedEntry = RankedList::Entry;
+
+// Increase suspicion scores by this much each time an entry is suspected as
+// being a leak.
+const int kSuspicionScoreIncrease = 1;
+
+}  // namespace
+
+LeakAnalyzer::LeakAnalyzer(uint32_t ranking_size,
+                           uint32_t num_suspicions_threshold)
+    : ranking_size_(ranking_size),
+      score_threshold_(num_suspicions_threshold),
+      ranked_entries_(ranking_size),
+      prev_ranked_entries_(ranking_size) {
+  suspected_leaks_.reserve(ranking_size);
+}
+
+LeakAnalyzer::~LeakAnalyzer() {}
+
+void LeakAnalyzer::AddSample(RankedList ranked_list) {
+  // Save the ranked entries from the previous call.
+  prev_ranked_entries_ = std::move(ranked_entries_);
+
+  // Save the current entries.
+  ranked_entries_ = std::move(ranked_list);
+
+  RankedList ranked_deltas(ranking_size_);
+  for (const RankedEntry& entry : ranked_entries_) {
+    // Determine what count was recorded for this value last time.
+    uint32_t prev_count = 0;
+    if (GetPreviousCountForValue(entry.value, &prev_count))
+      ranked_deltas.Add(entry.value, entry.count - prev_count);
+  }
+
+  AnalyzeDeltas(ranked_deltas);
+}
+
+void LeakAnalyzer::AnalyzeDeltas(const RankedList& ranked_deltas) {
+  bool found_drop = false;
+  RankedList::const_iterator drop_position = ranked_deltas.end();
+
+  if (ranked_deltas.size() > 1) {
+    RankedList::const_iterator entry_iter = ranked_deltas.begin();
+    RankedList::const_iterator next_entry_iter = ranked_deltas.begin();
+    ++next_entry_iter;
+
+    // If the first entry is 0, that means all deltas are 0 or negative. Do
+    // not treat this as a suspicion of leaks; just quit.
+    if (entry_iter->count > 0) {
+      while (next_entry_iter != ranked_deltas.end()) {
+        const RankedEntry& entry = *entry_iter;
+        const RankedEntry& next_entry = *next_entry_iter;
+
+        // Find the first major drop in values (i.e. by 50% or more).
+        if (entry.count > next_entry.count * 2) {
+          found_drop = true;
+          drop_position = next_entry_iter;
+          break;
+        }
+        ++entry_iter;
+        ++next_entry_iter;
+      }
+    }
+  }
+
+  // All leak values before the drop are suspected during this analysis.
+  std::set<ValueType, std::less<ValueType>, Allocator<ValueType>>
+      current_suspects;
+  if (found_drop) {
+    for (RankedList::const_iterator ranked_list_iter = ranked_deltas.begin();
+         ranked_list_iter != drop_position; ++ranked_list_iter) {
+      current_suspects.insert(ranked_list_iter->value);
+    }
+  }
+
+  // Reset the score to 0 for all previously suspected leak values that did
+  // not get suspected this time.
+  auto iter = suspected_histogram_.begin();
+  while (iter != suspected_histogram_.end()) {
+    const ValueType& value = iter->first;
+    // Erase entries whose suspicion score reaches 0.
+    auto erase_iter = iter++;
+    if (current_suspects.find(value) == current_suspects.end())
+      suspected_histogram_.erase(erase_iter);
+  }
+
+  // For currently suspected values, increase the leak score.
+  for (const ValueType& value : current_suspects) {
+    auto histogram_iter = suspected_histogram_.find(value);
+    if (histogram_iter != suspected_histogram_.end()) {
+      histogram_iter->second += kSuspicionScoreIncrease;
+    } else if (suspected_histogram_.size() < ranking_size_) {
+      // Create a new entry if it didn't already exist.
+      suspected_histogram_[value] = kSuspicionScoreIncrease;
+    }
+  }
+
+  // Now check the leak suspicion scores. Make sure to erase the suspected
+  // leaks from the previous call.
+  suspected_leaks_.clear();
+  for (const auto& entry : suspected_histogram_) {
+    if (suspected_leaks_.size() > ranking_size_)
+      break;
+
+    // Only report suspected values that have accumulated a suspicion score.
+    // This is achieved by maintaining suspicion for several cycles, with few
+    // skips.
+    if (entry.second >= score_threshold_)
+      suspected_leaks_.emplace_back(entry.first);
+  }
+}
+
+bool LeakAnalyzer::GetPreviousCountForValue(const ValueType& value,
+                                            uint32_t* count) const {
+  // Determine what count was recorded for this value last time.
+  for (const RankedEntry& entry : prev_ranked_entries_) {
+    if (entry.value == value) {
+      *count = entry.count;
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace leak_detector
+}  // namespace metrics
diff --git a/components/metrics/leak_detector/leak_analyzer.h b/components/metrics/leak_detector/leak_analyzer.h
new file mode 100644
index 0000000..589eb3cf
--- /dev/null
+++ b/components/metrics/leak_detector/leak_analyzer.h
@@ -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.
+
+#ifndef COMPONENTS_METRICS_LEAK_DETECTOR_LEAK_ANALYZER_H_
+#define COMPONENTS_METRICS_LEAK_DETECTOR_LEAK_ANALYZER_H_
+
+#include <map>
+#include <vector>
+
+#include "base/macros.h"
+#include "components/metrics/leak_detector/custom_allocator.h"
+#include "components/metrics/leak_detector/leak_detector_value_type.h"
+#include "components/metrics/leak_detector/ranked_list.h"
+#include "components/metrics/leak_detector/stl_allocator.h"
+
+namespace metrics {
+namespace leak_detector {
+
+// This class looks for possible leak patterns in allocation data over time.
+// Not thread-safe.
+class LeakAnalyzer {
+ public:
+  using ValueType = LeakDetectorValueType;
+
+  // This class uses CustomAllocator to avoid recursive malloc hook invocation
+  // when analyzing allocs and frees.
+  template <typename Type>
+  using Allocator = STLAllocator<Type, CustomAllocator>;
+
+  LeakAnalyzer(uint32_t ranking_size, uint32_t num_suspicions_threshold);
+  ~LeakAnalyzer();
+
+  // Take in a RankedList of allocations, sorted by count. Removes the contents
+  // of |ranked_list| to be stored internally, which is why it is not passed in
+  // as a const reference.
+  void AddSample(RankedList ranked_list);
+
+  // Used to report suspected leaks. Reported leaks are sorted by ValueType.
+  const std::vector<ValueType, Allocator<ValueType>>& suspected_leaks() const {
+    return suspected_leaks_;
+  }
+
+ private:
+  // Analyze a list of allocation count deltas from the previous iteration. If
+  // anything looks like a possible leak, update the suspicion scores.
+  void AnalyzeDeltas(const RankedList& ranked_deltas);
+
+  // Returns the count for the given value from the previous analysis in
+  // |count|. Returns true if the given value was present in the previous
+  // analysis, or false if not.
+  bool GetPreviousCountForValue(const ValueType& value, uint32_t* count) const;
+
+  // Look for the top |ranking_size_| entries when analyzing leaks.
+  const uint32_t ranking_size_;
+
+  // Report suspected leaks when the suspicion score reaches this value.
+  const uint32_t score_threshold_;
+
+  // A mapping of allocation values to suspicion score. All allocations in this
+  // container are suspected leaks. The score can increase or decrease over
+  // time. Once the score  reaches |score_threshold_|, the entry is reported as
+  // a suspected leak in |suspected_leaks_|.
+  std::map<ValueType,
+           uint32_t,
+           std::less<ValueType>,
+           Allocator<std::pair<ValueType, uint32_t>>> suspected_histogram_;
+
+  // Array of allocated values that passed the suspicion threshold and are being
+  // reported.
+  std::vector<ValueType, Allocator<ValueType>> suspected_leaks_;
+
+  // The most recent allocation entries, since the last call to AddSample().
+  RankedList ranked_entries_;
+  // The previous allocation entries, from before the last call to AddSample().
+  RankedList prev_ranked_entries_;
+
+  DISALLOW_COPY_AND_ASSIGN(LeakAnalyzer);
+};
+
+}  // namespace leak_detector
+}  // namespace metrics
+
+#endif  // COMPONENTS_METRICS_LEAK_DETECTOR_LEAK_ANALYZER_H_
diff --git a/components/metrics/leak_detector/leak_analyzer_unittest.cc b/components/metrics/leak_detector/leak_analyzer_unittest.cc
new file mode 100644
index 0000000..c8d900fd
--- /dev/null
+++ b/components/metrics/leak_detector/leak_analyzer_unittest.cc
@@ -0,0 +1,364 @@
+// 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/metrics/leak_detector/leak_analyzer.h"
+
+#include <algorithm>
+
+#include "base/macros.h"
+#include "components/metrics/leak_detector/custom_allocator.h"
+#include "components/metrics/leak_detector/ranked_list.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+namespace leak_detector {
+
+namespace {
+
+// Default ranking size and threshold used for leak analysis.
+const int kDefaultRankedListSize = 10;
+const int kDefaultLeakThreshold = 5;
+
+// Makes it easier to instantiate LeakDetectorValueTypes. Instantiates with an
+// integer value that indicates an allocation size. Storing the size allows us
+// to track the storage of the LeakDetectorValueType object within LeakAnalyzer.
+//
+// There is no need to test this with call stacks in addition to sizes because
+// call stacks will be contained in a LeakDetectorValueType object as well.
+LeakDetectorValueType Size(uint32_t value) {
+  return LeakDetectorValueType(value);
+}
+
+}  // namespace
+
+class LeakAnalyzerTest : public ::testing::Test {
+ public:
+  LeakAnalyzerTest() {}
+
+  void SetUp() override { CustomAllocator::Initialize(); }
+  void TearDown() override { EXPECT_TRUE(CustomAllocator::Shutdown()); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LeakAnalyzerTest);
+};
+
+TEST_F(LeakAnalyzerTest, Empty) {
+  LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
+  EXPECT_TRUE(analyzer.suspected_leaks().empty());
+}
+
+TEST_F(LeakAnalyzerTest, SingleSize) {
+  LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
+
+  for (int i = 0; i < kDefaultLeakThreshold + 20; ++i) {
+    RankedList list(kDefaultRankedListSize);
+    list.Add(Size(24), 10);
+    analyzer.AddSample(std::move(list));
+
+    // No leaks should have been detected.
+    EXPECT_TRUE(analyzer.suspected_leaks().empty());
+  }
+}
+
+TEST_F(LeakAnalyzerTest, VariousSizesWithoutIncrease) {
+  LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
+
+  for (int i = 0; i < kDefaultLeakThreshold + 20; ++i) {
+    RankedList list(kDefaultRankedListSize);
+    list.Add(Size(24), 30);
+    list.Add(Size(32), 10);
+    list.Add(Size(56), 90);
+    list.Add(Size(64), 40);
+    analyzer.AddSample(std::move(list));
+
+    // No leaks should have been detected.
+    EXPECT_TRUE(analyzer.suspected_leaks().empty());
+  }
+}
+
+TEST_F(LeakAnalyzerTest, VariousSizesWithEqualIncrease) {
+  LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
+
+  for (int i = 0; i < kDefaultLeakThreshold + 20; ++i) {
+    RankedList list(kDefaultRankedListSize);
+    list.Add(Size(24), 30 + i * 10);
+    list.Add(Size(32), 10 + i * 10);
+    list.Add(Size(56), 90 + i * 10);
+    list.Add(Size(64), 40 + i * 10);
+    analyzer.AddSample(std::move(list));
+
+    // No leaks should have been detected.
+    EXPECT_TRUE(analyzer.suspected_leaks().empty());
+  }
+}
+
+TEST_F(LeakAnalyzerTest, NotEnoughRunsToTriggerLeakReport) {
+  LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
+
+  // Run this one iteration short of the number of cycles needed to trigger a
+  // leak report. Because LeakAnalyzer requires |kDefaultLeakThreshold|
+  // suspicions based on deltas between AddSample() calls, the below loop needs
+  // to run |kDefaultLeakThreshold + 1| times to trigger a leak report.
+  for (int i = 0; i <= kDefaultLeakThreshold - 1; ++i) {
+    RankedList list(kDefaultRankedListSize);
+    list.Add(Size(24), 30 + i * 10);  // This one has a potential leak.
+    list.Add(Size(32), 10 + i * 2);
+    list.Add(Size(56), 90 + i);
+    list.Add(Size(64), 40 + i / 2);
+    analyzer.AddSample(std::move(list));
+
+    // No leaks should have been detected.
+    EXPECT_TRUE(analyzer.suspected_leaks().empty());
+  }
+}
+
+TEST_F(LeakAnalyzerTest, LeakSingleSize) {
+  LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
+
+  // Run this past the number of iterations required to trigger a leak report.
+  for (int i = 0; i < kDefaultLeakThreshold + 10; ++i) {
+    RankedList list(kDefaultRankedListSize);
+    list.Add(Size(32), 10);
+    list.Add(Size(56), 90);
+    list.Add(Size(24), 30 + i * 10);  // This one has a potential leak.
+    list.Add(Size(64), 40);
+    analyzer.AddSample(std::move(list));
+
+    // No leaks should have been detected initially...
+    if (i < kDefaultLeakThreshold) {
+      EXPECT_TRUE(analyzer.suspected_leaks().empty());
+    } else {
+      // ... but there should be reported leaks once the threshold is reached.
+      const auto& leaks = analyzer.suspected_leaks();
+      ASSERT_EQ(1U, leaks.size());
+      EXPECT_EQ(24U, leaks[0].size());
+    }
+  }
+}
+
+TEST_F(LeakAnalyzerTest, LeakSingleSizeOthersAlsoIncreasing) {
+  LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
+
+  for (int i = 0; i < kDefaultLeakThreshold + 10; ++i) {
+    RankedList list(kDefaultRankedListSize);
+    list.Add(Size(24), 30 + i * 10);  // This one has a potential leak.
+    list.Add(Size(32), 10 + i * 2);
+    list.Add(Size(56), 90 + i);
+    list.Add(Size(64), 40 + i / 2);
+    analyzer.AddSample(std::move(list));
+
+    // No leaks should have been detected initially...
+    if (i < kDefaultLeakThreshold) {
+      EXPECT_TRUE(analyzer.suspected_leaks().empty());
+    } else {
+      // ... but there should be reported leaks once the threshold is reached.
+      const auto& leaks = analyzer.suspected_leaks();
+      ASSERT_EQ(1U, leaks.size());
+      EXPECT_EQ(24U, leaks[0].size());
+    }
+  }
+}
+
+TEST_F(LeakAnalyzerTest, LeakMultipleSizes) {
+  LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
+
+  for (int i = 0; i < kDefaultLeakThreshold + 10; ++i) {
+    RankedList list(kDefaultRankedListSize);
+    list.Add(Size(24), 30 + i * 5);
+    list.Add(Size(32), 10 + i * 40);
+    list.Add(Size(56), 90 + i * 30);
+    list.Add(Size(64), 40 + i * 20);
+    list.Add(Size(80), 20 + i * 3);
+    analyzer.AddSample(std::move(list));
+
+    // No leaks should have been detected initially...
+    if (i < kDefaultLeakThreshold) {
+      EXPECT_TRUE(analyzer.suspected_leaks().empty());
+    } else {
+      // ... but there should be reported leaks once the threshold is reached.
+      const auto& leaks = analyzer.suspected_leaks();
+      ASSERT_EQ(3U, leaks.size());
+      // These should be in order of increasing allocation size.
+      EXPECT_EQ(32U, leaks[0].size());
+      EXPECT_EQ(56U, leaks[1].size());
+      EXPECT_EQ(64U, leaks[2].size());
+    }
+  }
+}
+
+TEST_F(LeakAnalyzerTest, LeakMultipleSizesValueOrder) {
+  LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
+
+  for (int i = 0; i <= kDefaultLeakThreshold; ++i) {
+    RankedList list(kDefaultRankedListSize);
+    // These are similar to LeakMultipleSizes, but the relative order of
+    // allocation increases is different from the relative order of sizes.
+    list.Add(Size(24), 30 + i * 5);
+    list.Add(Size(32), 10 + i * 20);
+    list.Add(Size(56), 90 + i * 40);
+    list.Add(Size(64), 40 + i * 30);
+    list.Add(Size(80), 20 + i * 3);
+    analyzer.AddSample(std::move(list));
+  }
+
+  const auto& leaks = analyzer.suspected_leaks();
+  ASSERT_EQ(3U, leaks.size());
+  // These should be in order of increasing allocation size, NOT in order of
+  // allocation count or deltas.
+  EXPECT_EQ(32U, leaks[0].size());
+  EXPECT_EQ(56U, leaks[1].size());
+  EXPECT_EQ(64U, leaks[2].size());
+}
+
+TEST_F(LeakAnalyzerTest, EqualIncreasesNoLeak) {
+  LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
+
+  for (int i = 0; i < kDefaultLeakThreshold + 20; ++i) {
+    RankedList list(kDefaultRankedListSize);
+    list.Add(Size(24), 30 + i * 10);
+    list.Add(Size(32), 10 + i * 10);
+    list.Add(Size(56), 90 + i * 10);
+    list.Add(Size(64), 40 + i * 10);
+    list.Add(Size(80), 20 + i * 10);
+    analyzer.AddSample(std::move(list));
+
+    EXPECT_TRUE(analyzer.suspected_leaks().empty());
+  }
+}
+
+TEST_F(LeakAnalyzerTest, NotBigEnoughDeltaGap) {
+  LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
+
+  for (int i = 0; i < kDefaultLeakThreshold + 20; ++i) {
+    RankedList list(kDefaultRankedListSize);
+    // These all have different increments but there is no clear group of
+    // increases that are larger than the rest.
+    list.Add(Size(24), 30 + i * 80);
+    list.Add(Size(32), 10 + i * 45);
+    list.Add(Size(56), 90 + i * 25);
+    list.Add(Size(64), 40 + i * 15);
+    list.Add(Size(80), 20 + i * 10);
+    analyzer.AddSample(std::move(list));
+
+    EXPECT_TRUE(analyzer.suspected_leaks().empty());
+  }
+}
+
+TEST_F(LeakAnalyzerTest, RepeatedRisesUntilLeakFound) {
+  LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
+
+  // Remember, there is an extra iteration beyond |kDefaultLeakThreshold| needed
+  // to actually trigger the leak detection.
+  for (int i = 0; i <= kDefaultLeakThreshold - 2; ++i) {
+    RankedList list(kDefaultRankedListSize);
+    list.Add(Size(24), 30 + i * 10);
+    list.Add(Size(32), 10);
+    list.Add(Size(56), 90);
+    list.Add(Size(64), 40);
+    list.Add(Size(80), 20);
+    analyzer.AddSample(std::move(list));
+
+    EXPECT_TRUE(analyzer.suspected_leaks().empty());
+  }
+
+  // Drop back down to 30.
+  for (int i = 0; i <= kDefaultLeakThreshold - 1; ++i) {
+    RankedList list(kDefaultRankedListSize);
+    list.Add(Size(24), 30 + i * 10);
+    list.Add(Size(32), 10);
+    list.Add(Size(56), 90);
+    list.Add(Size(64), 40);
+    list.Add(Size(80), 20);
+    analyzer.AddSample(std::move(list));
+
+    EXPECT_TRUE(analyzer.suspected_leaks().empty());
+  }
+
+  // Drop back down to 30.
+  for (int i = 0; i <= kDefaultLeakThreshold; ++i) {
+    // Initially there should not be any leak detected.
+    EXPECT_TRUE(analyzer.suspected_leaks().empty());
+
+    RankedList list(kDefaultRankedListSize);
+    list.Add(Size(24), 30 + i * 10);
+    list.Add(Size(32), 10);
+    list.Add(Size(56), 90);
+    list.Add(Size(64), 40);
+    list.Add(Size(80), 20);
+    analyzer.AddSample(std::move(list));
+  }
+  const auto& leaks = analyzer.suspected_leaks();
+  ASSERT_EQ(1U, leaks.size());
+  EXPECT_EQ(24U, leaks[0].size());
+}
+
+TEST_F(LeakAnalyzerTest, LeakWithMultipleGroupsOfDeltas) {
+  const int kRankedListSize = 20;
+  LeakAnalyzer analyzer(kRankedListSize, kDefaultLeakThreshold);
+
+  for (int i = 0; i <= kDefaultLeakThreshold; ++i) {
+    RankedList list(kRankedListSize);
+    list.Add(Size(24), 30 + i * 10);  // A group of smaller deltas.
+    list.Add(Size(32), 10 + i * 3);
+    list.Add(Size(80), 20 + i * 5);
+    list.Add(Size(40), 30 + i * 7);
+    list.Add(Size(56), 90);
+    list.Add(Size(64), 40);
+    list.Add(Size(128), 100);
+    list.Add(Size(44), 100 + i * 10);  // A group of medium deltas.
+    list.Add(Size(16), 60 + i * 50);
+    list.Add(Size(4), 20 + i * 40);
+    list.Add(Size(8), 100 + i * 60);
+    list.Add(Size(48), 100);
+    list.Add(Size(72), 60 + i * 240);  // A group of largest deltas.
+    list.Add(Size(28), 100);
+    list.Add(Size(100), 100 + i * 200);
+    list.Add(Size(104), 60 + i * 128);
+    analyzer.AddSample(std::move(list));
+  }
+  // Only the group of largest deltas should be caught.
+  const auto& leaks = analyzer.suspected_leaks();
+  ASSERT_EQ(3U, leaks.size());
+  // These should be in order of increasing allocation size.
+  EXPECT_EQ(72U, leaks[0].size());
+  EXPECT_EQ(100U, leaks[1].size());
+  EXPECT_EQ(104U, leaks[2].size());
+}
+
+TEST_F(LeakAnalyzerTest, LeakMultipleSizesWithLargeThreshold) {
+  const int kLeakThreshold = 50;
+  LeakAnalyzer analyzer(kDefaultRankedListSize, kLeakThreshold);
+
+  for (int i = 0; i <= kLeakThreshold + 10; ++i) {
+    RankedList list(kDefaultRankedListSize);
+    // * - Cluster of larger deltas
+    list.Add(Size(24), 30 + i * 5);
+    list.Add(Size(32), 10 + i * 40);  // *
+    list.Add(Size(56), 90 + i * 30);  // *
+    list.Add(Size(40), 30 + i * 7);
+    list.Add(Size(64), 40 + i * 25);  // *
+    list.Add(Size(80), 20 + i * 3);
+    list.Add(Size(128), 100);
+    list.Add(Size(44), 100 + i * 10);
+    list.Add(Size(16), 60 + i * 50);  // *
+    analyzer.AddSample(std::move(list));
+
+    // No leaks should have been detected initially...
+    if (i < kLeakThreshold) {
+      EXPECT_TRUE(analyzer.suspected_leaks().empty());
+    } else {
+      // ... but there should be reported leaks once the threshold is reached.
+      const auto& leaks = analyzer.suspected_leaks();
+      ASSERT_EQ(4U, leaks.size());
+      // These should be in order of increasing allocation size.
+      EXPECT_EQ(16U, leaks[0].size());
+      EXPECT_EQ(32U, leaks[1].size());
+      EXPECT_EQ(56U, leaks[2].size());
+      EXPECT_EQ(64U, leaks[3].size());
+    }
+  }
+}
+
+}  // namespace leak_detector
+}  // namespace metrics
diff --git a/components/metrics/leak_detector/leak_detector_impl.cc b/components/metrics/leak_detector/leak_detector_impl.cc
new file mode 100644
index 0000000..99988d2
--- /dev/null
+++ b/components/metrics/leak_detector/leak_detector_impl.cc
@@ -0,0 +1,215 @@
+// 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 "leak_detector_impl.h"
+
+#include <inttypes.h>
+#include <stddef.h>
+
+#include <algorithm>
+#include <new>
+
+#include "base/hash.h"
+#include "base/process/process_handle.h"
+#include "components/metrics/leak_detector/call_stack_table.h"
+#include "components/metrics/leak_detector/custom_allocator.h"
+#include "components/metrics/leak_detector/ranked_list.h"
+
+namespace metrics {
+namespace leak_detector {
+
+namespace {
+
+// Look for leaks in the the top N entries in each tier, where N is this value.
+const int kRankedListSize = 16;
+
+// Initial hash table size for |LeakDetectorImpl::address_map_|.
+const int kAddressMapNumBuckets = 100003;
+
+// Number of entries in the alloc size table. As sizes are aligned to 32-bits
+// the max supported allocation size is (kNumSizeEntries * 4 - 1). Any larger
+// sizes are ignored. This value is chosen high enough that such large sizes
+// are rare if not nonexistent.
+const int kNumSizeEntries = 2048;
+
+using ValueType = LeakDetectorValueType;
+
+// Functions to convert an allocation size to/from the array index used for
+// |LeakDetectorImpl::size_entries_|.
+size_t SizeToIndex(const size_t size) {
+  int result = static_cast<int>(size / sizeof(uint32_t));
+  if (result < kNumSizeEntries)
+    return result;
+  return 0;
+}
+
+size_t IndexToSize(size_t index) {
+  return sizeof(uint32_t) * index;
+}
+
+}  // namespace
+
+LeakDetectorImpl::LeakReport::LeakReport() : alloc_size_bytes_(0) {}
+
+LeakDetectorImpl::LeakReport::~LeakReport() {}
+
+bool LeakDetectorImpl::LeakReport::operator<(const LeakReport& other) const {
+  if (alloc_size_bytes_ != other.alloc_size_bytes_)
+    return alloc_size_bytes_ < other.alloc_size_bytes_;
+  for (size_t i = 0; i < call_stack_.size() && i < other.call_stack_.size();
+       ++i) {
+    if (call_stack_[i] != other.call_stack_[i])
+      return call_stack_[i] < other.call_stack_[i];
+  }
+  return call_stack_.size() < other.call_stack_.size();
+}
+
+LeakDetectorImpl::LeakDetectorImpl(uintptr_t mapping_addr,
+                                   size_t mapping_size,
+                                   int size_suspicion_threshold,
+                                   int call_stack_suspicion_threshold)
+    : num_allocs_(0),
+      num_frees_(0),
+      alloc_size_(0),
+      free_size_(0),
+      num_allocs_with_call_stack_(0),
+      num_stack_tables_(0),
+      address_map_(kAddressMapNumBuckets),
+      size_leak_analyzer_(kRankedListSize, size_suspicion_threshold),
+      size_entries_(kNumSizeEntries),
+      mapping_addr_(mapping_addr),
+      mapping_size_(mapping_size),
+      call_stack_suspicion_threshold_(call_stack_suspicion_threshold) {}
+
+LeakDetectorImpl::~LeakDetectorImpl() {
+  // Free any call stack tables.
+  for (AllocSizeEntry& entry : size_entries_) {
+    CallStackTable* table = entry.stack_table;
+    if (!table)
+      continue;
+    table->~CallStackTable();
+    CustomAllocator::Free(table, sizeof(CallStackTable));
+  }
+  size_entries_.clear();
+}
+
+bool LeakDetectorImpl::ShouldGetStackTraceForSize(size_t size) const {
+  return size_entries_[SizeToIndex(size)].stack_table != nullptr;
+}
+
+void LeakDetectorImpl::RecordAlloc(const void* ptr,
+                                   size_t size,
+                                   int stack_depth,
+                                   const void* const stack[]) {
+  AllocInfo alloc_info;
+  alloc_info.size = size;
+
+  alloc_size_ += alloc_info.size;
+  ++num_allocs_;
+
+  AllocSizeEntry* entry = &size_entries_[SizeToIndex(size)];
+  ++entry->num_allocs;
+
+  if (entry->stack_table && stack_depth > 0) {
+    alloc_info.call_stack =
+        call_stack_manager_.GetCallStack(stack_depth, stack);
+    entry->stack_table->Add(alloc_info.call_stack);
+
+    ++num_allocs_with_call_stack_;
+  }
+
+  uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
+  address_map_.insert(std::pair<uintptr_t, AllocInfo>(addr, alloc_info));
+}
+
+void LeakDetectorImpl::RecordFree(const void* ptr) {
+  // Look up address.
+  uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
+  auto iter = address_map_.find(addr);
+  // TODO(sque): Catch and report double frees.
+  if (iter == address_map_.end())
+    return;
+
+  const AllocInfo& alloc_info = iter->second;
+
+  AllocSizeEntry* entry = &size_entries_[SizeToIndex(alloc_info.size)];
+  ++entry->num_frees;
+
+  const CallStack* call_stack = alloc_info.call_stack;
+  if (call_stack) {
+    if (entry->stack_table)
+      entry->stack_table->Remove(call_stack);
+  }
+  ++num_frees_;
+  free_size_ += alloc_info.size;
+
+  address_map_.erase(iter);
+}
+
+void LeakDetectorImpl::TestForLeaks(InternalVector<LeakReport>* reports) {
+  // Add net alloc counts for each size to a ranked list.
+  RankedList size_ranked_list(kRankedListSize);
+  for (size_t i = 0; i < size_entries_.size(); ++i) {
+    const AllocSizeEntry& entry = size_entries_[i];
+    ValueType size_value(IndexToSize(i));
+    size_ranked_list.Add(size_value, entry.num_allocs - entry.num_frees);
+  }
+  size_leak_analyzer_.AddSample(std::move(size_ranked_list));
+
+  // Get suspected leaks by size.
+  for (const ValueType& size_value : size_leak_analyzer_.suspected_leaks()) {
+    uint32_t size = size_value.size();
+    AllocSizeEntry* entry = &size_entries_[SizeToIndex(size)];
+    if (entry->stack_table)
+      continue;
+    entry->stack_table = new (CustomAllocator::Allocate(sizeof(CallStackTable)))
+        CallStackTable(call_stack_suspicion_threshold_);
+    ++num_stack_tables_;
+  }
+
+  // Check for leaks in each CallStackTable. It makes sense to this before
+  // checking the size allocations, because that could potentially create new
+  // CallStackTable. However, the overhead to check a new CallStackTable is
+  // small since this function is run very rarely. So handle the leak checks of
+  // Tier 2 here.
+  reports->clear();
+  for (size_t i = 0; i < size_entries_.size(); ++i) {
+    const AllocSizeEntry& entry = size_entries_[i];
+    CallStackTable* stack_table = entry.stack_table;
+    if (!stack_table || stack_table->empty())
+      continue;
+
+    size_t size = IndexToSize(i);
+
+    // Get suspected leaks by call stack.
+    stack_table->TestForLeaks();
+    const LeakAnalyzer& leak_analyzer = stack_table->leak_analyzer();
+    for (const ValueType& call_stack_value : leak_analyzer.suspected_leaks()) {
+      const CallStack* call_stack = call_stack_value.call_stack();
+
+      // Return reports by storing in |*reports|.
+      reports->resize(reports->size() + 1);
+      LeakReport* report = &reports->back();
+      report->alloc_size_bytes_ = size;
+      report->call_stack_.resize(call_stack->depth);
+      for (size_t j = 0; j < call_stack->depth; ++j) {
+        report->call_stack_[j] = GetOffset(call_stack->stack[j]);
+      }
+    }
+  }
+}
+
+size_t LeakDetectorImpl::AddressHash::operator()(uintptr_t addr) const {
+  return base::Hash(reinterpret_cast<const char*>(&addr), sizeof(addr));
+}
+
+uintptr_t LeakDetectorImpl::GetOffset(const void* ptr) const {
+  uintptr_t ptr_value = reinterpret_cast<uintptr_t>(ptr);
+  if (ptr_value >= mapping_addr_ && ptr_value < mapping_addr_ + mapping_size_)
+    return ptr_value - mapping_addr_;
+  return ptr_value;
+}
+
+}  // namespace leak_detector
+}  // namespace metrics
diff --git a/components/metrics/leak_detector/leak_detector_impl.h b/components/metrics/leak_detector/leak_detector_impl.h
new file mode 100644
index 0000000..1c361303
--- /dev/null
+++ b/components/metrics/leak_detector/leak_detector_impl.h
@@ -0,0 +1,162 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_METRICS_LEAK_DETECTOR_LEAK_DETECTOR_IMPL_H_
+#define COMPONENTS_METRICS_LEAK_DETECTOR_LEAK_DETECTOR_IMPL_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "components/metrics/leak_detector/call_stack_manager.h"
+#include "components/metrics/leak_detector/custom_allocator.h"
+#include "components/metrics/leak_detector/leak_analyzer.h"
+
+namespace metrics {
+namespace leak_detector {
+
+class CallStackTable;
+
+// Class that contains the actual leak detection mechanism.
+// Not thread-safe.
+class LeakDetectorImpl {
+ public:
+  // Vector type that's safe to use within the memory leak detector. Uses
+  // CustomAllocator to avoid recursive malloc hook invocation when analyzing
+  // allocs and frees.
+  template <typename T>
+  using InternalVector = std::vector<T, STLAllocator<T, CustomAllocator>>;
+
+  // Leak report generated by LeakDetectorImpl.
+  class LeakReport {
+   public:
+    LeakReport();
+    ~LeakReport();
+
+    size_t alloc_size_bytes() const { return alloc_size_bytes_; }
+
+    const InternalVector<uintptr_t>& call_stack() const { return call_stack_; }
+
+    // Used to compare the contents of two leak reports.
+    bool operator<(const LeakReport& other) const;
+
+   private:
+    // LeakDetectorImpl needs access to class members when creating a new leak
+    // report.
+    friend class LeakDetectorImpl;
+
+    // Number of bytes allocated by the leak site during each allocation.
+    size_t alloc_size_bytes_;
+
+    // Unlike the CallStack struct, which consists of addresses, this call stack
+    // will contain offsets in the executable binary.
+    InternalVector<uintptr_t> call_stack_;
+
+    // TODO(sque): Add leak detector parameters.
+  };
+
+  LeakDetectorImpl(uintptr_t mapping_addr,
+                   size_t mapping_size,
+                   int size_suspicion_threshold,
+                   int call_stack_suspicion_threshold);
+  ~LeakDetectorImpl();
+
+  // Indicates whether the given allocation size has an associated call stack
+  // table, and thus requires a stack unwind.
+  bool ShouldGetStackTraceForSize(size_t size) const;
+
+  // Record allocs and frees.
+  void RecordAlloc(const void* ptr,
+                   size_t size,
+                   int stack_depth,
+                   const void* const call_stack[]);
+  void RecordFree(const void* ptr);
+
+  // Run check for possible leaks based on the current profiling data.
+  void TestForLeaks(InternalVector<LeakReport>* reports);
+
+ private:
+  // A record of allocations for a particular size.
+  struct AllocSizeEntry {
+    // Number of allocations and frees for this size.
+    uint32_t num_allocs;
+    uint32_t num_frees;
+
+    // A stack table, if this size is being profiled for stack as well.
+    CallStackTable* stack_table;
+  };
+
+  // Info for a single allocation.
+  struct AllocInfo {
+    AllocInfo() : call_stack(nullptr) {}
+
+    // Number of bytes in this allocation.
+    size_t size;
+
+    // Points to a unique call stack.
+    const CallStack* call_stack;
+  };
+
+  // Allocator class for allocation entry map. Maps allocated addresses to
+  // AllocInfo objects.
+  using AllocationEntryAllocator =
+      STLAllocator<std::pair<const void*, AllocInfo>, CustomAllocator>;
+
+  // Hash class for addresses.
+  struct AddressHash {
+    size_t operator()(uintptr_t addr) const;
+  };
+
+  // Returns the offset of |ptr| within the current binary. If it is not in the
+  // current binary, just return |ptr| as an integer.
+  uintptr_t GetOffset(const void* ptr) const;
+
+  // Owns all unique call stack objects, which are allocated on the heap. Any
+  // other class or function that references a call stack must get it from here,
+  // but may not take ownership of the call stack object.
+  CallStackManager call_stack_manager_;
+
+  // Allocation stats.
+  uint64_t num_allocs_;
+  uint64_t num_frees_;
+  uint64_t alloc_size_;
+  uint64_t free_size_;
+
+  uint32_t num_allocs_with_call_stack_;
+  uint32_t num_stack_tables_;
+
+  // Stores all individual recorded allocations.
+  base::hash_map<uintptr_t,
+                 AllocInfo,
+                 AddressHash,
+                 std::equal_to<uintptr_t>,
+                 AllocationEntryAllocator> address_map_;
+
+  // Used to analyze potential leak patterns in the allocation sizes.
+  LeakAnalyzer size_leak_analyzer_;
+
+  // Allocation stats for each size.
+  InternalVector<AllocSizeEntry> size_entries_;
+
+  // Address mapping info of the current binary.
+  uintptr_t mapping_addr_;
+  size_t mapping_size_;
+
+  // Number of consecutive times an allocation size must trigger suspicion to be
+  // considered a leak suspect.
+  int size_suspicion_threshold_;
+
+  // Number of consecutive times a call stack must trigger suspicion to be
+  // considered a leak suspect.
+  int call_stack_suspicion_threshold_;
+
+  DISALLOW_COPY_AND_ASSIGN(LeakDetectorImpl);
+};
+
+}  // namespace leak_detector
+}  // namespace metrics
+
+#endif  // COMPONENTS_METRICS_LEAK_DETECTOR_LEAK_DETECTOR_IMPL_H_
diff --git a/components/metrics/leak_detector/leak_detector_impl_unittest.cc b/components/metrics/leak_detector/leak_detector_impl_unittest.cc
new file mode 100644
index 0000000..0e9293e
--- /dev/null
+++ b/components/metrics/leak_detector/leak_detector_impl_unittest.cc
@@ -0,0 +1,464 @@
+// 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/metrics/leak_detector/leak_detector_impl.h"
+
+#include <math.h>
+#include <stdint.h>
+
+#include <complex>
+#include <new>
+#include <set>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "components/metrics/leak_detector/custom_allocator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+namespace leak_detector {
+
+using InternalLeakReport = LeakDetectorImpl::LeakReport;
+
+namespace {
+
+// Makes working with complex numbers easier.
+using Complex = std::complex<double>;
+
+// The mapping location in memory for a fictional executable.
+const uintptr_t kMappingAddr = 0x800000;
+const size_t kMappingSize = 0x200000;
+
+// Some call stacks within the fictional executable.
+// * - outside the mapping range, e.g. JIT code.
+const uintptr_t kRawStack0[] = {
+    0x800100, 0x900000, 0x880080, 0x810000,
+};
+const uintptr_t kRawStack1[] = {
+    0x940000, 0x980000,
+    0xdeadbeef,  // *
+    0x9a0000,
+};
+const uintptr_t kRawStack2[] = {
+    0x8f0d00, 0x803abc, 0x9100a0,
+};
+const uintptr_t kRawStack3[] = {
+    0x90fcde,
+    0x900df00d,  // *
+    0x801000,   0x880088,
+    0xdeadcafe,  // *
+    0x9f0000,   0x8700a0, 0x96037c,
+};
+const uintptr_t kRawStack4[] = {
+    0x8c0000, 0x85d00d, 0x921337,
+    0x780000,  // *
+};
+const uintptr_t kRawStack5[] = {
+    0x990000, 0x888888, 0x830ac0, 0x8e0000,
+    0xc00000,  // *
+};
+
+// This struct makes it easier to pass call stack info to
+// LeakDetectorImplTest::Alloc().
+struct TestCallStack {
+  const uintptr_t* stack;  // A reference to the original stack data.
+  size_t depth;
+};
+
+const TestCallStack kStack0 = {kRawStack0, arraysize(kRawStack0)};
+const TestCallStack kStack1 = {kRawStack1, arraysize(kRawStack1)};
+const TestCallStack kStack2 = {kRawStack2, arraysize(kRawStack2)};
+const TestCallStack kStack3 = {kRawStack3, arraysize(kRawStack3)};
+const TestCallStack kStack4 = {kRawStack4, arraysize(kRawStack4)};
+const TestCallStack kStack5 = {kRawStack5, arraysize(kRawStack5)};
+
+// The interval between consecutive analyses (LeakDetectorImpl::TestForLeaks),
+// in number of bytes allocated. e.g. if |kAllocedSizeAnalysisInterval| = 1024
+// then call TestForLeaks() every 1024 bytes of allocation that occur.
+static const size_t kAllocedSizeAnalysisInterval = 8192;
+
+}  // namespace
+
+// This test suite will test the ability of LeakDetectorImpl to catch leaks in
+// a program. Individual tests can run leaky code locally.
+//
+// The leaky code must call Alloc() and Free() for heap memory management. It
+// should not call See comments on those
+// functions for more details.
+class LeakDetectorImplTest : public ::testing::Test {
+ public:
+  LeakDetectorImplTest()
+      : total_num_allocs_(0),
+        total_num_frees_(0),
+        total_alloced_size_(0),
+        next_analysis_total_alloced_size_(kAllocedSizeAnalysisInterval) {}
+
+  void SetUp() override {
+    CustomAllocator::Initialize();
+
+    const int kSizeSuspicionThreshold = 4;
+    const int kCallStackSuspicionThreshold = 4;
+    detector_.reset(new LeakDetectorImpl(kMappingAddr, kMappingSize,
+                                         kSizeSuspicionThreshold,
+                                         kCallStackSuspicionThreshold));
+  }
+
+  void TearDown() override {
+    // Free any memory that was leaked by test cases. Do not use Free() because
+    // that will try to modify |alloced_ptrs_|.
+    for (void* ptr : alloced_ptrs_)
+      delete[] reinterpret_cast<char*>(ptr);
+    alloced_ptrs_.clear();
+
+    // Must destroy all objects that use CustomAllocator before shutting down.
+    detector_.reset();
+    stored_reports_.clear();
+
+    EXPECT_TRUE(CustomAllocator::Shutdown());
+  }
+
+ protected:
+  // Alloc and free functions that allocate and free heap memory and
+  // automatically pass alloc/free info to |detector_|. They emulate the
+  // alloc/free hook functions that would call into LeakDetectorImpl in
+  // real-life usage. They also keep track of individual allocations locally, so
+  // any leaked memory could be cleaned up.
+  //
+  // |stack| is just a nominal call stack object to identify the call site. It
+  // doesn't have to contain the stack trace of the actual call stack.
+  void* Alloc(size_t size, const TestCallStack& stack) {
+    void* ptr = new char[size];
+    detector_->RecordAlloc(ptr, size, stack.depth,
+                           reinterpret_cast<const void* const*>(stack.stack));
+
+    EXPECT_TRUE(alloced_ptrs_.find(ptr) == alloced_ptrs_.end());
+    alloced_ptrs_.insert(ptr);
+
+    ++total_num_allocs_;
+    total_alloced_size_ += size;
+    if (total_alloced_size_ >= next_analysis_total_alloced_size_) {
+      LeakDetectorImpl::InternalVector<InternalLeakReport> reports;
+      detector_->TestForLeaks(&reports);
+      for (const InternalLeakReport& report : reports)
+        stored_reports_.insert(report);
+
+      // Determine when the next leak analysis should occur.
+      while (total_alloced_size_ >= next_analysis_total_alloced_size_)
+        next_analysis_total_alloced_size_ += kAllocedSizeAnalysisInterval;
+    }
+    return ptr;
+  }
+
+  // See comment for Alloc().
+  void Free(void* ptr) {
+    auto find_ptr_iter = alloced_ptrs_.find(ptr);
+    EXPECT_FALSE(find_ptr_iter == alloced_ptrs_.end());
+    if (find_ptr_iter == alloced_ptrs_.end())
+      return;
+    alloced_ptrs_.erase(find_ptr_iter);
+    ++total_num_frees_;
+
+    detector_->RecordFree(ptr);
+
+    delete[] reinterpret_cast<char*>(ptr);
+  }
+
+  // TEST CASE: Julia set fractal computation. Pass in enable_leaks=true to
+  // trigger some memory leaks.
+  void JuliaSet(bool enable_leaks);
+
+  // Instance of the class being tested.
+  scoped_ptr<LeakDetectorImpl> detector_;
+
+  // Number of pointers allocated and freed so far.
+  size_t total_num_allocs_;
+  size_t total_num_frees_;
+
+  // Keeps count of total size allocated by Alloc().
+  size_t total_alloced_size_;
+
+  // The cumulative allocation size at which to trigger the TestForLeaks() call.
+  size_t next_analysis_total_alloced_size_;
+
+  // Stores all pointers to memory allocated by by Alloc() so we can manually
+  // free the leaked pointers at the end. This also serves as redundant
+  // bookkeepping: it stores all pointers that have been allocated but not yet
+  // freed.
+  std::set<void*> alloced_ptrs_;
+
+  // Store leak reports here. Use a set so duplicate reports are not stored.
+  std::set<InternalLeakReport> stored_reports_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LeakDetectorImplTest);
+};
+
+void LeakDetectorImplTest::JuliaSet(bool enable_leaks) {
+  // The center region of the complex plane that is the basis for our Julia set
+  // computations is a circle of radius kRadius.
+  constexpr double kRadius = 2;
+
+  // To track points in the complex plane, we will use a rectangular grid in the
+  // range defined by [-kRadius, kRadius] along both axes.
+  constexpr double kRangeMin = -kRadius;
+  constexpr double kRangeMax = kRadius;
+
+  // Divide each axis into intervals, each of which is associated with a point
+  // on that axis at its center.
+  constexpr double kIntervalInverse = 64;
+  constexpr double kInterval = 1.0 / kIntervalInverse;
+  constexpr int kNumPoints = (kRangeMax - kRangeMin) / kInterval + 1;
+
+  // Contains some useful functions for converting between points on the complex
+  // plane and in a gridlike data structure.
+  struct ComplexPlane {
+    static int GetXGridIndex(const Complex& value) {
+      return (value.real() + kInterval / 2 - kRangeMin) / kInterval;
+    }
+    static int GetYGridIndex(const Complex& value) {
+      return (value.imag() + kInterval / 2 - kRangeMin) / kInterval;
+    }
+    static int GetArrayIndex(const Complex& value) {
+      return GetXGridIndex(value) + GetYGridIndex(value) * kNumPoints;
+    }
+    static Complex GetComplexForGridPoint(size_t x, size_t y) {
+      return Complex(kRangeMin + x * kInterval, kRangeMin + y * kInterval);
+    }
+  };
+
+  // Make sure the choice of interval doesn't result in any loss of precision.
+  ASSERT_EQ(1.0, kInterval * kIntervalInverse);
+
+  // Create a grid for part of the complex plane, with each axis within the
+  // range [kRangeMin, kRangeMax].
+  constexpr size_t width = kNumPoints;
+  constexpr size_t height = kNumPoints;
+  std::vector<Complex*> grid(width * height);
+
+  // Initialize an object for each point within the inner circle |z| < kRadius.
+  for (size_t i = 0; i < width; ++i) {
+    for (size_t j = 0; j < height; ++j) {
+      Complex point = ComplexPlane::GetComplexForGridPoint(i, j);
+      // Do not store any values outside the inner circle.
+      if (abs(point) <= kRadius) {
+        grid[i + j * width] =
+            new (Alloc(sizeof(Complex), kStack0)) Complex(point);
+      }
+    }
+  }
+  EXPECT_LE(alloced_ptrs_.size(), width * height);
+
+  // Create a new grid for the result of the transformation.
+  std::vector<Complex*> next_grid(width * height, nullptr);
+
+  const int kNumIterations = 20;
+  for (int n = 0; n < kNumIterations; ++n) {
+    for (int i = 0; i < kNumPoints; ++i) {
+      for (int j = 0; j < kNumPoints; ++j) {
+        if (!grid[i + j * width])
+          continue;
+
+        // NOTE: The below code is NOT an efficient way to compute a Julia set.
+        // This is only to test the leak detector with some nontrivial code.
+
+        // A simple polynomial function for generating Julia sets is:
+        //   f(z) = z^n + c
+
+        // But in this algorithm, we need the inverse:
+        //   fInv(z) = (z - c)^(1/n)
+
+        // Here, let's use n=5 and c=0.544.
+        const Complex c(0.544, 0);
+        const Complex& z = *grid[i + j * width];
+
+        // This is the principal root.
+        Complex root = pow(z - c, 0.2);
+
+        // Discard the result if it is too far out from the center of the plane.
+        if (abs(root) > kRadius)
+          continue;
+
+        // The below code only allocates Complex objects of the same size. The
+        // leak detector expects various sizes, so increase the allocation size
+        // by a different amount at each call site.
+
+        // Nth root produces N results.
+        // Place all root results on |next_grid|.
+
+        // First, place the principal root.
+        if (!next_grid[ComplexPlane::GetArrayIndex(root)]) {
+          next_grid[ComplexPlane::GetArrayIndex(root)] =
+              new (Alloc(sizeof(Complex) + 24, kStack1)) Complex(root);
+        }
+
+        double magnitude = abs(root);
+        double angle = arg(root);
+        // To generate other roots, rotate the principal root by increments of
+        // 1/N of a full circle.
+        const double kAngleIncrement = M_PI * 2 / 5;
+
+        // Second root.
+        root = std::polar(magnitude, angle + kAngleIncrement);
+        if (!next_grid[ComplexPlane::GetArrayIndex(root)]) {
+          next_grid[ComplexPlane::GetArrayIndex(root)] =
+              new (Alloc(sizeof(Complex) + 40, kStack2)) Complex(root);
+        }
+
+        // In some of the sections below, setting |enable_leaks| to true will
+        // trigger a memory leak by overwriting the old Complex pointer value
+        // without freeing it. Due to the nature of complex roots being confined
+        // to equal sections of the complex plane, each new pointer will
+        // displace an old pointer that was allocated from the same line of
+        // code.
+
+        // Third root.
+        root = std::polar(magnitude, angle + kAngleIncrement * 2);
+        // *** LEAK ***
+        if (enable_leaks || !next_grid[ComplexPlane::GetArrayIndex(root)]) {
+          next_grid[ComplexPlane::GetArrayIndex(root)] =
+              new (Alloc(sizeof(Complex) + 40, kStack3)) Complex(root);
+        }
+
+        // Fourth root.
+        root = std::polar(magnitude, angle + kAngleIncrement * 3);
+        // *** LEAK ***
+        if (enable_leaks || !next_grid[ComplexPlane::GetArrayIndex(root)]) {
+          next_grid[ComplexPlane::GetArrayIndex(root)] =
+              new (Alloc(sizeof(Complex) + 52, kStack4)) Complex(root);
+        }
+
+        // Fifth root.
+        root = std::polar(magnitude, angle + kAngleIncrement * 4);
+        if (!next_grid[ComplexPlane::GetArrayIndex(root)]) {
+          next_grid[ComplexPlane::GetArrayIndex(root)] =
+              new (Alloc(sizeof(Complex) + 52, kStack5)) Complex(root);
+        }
+      }
+    }
+
+    // Clear the previously allocated points.
+    for (Complex*& point : grid) {
+      if (point) {
+        Free(point);
+        point = nullptr;
+      }
+    }
+
+    // Now swap the two grids for the next iteration.
+    grid.swap(next_grid);
+  }
+
+  // Clear the previously allocated points.
+  for (Complex*& point : grid) {
+    if (point) {
+      Free(point);
+      point = nullptr;
+    }
+  }
+}
+
+TEST_F(LeakDetectorImplTest, CheckTestFramework) {
+  EXPECT_EQ(0U, total_num_allocs_);
+  EXPECT_EQ(0U, total_num_frees_);
+  EXPECT_EQ(0U, alloced_ptrs_.size());
+
+  // Allocate some memory.
+  void* ptr0 = Alloc(12, kStack0);
+  void* ptr1 = Alloc(16, kStack0);
+  void* ptr2 = Alloc(24, kStack0);
+  EXPECT_EQ(3U, total_num_allocs_);
+  EXPECT_EQ(0U, total_num_frees_);
+  EXPECT_EQ(3U, alloced_ptrs_.size());
+
+  // Free one of the pointers.
+  Free(ptr1);
+  EXPECT_EQ(3U, total_num_allocs_);
+  EXPECT_EQ(1U, total_num_frees_);
+  EXPECT_EQ(2U, alloced_ptrs_.size());
+
+  // Allocate some more memory.
+  void* ptr3 = Alloc(72, kStack1);
+  void* ptr4 = Alloc(104, kStack1);
+  void* ptr5 = Alloc(96, kStack1);
+  void* ptr6 = Alloc(24, kStack1);
+  EXPECT_EQ(7U, total_num_allocs_);
+  EXPECT_EQ(1U, total_num_frees_);
+  EXPECT_EQ(6U, alloced_ptrs_.size());
+
+  // Free more pointers.
+  Free(ptr2);
+  Free(ptr4);
+  Free(ptr6);
+  EXPECT_EQ(7U, total_num_allocs_);
+  EXPECT_EQ(4U, total_num_frees_);
+  EXPECT_EQ(3U, alloced_ptrs_.size());
+
+  // Free remaining memory.
+  Free(ptr0);
+  Free(ptr3);
+  Free(ptr5);
+  EXPECT_EQ(7U, total_num_allocs_);
+  EXPECT_EQ(7U, total_num_frees_);
+  EXPECT_EQ(0U, alloced_ptrs_.size());
+}
+
+TEST_F(LeakDetectorImplTest, JuliaSetNoLeak) {
+  JuliaSet(false /* enable_leaks */);
+
+  // JuliaSet() should have run cleanly without leaking.
+  EXPECT_EQ(total_num_allocs_, total_num_frees_);
+  EXPECT_EQ(0U, alloced_ptrs_.size());
+  ASSERT_EQ(0U, stored_reports_.size());
+}
+
+TEST_F(LeakDetectorImplTest, JuliaSetWithLeak) {
+  JuliaSet(true /* enable_leaks */);
+
+  // JuliaSet() should have leaked some memory from two call sites.
+  EXPECT_GT(total_num_allocs_, total_num_frees_);
+  EXPECT_GT(alloced_ptrs_.size(), 0U);
+
+  // There should be one unique leak report generated for each leaky call site.
+  ASSERT_EQ(2U, stored_reports_.size());
+
+  // The reports should be stored in order of size.
+
+  // |report1| comes from the call site in JuliaSet() corresponding to
+  // |kStack3|.
+  const InternalLeakReport& report1 = *stored_reports_.begin();
+  EXPECT_EQ(sizeof(Complex) + 40, report1.alloc_size_bytes());
+  EXPECT_EQ(kStack3.depth, report1.call_stack().size());
+  for (size_t i = 0; i < kStack3.depth && i < report1.call_stack().size();
+       ++i) {
+    // The call stack's addresses may not fall within the mapping address.
+    // Those that don't will not be converted to mapping offsets.
+    if (kStack3.stack[i] >= kMappingAddr &&
+        kStack3.stack[i] <= kMappingAddr + kMappingSize) {
+      EXPECT_EQ(kStack3.stack[i] - kMappingAddr, report1.call_stack()[i]);
+    } else {
+      EXPECT_EQ(kStack3.stack[i], report1.call_stack()[i]);
+    }
+  }
+
+  // |report2| comes from the call site in JuliaSet() corresponding to
+  // |kStack4|.
+  const InternalLeakReport& report2 = *(++stored_reports_.begin());
+  EXPECT_EQ(sizeof(Complex) + 52, report2.alloc_size_bytes());
+  EXPECT_EQ(kStack4.depth, report2.call_stack().size());
+  for (size_t i = 0; i < kStack4.depth && i < report2.call_stack().size();
+       ++i) {
+    // The call stack's addresses may not fall within the mapping address.
+    // Those that don't will not be converted to mapping offsets.
+    if (kStack4.stack[i] >= kMappingAddr &&
+        kStack4.stack[i] <= kMappingAddr + kMappingSize) {
+      EXPECT_EQ(kStack4.stack[i] - kMappingAddr, report2.call_stack()[i]);
+    } else {
+      EXPECT_EQ(kStack4.stack[i], report2.call_stack()[i]);
+    }
+  }
+}
+
+}  // namespace leak_detector
+}  // namespace metrics
diff --git a/components/metrics/leak_detector/leak_detector_value_type.cc b/components/metrics/leak_detector/leak_detector_value_type.cc
new file mode 100644
index 0000000..4642f515
--- /dev/null
+++ b/components/metrics/leak_detector/leak_detector_value_type.cc
@@ -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.
+
+#include "components/metrics/leak_detector/leak_detector_value_type.h"
+
+#include <stdio.h>
+
+namespace metrics {
+namespace leak_detector {
+
+bool LeakDetectorValueType::operator==(
+    const LeakDetectorValueType& other) const {
+  if (type_ != other.type_)
+    return false;
+
+  switch (type_) {
+    case TYPE_SIZE:
+      return size_ == other.size_;
+    case TYPE_CALL_STACK:
+      return call_stack_ == other.call_stack_;
+    case TYPE_NONE:
+      // "NONE" types are considered to be all identical.
+      return true;
+  }
+  return false;
+}
+
+bool LeakDetectorValueType::operator<(
+    const LeakDetectorValueType& other) const {
+  if (type_ != other.type_)
+    return type_ < other.type_;
+
+  switch (type_) {
+    case TYPE_SIZE:
+      return size_ < other.size_;
+    case TYPE_CALL_STACK:
+      return call_stack_ < other.call_stack_;
+    case TYPE_NONE:
+      // "NONE" types are considered to be all identical.
+      return false;
+  }
+  return false;
+}
+
+}  // namespace leak_detector
+}  // namespace metrics
diff --git a/components/metrics/leak_detector/leak_detector_value_type.h b/components/metrics/leak_detector/leak_detector_value_type.h
new file mode 100644
index 0000000..40f6108
--- /dev/null
+++ b/components/metrics/leak_detector/leak_detector_value_type.h
@@ -0,0 +1,52 @@
+// 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_METRICS_LEAK_DETECTOR_LEAK_DETECTOR_VALUE_TYPE_
+#define COMPONENTS_METRICS_LEAK_DETECTOR_LEAK_DETECTOR_VALUE_TYPE_
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace metrics {
+namespace leak_detector {
+
+// Used for tracking unique call stacks.
+// Not thread-safe.
+struct CallStack;
+
+class LeakDetectorValueType {
+ public:
+  // Supported types.
+  enum Type {
+    TYPE_NONE,
+    TYPE_SIZE,
+    TYPE_CALL_STACK,
+  };
+
+  LeakDetectorValueType() : type_(TYPE_NONE), size_(0), call_stack_(nullptr) {}
+  explicit LeakDetectorValueType(size_t size)
+      : type_(TYPE_SIZE), size_(size), call_stack_(nullptr) {}
+  explicit LeakDetectorValueType(const CallStack* call_stack)
+      : type_(TYPE_CALL_STACK), size_(0), call_stack_(call_stack) {}
+
+  // Accessors.
+  Type type() const { return type_; }
+  size_t size() const { return size_; }
+  const CallStack* call_stack() const { return call_stack_; }
+
+  // Comparators.
+  bool operator==(const LeakDetectorValueType& other) const;
+  bool operator<(const LeakDetectorValueType& other) const;
+
+ private:
+  Type type_;
+
+  size_t size_;
+  const CallStack* call_stack_;
+};
+
+}  // namespace leak_detector
+}  // namespace metrics
+
+#endif  // COMPONENTS_METRICS_LEAK_DETECTOR_LEAK_DETECTOR_VALUE_TYPE_
diff --git a/components/metrics/leak_detector/ranked_list.cc b/components/metrics/leak_detector/ranked_list.cc
new file mode 100644
index 0000000..d2f335d
--- /dev/null
+++ b/components/metrics/leak_detector/ranked_list.cc
@@ -0,0 +1,49 @@
+// 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/metrics/leak_detector/ranked_list.h"
+
+#include <algorithm>
+
+namespace metrics {
+namespace leak_detector {
+
+RankedList::RankedList(size_t max_size) : max_size_(max_size) {}
+
+RankedList::~RankedList() {}
+
+RankedList::RankedList(RankedList&& other)
+    : max_size_(other.max_size_) {
+  entries_ = std::move(other.entries_);
+}
+
+RankedList& RankedList::operator=(RankedList&& other) {
+  max_size_ = other.max_size_;
+  entries_ = std::move(other.entries_);
+  return *this;
+}
+
+void RankedList::Add(const ValueType& value, int count) {
+  Entry new_entry;
+  new_entry.value = value;
+  new_entry.count = count;
+
+  // Determine where to insert the value given its count.
+  EntryList::iterator iter = std::upper_bound(entries_.begin(), entries_.end(),
+                                              new_entry);
+
+  // If the list is full, do not add any entry with |count| if does not exceed
+  // the lowest count of the entries in the list.
+  if (size() == max_size_ && iter == end())
+    return;
+
+  entries_.insert(iter, new_entry);
+
+  // Limit the list size if it exceeds the maximum allowed size.
+  if (entries_.size() > max_size_)
+    entries_.resize(max_size_);
+}
+
+}  // namespace leak_detector
+}  // namespace metrics
diff --git a/components/metrics/leak_detector/ranked_list.h b/components/metrics/leak_detector/ranked_list.h
new file mode 100644
index 0000000..3058ca1
--- /dev/null
+++ b/components/metrics/leak_detector/ranked_list.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 COMPONENTS_METRICS_LEAK_DETECTOR_RANKED_LIST_H_
+#define COMPONENTS_METRICS_LEAK_DETECTOR_RANKED_LIST_H_
+
+#include <stddef.h>
+
+#include <list>
+
+#include "base/macros.h"
+#include "components/metrics/leak_detector/custom_allocator.h"
+#include "components/metrics/leak_detector/leak_detector_value_type.h"
+#include "components/metrics/leak_detector/stl_allocator.h"
+
+namespace metrics {
+namespace leak_detector {
+
+// RankedList lets you add entries consisting of a value-count pair, and
+// automatically sorts them internally by count in descending order. This allows
+// for the user of this list to put value-count pairs into this list without
+// having to explicitly sort them by count.
+class RankedList {
+ public:
+  using ValueType = LeakDetectorValueType;
+
+  // A single entry in the RankedList. The RankedList sorts entries by |count|
+  // in descending order.
+  struct Entry {
+    ValueType value;
+    int count;
+
+    // Create a < comparator for reverse sorting.
+    bool operator<(const Entry& entry) const { return count > entry.count; }
+  };
+
+  // This class uses CustomAllocator to avoid recursive malloc hook invocation
+  // when analyzing allocs and frees.
+  using EntryList = std::list<Entry, STLAllocator<Entry, CustomAllocator>>;
+  using const_iterator = EntryList::const_iterator;
+
+  explicit RankedList(size_t max_size);
+  ~RankedList();
+
+  // For move semantics.
+  RankedList(RankedList&& other);
+  RankedList& operator=(RankedList&& other);
+
+  // Accessors for begin() and end() const iterators.
+  const_iterator begin() const { return entries_.begin(); }
+  const_iterator end() const { return entries_.end(); }
+
+  size_t size() const { return entries_.size(); }
+  size_t max_size() const { return max_size_; }
+
+  // Add a new value-count pair to the list. Does not check for existing entries
+  // with the same value. Is an O(n) operation due to ordering.
+  void Add(const ValueType& value, int count);
+
+ private:
+  // Max and min counts. Returns 0 if the list is empty.
+  int max_count() const {
+    return entries_.empty() ? 0 : entries_.begin()->count;
+  }
+  int min_count() const {
+    return entries_.empty() ? 0 : entries_.rbegin()->count;
+  }
+
+  // Max number of items that can be stored in the list.
+  size_t max_size_;
+
+  // Points to the array of entries.
+  std::list<Entry, STLAllocator<Entry, CustomAllocator>> entries_;
+
+  DISALLOW_COPY_AND_ASSIGN(RankedList);
+};
+
+}  // namespace leak_detector
+}  // namespace metrics
+
+#endif  // COMPONENTS_METRICS_LEAK_DETECTOR_RANKED_LIST_H_
diff --git a/components/metrics/leak_detector/ranked_list_unittest.cc b/components/metrics/leak_detector/ranked_list_unittest.cc
new file mode 100644
index 0000000..3043257
--- /dev/null
+++ b/components/metrics/leak_detector/ranked_list_unittest.cc
@@ -0,0 +1,268 @@
+// 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/metrics/leak_detector/ranked_list.h"
+
+#include <algorithm>
+
+#include "base/macros.h"
+#include "components/metrics/leak_detector/custom_allocator.h"
+#include "components/metrics/leak_detector/leak_detector_value_type.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+namespace leak_detector {
+
+namespace {
+
+// Makes it easier to instantiate LeakDetectorValueTypes.
+LeakDetectorValueType Value(uint32_t value) {
+  return LeakDetectorValueType(value);
+}
+
+}  // namespace
+
+class RankedListTest : public ::testing::Test {
+ public:
+  RankedListTest() {}
+
+  void SetUp() override { CustomAllocator::Initialize(); }
+  void TearDown() override { EXPECT_TRUE(CustomAllocator::Shutdown()); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RankedListTest);
+};
+
+TEST_F(RankedListTest, Iterators) {
+  RankedList list(10);
+  EXPECT_TRUE(list.begin() == list.end());
+
+  list.Add(Value(0x1234), 100);
+  EXPECT_FALSE(list.begin() == list.end());
+}
+
+TEST_F(RankedListTest, SingleInsertion) {
+  RankedList list(10);
+  EXPECT_EQ(0U, list.size());
+
+  list.Add(Value(0x1234), 100);
+  EXPECT_EQ(1U, list.size());
+
+  auto iter = list.begin();
+  EXPECT_EQ(0x1234U, iter->value.size());
+  EXPECT_EQ(100, iter->count);
+}
+
+TEST_F(RankedListTest, InOrderInsertion) {
+  RankedList list(10);
+  EXPECT_EQ(0U, list.size());
+
+  list.Add(Value(0x1234), 100);
+  EXPECT_EQ(1U, list.size());
+  list.Add(Value(0x2345), 95);
+  EXPECT_EQ(2U, list.size());
+  list.Add(Value(0x3456), 90);
+  EXPECT_EQ(3U, list.size());
+  list.Add(Value(0x4567), 85);
+  EXPECT_EQ(4U, list.size());
+  list.Add(Value(0x5678), 80);
+  EXPECT_EQ(5U, list.size());
+
+  // Iterate through the contents to make sure they match what went in.
+  const RankedList::Entry kExpectedValues[] = {
+      {Value(0x1234), 100}, {Value(0x2345), 95}, {Value(0x3456), 90},
+      {Value(0x4567), 85},  {Value(0x5678), 80},
+  };
+
+  size_t index = 0;
+  for (const auto& entry : list) {
+    EXPECT_LT(index, arraysize(kExpectedValues));
+    EXPECT_EQ(kExpectedValues[index].value.size(), entry.value.size());
+    EXPECT_EQ(kExpectedValues[index].count, entry.count);
+    ++index;
+  }
+}
+
+TEST_F(RankedListTest, ReverseOrderInsertion) {
+  RankedList list(10);
+  EXPECT_EQ(0U, list.size());
+
+  list.Add(Value(0x1234), 0);
+  EXPECT_EQ(1U, list.size());
+  list.Add(Value(0x2345), 5);
+  EXPECT_EQ(2U, list.size());
+  list.Add(Value(0x3456), 10);
+  EXPECT_EQ(3U, list.size());
+  list.Add(Value(0x4567), 15);
+  EXPECT_EQ(4U, list.size());
+  list.Add(Value(0x5678), 20);
+  EXPECT_EQ(5U, list.size());
+
+  // Iterate through the contents to make sure they match what went in.
+  const RankedList::Entry kExpectedValues[] = {
+      {Value(0x5678), 20}, {Value(0x4567), 15}, {Value(0x3456), 10},
+      {Value(0x2345), 5},  {Value(0x1234), 0},
+  };
+
+  size_t index = 0;
+  for (const auto& entry : list) {
+    EXPECT_LT(index, arraysize(kExpectedValues));
+    EXPECT_EQ(kExpectedValues[index].value.size(), entry.value.size());
+    EXPECT_EQ(kExpectedValues[index].count, entry.count);
+    ++index;
+  }
+}
+
+TEST_F(RankedListTest, UnorderedInsertion) {
+  RankedList list(10);
+  EXPECT_EQ(0U, list.size());
+
+  list.Add(Value(0x1234), 15);
+  list.Add(Value(0x2345), 20);
+  list.Add(Value(0x3456), 10);
+  list.Add(Value(0x4567), 30);
+  list.Add(Value(0x5678), 25);
+  EXPECT_EQ(5U, list.size());
+
+  // Iterate through the contents to make sure they match what went in.
+  const RankedList::Entry kExpectedValues1[] = {
+      {Value(0x4567), 30}, {Value(0x5678), 25}, {Value(0x2345), 20},
+      {Value(0x1234), 15}, {Value(0x3456), 10},
+  };
+
+  size_t index = 0;
+  for (const auto& entry : list) {
+    EXPECT_LT(index, arraysize(kExpectedValues1));
+    EXPECT_EQ(kExpectedValues1[index].value.size(), entry.value.size());
+    EXPECT_EQ(kExpectedValues1[index].count, entry.count);
+    ++index;
+  }
+
+  // Add more items.
+  list.Add(Value(0x6789), 35);
+  list.Add(Value(0x789a), 40);
+  list.Add(Value(0x89ab), 50);
+  list.Add(Value(0x9abc), 5);
+  list.Add(Value(0xabcd), 0);
+  EXPECT_EQ(10U, list.size());
+
+  // Iterate through the contents to make sure they match what went in.
+  const RankedList::Entry kExpectedValues2[] = {
+      {Value(0x89ab), 50}, {Value(0x789a), 40}, {Value(0x6789), 35},
+      {Value(0x4567), 30}, {Value(0x5678), 25}, {Value(0x2345), 20},
+      {Value(0x1234), 15}, {Value(0x3456), 10}, {Value(0x9abc), 5},
+      {Value(0xabcd), 0},
+  };
+
+  index = 0;
+  for (const auto& entry : list) {
+    EXPECT_LT(index, arraysize(kExpectedValues2));
+    EXPECT_EQ(kExpectedValues2[index].value.size(), entry.value.size());
+    EXPECT_EQ(kExpectedValues2[index].count, entry.count);
+    ++index;
+  }
+}
+
+TEST_F(RankedListTest, InsertionWithOverflow) {
+  RankedList list(5);
+  EXPECT_EQ(0U, list.size());
+
+  list.Add(Value(0x1234), 15);
+  list.Add(Value(0x2345), 20);
+  list.Add(Value(0x3456), 10);
+  list.Add(Value(0x4567), 30);
+  list.Add(Value(0x5678), 25);
+  EXPECT_EQ(5U, list.size());
+
+  // These values will not make it into the list, which is now full.
+  list.Add(Value(0x6789), 0);
+  EXPECT_EQ(5U, list.size());
+  list.Add(Value(0x789a), 5);
+  EXPECT_EQ(5U, list.size());
+
+  // Iterate through the contents to make sure they match what went in.
+  const RankedList::Entry kExpectedValues1[] = {
+      {Value(0x4567), 30}, {Value(0x5678), 25}, {Value(0x2345), 20},
+      {Value(0x1234), 15}, {Value(0x3456), 10},
+  };
+
+  size_t index = 0;
+  for (const auto& entry : list) {
+    EXPECT_LT(index, arraysize(kExpectedValues1));
+    EXPECT_EQ(kExpectedValues1[index].value.size(), entry.value.size());
+    EXPECT_EQ(kExpectedValues1[index].count, entry.count);
+    ++index;
+  }
+
+  // Insert some more values that go in the middle of the list.
+  list.Add(Value(0x89ab), 27);
+  EXPECT_EQ(5U, list.size());
+  list.Add(Value(0x9abc), 22);
+  EXPECT_EQ(5U, list.size());
+
+  // Iterate through the contents to make sure they match what went in.
+  const RankedList::Entry kExpectedValues2[] = {
+      {Value(0x4567), 30}, {Value(0x89ab), 27}, {Value(0x5678), 25},
+      {Value(0x9abc), 22}, {Value(0x2345), 20},
+  };
+
+  index = 0;
+  for (const auto& entry : list) {
+    EXPECT_LT(index, arraysize(kExpectedValues2));
+    EXPECT_EQ(kExpectedValues2[index].value.size(), entry.value.size());
+    EXPECT_EQ(kExpectedValues2[index].count, entry.count);
+    ++index;
+  }
+
+  // Insert some more values at the front of the list.
+  list.Add(Value(0xabcd), 40);
+  EXPECT_EQ(5U, list.size());
+  list.Add(Value(0xbcde), 35);
+  EXPECT_EQ(5U, list.size());
+
+  // Iterate through the contents to make sure they match what went in.
+  const RankedList::Entry kExpectedValues3[] = {
+      {Value(0xabcd), 40}, {Value(0xbcde), 35}, {Value(0x4567), 30},
+      {Value(0x89ab), 27}, {Value(0x5678), 25},
+  };
+
+  index = 0;
+  for (const auto& entry : list) {
+    EXPECT_LT(index, arraysize(kExpectedValues3));
+    EXPECT_EQ(kExpectedValues3[index].value.size(), entry.value.size());
+    EXPECT_EQ(kExpectedValues3[index].count, entry.count);
+    ++index;
+  }
+}
+
+TEST_F(RankedListTest, MoveOperation) {
+  const RankedList::Entry kExpectedValues[] = {
+      {Value(0x89ab), 50}, {Value(0x789a), 40}, {Value(0x6789), 35},
+      {Value(0x4567), 30}, {Value(0x5678), 25}, {Value(0x2345), 20},
+      {Value(0x1234), 15}, {Value(0x3456), 10}, {Value(0x9abc), 5},
+      {Value(0xabcd), 0},
+  };
+
+  RankedList source_list(10);
+  for (const RankedList::Entry& entry : kExpectedValues) {
+    source_list.Add(entry.value, entry.count);
+  }
+  EXPECT_EQ(10U, source_list.size());
+
+  RankedList dest_list(25);  // This should be changed by the move.
+  dest_list = std::move(source_list);
+  EXPECT_EQ(10U, dest_list.size());
+  EXPECT_EQ(10U, dest_list.max_size());
+
+  size_t index = 0;
+  for (const auto& entry : dest_list) {
+    EXPECT_LT(index, arraysize(kExpectedValues));
+    EXPECT_EQ(kExpectedValues[index].value.size(), entry.value.size());
+    EXPECT_EQ(kExpectedValues[index].count, entry.count);
+    ++index;
+  }
+}
+
+}  // namespace leak_detector
+}  // namespace metrics
diff --git a/components/metrics/leak_detector/stl_allocator.h b/components/metrics/leak_detector/stl_allocator.h
new file mode 100644
index 0000000..bfef0a38
--- /dev/null
+++ b/components/metrics/leak_detector/stl_allocator.h
@@ -0,0 +1,61 @@
+// 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_METRICS_LEAK_DETECTOR_STL_ALLOCATOR_H_
+#define COMPONENTS_METRICS_LEAK_DETECTOR_STL_ALLOCATOR_H_
+
+#include <stddef.h>
+
+#include <limits>
+#include <memory>
+
+#include "base/logging.h"
+
+// Generic allocator class for STL objects.
+// deallocate() to use the template class Alloc's allocation.
+// that uses a given type-less allocator Alloc, which must provide:
+//   static void* Alloc::Allocate(size_t size);
+//   static void Alloc::Free(void* ptr, size_t size);
+//
+// Inherits from the default allocator, std::allocator. Overrides allocate() and
+// deallocate() and some other functions.
+//
+// STLAllocator<T, MyAlloc> provides the same thread-safety guarantees as
+// MyAlloc.
+//
+// Usage example:
+//   set<T, less<T>, STLAllocator<T, MyAlloc> > my_set;
+
+template <typename T, class Alloc>
+class STLAllocator : public std::allocator<T> {
+ public:
+  typedef size_t size_type;
+  typedef T* pointer;
+
+  template <class T1>
+  struct rebind {
+    typedef STLAllocator<T1, Alloc> other;
+  };
+
+  STLAllocator() {}
+  explicit STLAllocator(const STLAllocator&) {}
+  template <class T1>
+  STLAllocator(const STLAllocator<T1, Alloc>&) {}
+  ~STLAllocator() {}
+
+  pointer allocate(size_type n, const void* = 0) {
+    // Make sure the computation of the total allocation size does not cause an
+    // integer overflow.
+    RAW_CHECK(n < max_size());
+    return static_cast<T*>(Alloc::Allocate(n * sizeof(T)));
+  }
+
+  void deallocate(pointer p, size_type n) { Alloc::Free(p, n * sizeof(T)); }
+
+  size_type max_size() const {
+    return std::numeric_limits<size_t>::max() / sizeof(T);
+  }
+};
+
+#endif  // COMPONENTS_METRICS_LEAK_DETECTOR_STL_ALLOCATOR_H_
diff --git a/components/metrics/stability_metrics_helper.cc b/components/metrics/stability_metrics_helper.cc
index 73aaeec..1597791a 100644
--- a/components/metrics/stability_metrics_helper.cc
+++ b/components/metrics/stability_metrics_helper.cc
@@ -42,7 +42,7 @@
   // Since |abs(STATUS_GUARD_PAGE_VIOLATION) == MAX_INT| it causes problems in
   // histograms.cc. Solve this by remapping it to a smaller value, which
   // hopefully doesn't conflict with other codes.
-  if (exit_code == STATUS_GUARD_PAGE_VIOLATION)
+  if (static_cast<DWORD>(exit_code) == STATUS_GUARD_PAGE_VIOLATION)
     return 0x1FCF7EC3;  // Randomly picked number.
 #endif
 
diff --git a/components/mus/android_loader.cc b/components/mus/android_loader.cc
index 06b78691..a7e9b72d 100644
--- a/components/mus/android_loader.cc
+++ b/components/mus/android_loader.cc
@@ -17,7 +17,7 @@
     mojo::InterfaceRequest<mojo::Application> application_request) {
   DCHECK(application_request.is_pending());
   app_.reset(new mojo::ApplicationImpl(new MandolineUIServicesApp,
-                                       application_request.Pass()));
+                                       std::move(application_request)));
 }
 
 }  // namespace mus
diff --git a/components/mus/gles2/command_buffer_driver.cc b/components/mus/gles2/command_buffer_driver.cc
index 2ef83e1f..d4b45d7 100644
--- a/components/mus/gles2/command_buffer_driver.cc
+++ b/components/mus/gles2/command_buffer_driver.cc
@@ -147,11 +147,11 @@
 
   const size_t kSize = sizeof(gpu::CommandBufferSharedState);
   scoped_ptr<gpu::BufferBacking> backing(
-      MojoBufferBacking::Create(shared_state.Pass(), kSize));
+      MojoBufferBacking::Create(std::move(shared_state), kSize));
   if (!backing)
     return false;
 
-  command_buffer_->SetSharedStateBuffer(backing.Pass());
+  command_buffer_->SetSharedStateBuffer(std::move(backing));
   return true;
 }
 
@@ -177,12 +177,12 @@
   // Take ownership of the memory and map it into this process.
   // This validates the size.
   scoped_ptr<gpu::BufferBacking> backing(
-      MojoBufferBacking::Create(transfer_buffer.Pass(), size));
+      MojoBufferBacking::Create(std::move(transfer_buffer), size));
   if (!backing) {
     DVLOG(0) << "Failed to map shared memory.";
     return;
   }
-  command_buffer_->RegisterTransferBuffer(id, backing.Pass());
+  command_buffer_->RegisterTransferBuffer(id, std::move(backing));
 }
 
 void CommandBufferDriver::DestroyTransferBuffer(int32_t id) {
diff --git a/components/mus/gles2/command_buffer_driver.h b/components/mus/gles2/command_buffer_driver.h
index 2ac36e5a..dda41f9 100644
--- a/components/mus/gles2/command_buffer_driver.h
+++ b/components/mus/gles2/command_buffer_driver.h
@@ -49,7 +49,7 @@
 
   ~CommandBufferDriver();
 
-  void set_client(scoped_ptr<Client> client) { client_ = client.Pass(); }
+  void set_client(scoped_ptr<Client> client) { client_ = std::move(client); }
 
   bool Initialize(mojo::InterfacePtrInfo<
                       mojom::CommandBufferLostContextObserver> loss_observer,
diff --git a/components/mus/gles2/command_buffer_local.cc b/components/mus/gles2/command_buffer_local.cc
index 178de61..99b8018 100644
--- a/components/mus/gles2/command_buffer_local.cc
+++ b/components/mus/gles2/command_buffer_local.cc
@@ -228,6 +228,10 @@
   return command_buffer_id_;
 }
 
+int32_t CommandBufferLocal::GetExtraCommandBufferData() const {
+  return 0;
+}
+
 uint64_t CommandBufferLocal::GenerateFenceSyncRelease() {
   return next_fence_sync_release_++;
 }
diff --git a/components/mus/gles2/command_buffer_local.h b/components/mus/gles2/command_buffer_local.h
index 077cf065..70811090 100644
--- a/components/mus/gles2/command_buffer_local.h
+++ b/components/mus/gles2/command_buffer_local.h
@@ -73,6 +73,7 @@
   bool IsGpuChannelLost() override;
   gpu::CommandBufferNamespace GetNamespaceID() const override;
   uint64_t GetCommandBufferID() const override;
+  int32_t GetExtraCommandBufferData() const override;
   uint64_t GenerateFenceSyncRelease() override;
   bool IsFenceSyncRelease(uint64_t release) override;
   bool IsFenceSyncFlushed(uint64_t release) override;
diff --git a/components/mus/gles2/command_buffer_type_conversions.cc b/components/mus/gles2/command_buffer_type_conversions.cc
index 1bd83993..56353acf 100644
--- a/components/mus/gles2/command_buffer_type_conversions.cc
+++ b/components/mus/gles2/command_buffer_type_conversions.cc
@@ -29,7 +29,7 @@
   result->error = input.error;
   result->context_lost_reason = input.context_lost_reason;
   result->generation = input.generation;
-  return result.Pass();
+  return result;
 }
 
 gpu::CommandBuffer::State
@@ -52,7 +52,7 @@
   result->min_range = input.min_range;
   result->max_range = input.max_range;
   result->precision = input.precision;
-  return result.Pass();
+  return result;
 }
 
 gpu::Capabilities::ShaderPrecision TypeConverter<
@@ -75,7 +75,7 @@
   result->low_float = GpuShaderPrecision::From(input.low_float);
   result->medium_float = GpuShaderPrecision::From(input.medium_float);
   result->high_float = GpuShaderPrecision::From(input.high_float);
-  return result.Pass();
+  return result;
 }
 
 gpu::Capabilities::PerStagePrecisions TypeConverter<
@@ -133,7 +133,7 @@
   result->blend_equation_advanced = input.blend_equation_advanced;
   result->blend_equation_advanced_coherent =
       input.blend_equation_advanced_coherent;
-  return result.Pass();
+  return result;
 }
 
 gpu::Capabilities TypeConverter<gpu::Capabilities, GpuCapabilitiesPtr>::Convert(
@@ -189,7 +189,7 @@
   result->renderer_info = mojo::String::From<std::string>(input.gl_renderer);
   result->driver_version =
       mojo::String::From<std::string>(input.driver_version);
-  return result.Pass();
+  return result;
 }
 
 }  // namespace mojo
diff --git a/components/mus/gles2/gpu_impl.cc b/components/mus/gles2/gpu_impl.cc
index e23add8..f00bbc78 100644
--- a/components/mus/gles2/gpu_impl.cc
+++ b/components/mus/gles2/gpu_impl.cc
@@ -12,14 +12,13 @@
 
 GpuImpl::GpuImpl(mojo::InterfaceRequest<Gpu> request,
                  const scoped_refptr<GpuState>& state)
-    : binding_(this, request.Pass()), state_(state) {
-}
+    : binding_(this, std::move(request)), state_(state) {}
 
 GpuImpl::~GpuImpl() {}
 
 void GpuImpl::CreateOffscreenGLES2Context(
     mojo::InterfaceRequest<mojom::CommandBuffer> request) {
-  new CommandBufferImpl(request.Pass(), state_,
+  new CommandBufferImpl(std::move(request), state_,
                         make_scoped_ptr(new CommandBufferDriver(state_)));
 }
 
diff --git a/components/mus/gles2/mojo_buffer_backing.cc b/components/mus/gles2/mojo_buffer_backing.cc
index 1beadb32..5aae1d1 100644
--- a/components/mus/gles2/mojo_buffer_backing.cc
+++ b/components/mus/gles2/mojo_buffer_backing.cc
@@ -11,7 +11,7 @@
 MojoBufferBacking::MojoBufferBacking(mojo::ScopedSharedBufferHandle handle,
                                      void* memory,
                                      size_t size)
-    : handle_(handle.Pass()), memory_(memory), size_(size) {}
+    : handle_(std::move(handle)), memory_(memory), size_(size) {}
 
 MojoBufferBacking::~MojoBufferBacking() {
   mojo::UnmapBuffer(memory_);
@@ -28,7 +28,7 @@
     return scoped_ptr<BufferBacking>();
   DCHECK(memory);
   return scoped_ptr<BufferBacking>(
-      new MojoBufferBacking(handle.Pass(), memory, size));
+      new MojoBufferBacking(std::move(handle), memory, size));
 }
 void* MojoBufferBacking::GetMemory() const {
   return memory_;
diff --git a/components/mus/gles2/mojo_gpu_memory_buffer.cc b/components/mus/gles2/mojo_gpu_memory_buffer.cc
index f5172633..f54757f 100644
--- a/components/mus/gles2/mojo_gpu_memory_buffer.cc
+++ b/components/mus/gles2/mojo_gpu_memory_buffer.cc
@@ -17,7 +17,7 @@
     scoped_ptr<base::SharedMemory> shared_memory)
     : size_(size),
       format_(format),
-      shared_memory_(shared_memory.Pass()),
+      shared_memory_(std::move(shared_memory)),
       mapped_(false) {}
 
 MojoGpuMemoryBufferImpl::~MojoGpuMemoryBufferImpl() {}
@@ -40,7 +40,7 @@
 #endif  // defined(OS_MACOSX)
 
   return make_scoped_ptr<gfx::GpuMemoryBuffer>(
-      new MojoGpuMemoryBufferImpl(size, format, shared_memory.Pass()));
+      new MojoGpuMemoryBufferImpl(size, format, std::move(shared_memory)));
 }
 
 MojoGpuMemoryBufferImpl* MojoGpuMemoryBufferImpl::FromClientBuffer(
diff --git a/components/mus/mus_app.cc b/components/mus/mus_app.cc
index bb8657cb..b3138dd3 100644
--- a/components/mus/mus_app.cc
+++ b/components/mus/mus_app.cc
@@ -86,7 +86,7 @@
   WindowManagerRequests requests;
   requests.swap(pending_window_manager_requests_);
   for (auto& request : requests)
-    Create(nullptr, request->Pass());
+    Create(nullptr, std::move(*request));
 }
 
 void MandolineUIServicesApp::OnNoMoreRootConnections() {
@@ -103,8 +103,9 @@
     mojom::WindowTreeClientPtr client) {
   scoped_ptr<ws::WindowTreeImpl> service(new ws::WindowTreeImpl(
       connection_manager, creator_id, root_id, policy_bitmask));
-  return new ws::DefaultClientConnection(service.Pass(), connection_manager,
-                                         tree_request.Pass(), client.Pass());
+  return new ws::DefaultClientConnection(std::move(service), connection_manager,
+                                         std::move(tree_request),
+                                         std::move(client));
 }
 
 void MandolineUIServicesApp::Create(
@@ -112,7 +113,7 @@
     mojo::InterfaceRequest<mojom::WindowManager> request) {
   if (!connection_manager_->has_tree_host_connections()) {
     pending_window_manager_requests_.push_back(make_scoped_ptr(
-        new mojo::InterfaceRequest<mojom::WindowManager>(request.Pass())));
+        new mojo::InterfaceRequest<mojom::WindowManager>(std::move(request))));
     return;
   }
   if (!window_manager_impl_) {
@@ -120,19 +121,19 @@
         new ws::ForwardingWindowManager(connection_manager_.get()));
   }
   window_manager_bindings_.AddBinding(window_manager_impl_.get(),
-                                      request.Pass());
+                                      std::move(request));
 }
 
 void MandolineUIServicesApp::Create(
     ApplicationConnection* connection,
     InterfaceRequest<WindowTreeHostFactory> request) {
-  factory_bindings_.AddBinding(this, request.Pass());
+  factory_bindings_.AddBinding(this, std::move(request));
 }
 
 void MandolineUIServicesApp::Create(mojo::ApplicationConnection* connection,
                                     mojo::InterfaceRequest<Gpu> request) {
   DCHECK(gpu_state_);
-  new GpuImpl(request.Pass(), gpu_state_);
+  new GpuImpl(std::move(request), gpu_state_);
 }
 
 void MandolineUIServicesApp::CreateWindowTreeHost(
@@ -145,12 +146,12 @@
   // TODO(fsamuel): We need to make sure that only the window manager can create
   // new roots.
   ws::WindowTreeHostImpl* host_impl = new ws::WindowTreeHostImpl(
-      host_client.Pass(), connection_manager_.get(), app_impl_, gpu_state_,
-      surfaces_state_, window_manager.Pass());
+      std::move(host_client), connection_manager_.get(), app_impl_, gpu_state_,
+      surfaces_state_, std::move(window_manager));
 
   // WindowTreeHostConnection manages its own lifetime.
   host_impl->Init(new ws::WindowTreeHostConnectionImpl(
-      host.Pass(), make_scoped_ptr(host_impl), tree_client.Pass(),
+      std::move(host), make_scoped_ptr(host_impl), std::move(tree_client),
       connection_manager_.get()));
 }
 
diff --git a/components/mus/public/cpp/lib/context_provider.cc b/components/mus/public/cpp/lib/context_provider.cc
index 256939e7..c44d398 100644
--- a/components/mus/public/cpp/lib/context_provider.cc
+++ b/components/mus/public/cpp/lib/context_provider.cc
@@ -13,7 +13,8 @@
 
 ContextProvider::ContextProvider(
     mojo::ScopedMessagePipeHandle command_buffer_handle)
-    : command_buffer_handle_(command_buffer_handle.Pass()), context_(nullptr) {
+    : command_buffer_handle_(std::move(command_buffer_handle)),
+      context_(nullptr) {
   // Enabled the CHROMIUM_image extension to use GpuMemoryBuffers. The
   // implementation of which is used in CommandBufferDriver.
   capabilities_.gpu.image = true;
diff --git a/components/mus/public/cpp/lib/event_matcher.cc b/components/mus/public/cpp/lib/event_matcher.cc
index b619adf..e52e97c 100644
--- a/components/mus/public/cpp/lib/event_matcher.cc
+++ b/components/mus/public/cpp/lib/event_matcher.cc
@@ -23,7 +23,7 @@
   matcher->type_matcher->type = mus::mojom::EVENT_TYPE_KEY_PRESSED;
   matcher->flags_matcher->flags = flags;
   matcher->key_matcher->keyboard_code = code;
-  return matcher.Pass();
+  return matcher;
 }
 
 }  // namespace mus
diff --git a/components/mus/public/cpp/lib/in_flight_change.cc b/components/mus/public/cpp/lib/in_flight_change.cc
index 922ae13..8e3b8de 100644
--- a/components/mus/public/cpp/lib/in_flight_change.cc
+++ b/components/mus/public/cpp/lib/in_flight_change.cc
@@ -118,7 +118,7 @@
 
 void InFlightPropertyChange::Revert() {
   WindowPrivate(window())
-      .LocalSetSharedProperty(property_name_, revert_value_.Pass());
+      .LocalSetSharedProperty(property_name_, std::move(revert_value_));
 }
 
 // InFlightPredefinedCursorChange ---------------------------------------------
diff --git a/components/mus/public/cpp/lib/in_flight_change.h b/components/mus/public/cpp/lib/in_flight_change.h
index 54aa779..4537fd7 100644
--- a/components/mus/public/cpp/lib/in_flight_change.h
+++ b/components/mus/public/cpp/lib/in_flight_change.h
@@ -131,7 +131,6 @@
   void Revert() override;
 
  private:
-  Window* window_;
   gfx::Rect revert_bounds_;
 
   DISALLOW_COPY_AND_ASSIGN(InFlightBoundsChange);
@@ -221,7 +220,6 @@
   void Revert() override;
 
  private:
-  Window* window_;
   bool revert_visible_;
 
   DISALLOW_COPY_AND_ASSIGN(InFlightVisibleChange);
diff --git a/components/mus/public/cpp/lib/output_surface.cc b/components/mus/public/cpp/lib/output_surface.cc
index 83f7f7a..f5f0469 100644
--- a/components/mus/public/cpp/lib/output_surface.cc
+++ b/components/mus/public/cpp/lib/output_surface.cc
@@ -16,7 +16,7 @@
 OutputSurface::OutputSurface(
     const scoped_refptr<cc::ContextProvider>& context_provider,
     scoped_ptr<mus::WindowSurface> surface)
-    : cc::OutputSurface(context_provider), surface_(surface.Pass()) {
+    : cc::OutputSurface(context_provider), surface_(std::move(surface)) {
   capabilities_.delegated_rendering = true;
 }
 
diff --git a/components/mus/public/cpp/lib/window.cc b/components/mus/public/cpp/lib/window.cc
index c09438c..f242d11 100644
--- a/components/mus/public/cpp/lib/window.cc
+++ b/components/mus/public/cpp/lib/window.cc
@@ -349,14 +349,14 @@
 
 void Window::SetTextInputState(mojo::TextInputStatePtr state) {
   if (connection_)
-    tree_client()->SetWindowTextInputState(id_, state.Pass());
+    tree_client()->SetWindowTextInputState(id_, std::move(state));
 }
 
 void Window::SetImeVisibility(bool visible, mojo::TextInputStatePtr state) {
   // SetImeVisibility() shouldn't be used if the window is not editable.
   DCHECK(state.is_null() || state->type != mojo::TEXT_INPUT_TYPE_NONE);
   if (connection_)
-    tree_client()->SetImeVisibility(id_, visible, state.Pass());
+    tree_client()->SetImeVisibility(id_, visible, std::move(state));
 }
 
 void Window::SetFocus() {
@@ -374,7 +374,7 @@
 }
 
 void Window::Embed(mus::mojom::WindowTreeClientPtr client) {
-  Embed(client.Pass(), mus::mojom::WindowTree::ACCESS_POLICY_DEFAULT,
+  Embed(std::move(client), mus::mojom::WindowTree::ACCESS_POLICY_DEFAULT,
         base::Bind(&EmptyEmbedCallback));
 }
 
@@ -382,7 +382,7 @@
                    uint32_t policy_bitmask,
                    const EmbedCallback& callback) {
   if (PrepareForEmbed())
-    tree_client()->Embed(id_, client.Pass(), policy_bitmask, callback);
+    tree_client()->Embed(id_, std::move(client), policy_bitmask, callback);
   else
     callback.Run(false, 0);
 }
@@ -395,9 +395,7 @@
 mojom::ViewportMetricsPtr CreateEmptyViewportMetrics() {
   mojom::ViewportMetricsPtr metrics = mojom::ViewportMetrics::New();
   metrics->size_in_pixels = mojo::Size::New();
-  // TODO(vtl): The |.Pass()| below is only needed due to an MSVS bug; remove it
-  // once that's fixed.
-  return metrics.Pass();
+  return metrics;
 }
 
 }  // namespace
@@ -416,6 +414,14 @@
 Window::~Window() {
   FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroying(this));
 
+  if (HasFocus()) {
+    // 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.
+    tree_client()->LocalSetFocus(nullptr);
+  }
+
   // Remove from transient parent.
   if (transient_parent_)
     transient_parent_->LocalRemoveTransientWindow(this);
@@ -440,11 +446,6 @@
     DCHECK(children_.empty() || children_.front() != child);
   }
 
-  // TODO(beng): It'd be better to do this via a destruction observer in the
-  //             WindowTreeClientImpl.
-  if (connection_)
-    tree_client()->RemoveWindow(id_);
-
   // Clear properties.
   for (auto& pair : prop_map_) {
     if (pair.second.deallocator)
@@ -454,8 +455,10 @@
 
   FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroyed(this));
 
-  if (connection_ && connection_->GetRoot() == this)
-    tree_client()->OnRootDestroyed(this);
+  // Invoke after observers so that can clean up any internal state observers
+  // may have changed.
+  if (tree_client())
+    tree_client()->OnWindowDestroyed(this);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -488,7 +491,7 @@
         memcpy(&transport_value.front(), &(value->front()), value->size());
     }
     // TODO: add test coverage of this (450303).
-    tree_client()->SetProperty(this, name, transport_value.Pass());
+    tree_client()->SetProperty(this, name, std::move(transport_value));
   }
   LocalSetSharedProperty(name, value);
 }
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 4e0d946..b4dfc50 100644
--- a/components/mus/public/cpp/lib/window_tree_client_impl.cc
+++ b/components/mus/public/cpp/lib/window_tree_client_impl.cc
@@ -83,7 +83,7 @@
     mojo::InterfaceRequest<mojom::WindowTreeClient> request,
     CreateType create_type) {
   WindowTreeClientImpl* client =
-      new WindowTreeClientImpl(delegate, nullptr, request.Pass());
+      new WindowTreeClientImpl(delegate, nullptr, std::move(request));
   if (create_type == CreateType::WAIT_FOR_EMBED)
     client->WaitForEmbed();
   return client;
@@ -95,7 +95,7 @@
     CreateType create_type,
     WindowManagerDelegate* window_manager_delegate) {
   WindowTreeClientImpl* client = new WindowTreeClientImpl(
-      delegate, window_manager_delegate, request.Pass());
+      delegate, window_manager_delegate, std::move(request));
   if (create_type == CreateType::WAIT_FOR_EMBED)
     client->WaitForEmbed();
   return client;
@@ -118,7 +118,7 @@
       in_destructor_(false) {
   // Allow for a null request in tests.
   if (request.is_pending())
-    binding_.Bind(request.Pass());
+    binding_.Bind(std::move(request));
 }
 
 WindowTreeClientImpl::~WindowTreeClientImpl() {
@@ -269,21 +269,21 @@
   const uint32_t change_id = ScheduleInFlightChange(
       make_scoped_ptr(new InFlightPropertyChange(window, name, old_value)));
   tree_->SetWindowProperty(change_id, window->id(), mojo::String(name),
-                           data.Pass());
+                           std::move(data));
 }
 
 void WindowTreeClientImpl::SetWindowTextInputState(
     Id window_id,
     mojo::TextInputStatePtr state) {
   DCHECK(tree_);
-  tree_->SetWindowTextInputState(window_id, state.Pass());
+  tree_->SetWindowTextInputState(window_id, std::move(state));
 }
 
 void WindowTreeClientImpl::SetImeVisibility(Id window_id,
                                             bool visible,
                                             mojo::TextInputStatePtr state) {
   DCHECK(tree_);
-  tree_->SetImeVisibility(window_id, visible, state.Pass());
+  tree_->SetImeVisibility(window_id, visible, std::move(state));
 }
 
 void WindowTreeClientImpl::Embed(
@@ -292,7 +292,7 @@
     uint32_t policy_bitmask,
     const mojom::WindowTree::EmbedCallback& callback) {
   DCHECK(tree_);
-  tree_->Embed(window_id, client.Pass(), policy_bitmask, callback);
+  tree_->Embed(window_id, std::move(client), policy_bitmask, callback);
 }
 
 void WindowTreeClientImpl::AttachSurface(
@@ -301,7 +301,7 @@
     mojo::InterfaceRequest<mojom::Surface> surface,
     mojom::SurfaceClientPtr client) {
   DCHECK(tree_);
-  tree_->AttachSurface(window_id, type, surface.Pass(), client.Pass());
+  tree_->AttachSurface(window_id, type, std::move(surface), std::move(client));
 }
 
 void WindowTreeClientImpl::LocalSetFocus(Window* focused) {
@@ -327,36 +327,25 @@
   windows_[window->id()] = window;
 }
 
-void WindowTreeClientImpl::RemoveWindow(Id window_id) {
-  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())
-    windows_.erase(it);
+void WindowTreeClientImpl::OnWindowDestroyed(Window* window) {
+  windows_.erase(window->id());
 
   // Remove any InFlightChanges associated with the window.
-  std::set<uint32_t> in_flight_change_ids;
+  std::set<uint32_t> in_flight_change_ids_to_remove;
   for (const auto& pair : in_flight_map_) {
-    if (pair.second->window() && pair.second->window()->id() == window_id)
-      in_flight_change_ids.insert(pair.first);
+    if (pair.second->window() == window)
+      in_flight_change_ids_to_remove.insert(pair.first);
   }
-  for (auto change_id : in_flight_change_ids)
+  for (auto change_id : in_flight_change_ids_to_remove)
     in_flight_map_.erase(change_id);
-}
 
-void WindowTreeClientImpl::OnRootDestroyed(Window* root) {
-  DCHECK_EQ(root, root_);
-  root_ = nullptr;
+  if (window == root_) {
+    root_ = nullptr;
 
-  // When the root is gone we can't do anything useful.
-  if (!in_destructor_)
-    delete this;
+    // When the root is gone we can't do anything useful.
+    if (!in_destructor_)
+      delete this;
+  }
 }
 
 InFlightChange* WindowTreeClientImpl::GetOldestInFlightChangeMatching(
@@ -373,6 +362,7 @@
 
 uint32_t WindowTreeClientImpl::ScheduleInFlightChange(
     scoped_ptr<InFlightChange> change) {
+  DCHECK(!change->window() || windows_.count(change->window()->id()) > 0);
   const uint32_t change_id = next_change_id_++;
   in_flight_map_[change_id] = std::move(change);
   return change_id;
@@ -443,7 +433,7 @@
     transport_properties =
         mojo::Map<mojo::String, mojo::Array<uint8_t>>::From(*properties);
   }
-  tree_->NewWindow(change_id, window->id(), transport_properties.Pass());
+  tree_->NewWindow(change_id, window->id(), std::move(transport_properties));
   return window;
 }
 
@@ -473,9 +463,9 @@
                                    Id focused_window_id,
                                    uint32 access_policy) {
   DCHECK(!tree_ptr_);
-  tree_ptr_ = tree.Pass();
+  tree_ptr_ = std::move(tree);
   tree_ptr_.set_connection_error_handler([this]() { delete this; });
-  OnEmbedImpl(tree_ptr_.get(), connection_id, root_data.Pass(),
+  OnEmbedImpl(tree_ptr_.get(), connection_id, std::move(root_data),
               focused_window_id, access_policy);
 }
 
@@ -634,7 +624,7 @@
   if (ApplyServerChangeToExistingInFlightChange(new_change))
     return;
 
-  WindowPrivate(window).LocalSetSharedProperty(name, new_data.Pass());
+  WindowPrivate(window).LocalSetSharedProperty(name, std::move(new_data));
 }
 
 void WindowTreeClientImpl::OnWindowInputEvent(uint32_t event_id,
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 7e46a79a..abf688f 100644
--- a/components/mus/public/cpp/lib/window_tree_client_impl.h
+++ b/components/mus/public/cpp/lib/window_tree_client_impl.h
@@ -96,14 +96,12 @@
   // Start/stop tracking windows. While tracked, they can be retrieved via
   // WindowTreeConnection::GetWindowById.
   void AddWindow(Window* window);
-  void RemoveWindow(Id window_id);
 
   bool is_embed_root() const { return is_embed_root_; }
 
-  // Called after the root window's observers have been notified of destruction
-  // (as the last step of ~Window). This ordering ensures that the Window Server
-  // is torn down after the root.
-  void OnRootDestroyed(Window* root);
+  // Called after the window's observers have been notified of destruction (as
+  // the last step of ~Window).
+  void OnWindowDestroyed(Window* window);
 
  private:
   friend class WindowTreeClientImplPrivate;
diff --git a/components/mus/public/cpp/lib/window_tree_host_factory.cc b/components/mus/public/cpp/lib/window_tree_host_factory.cc
index 59e3cf42..98c111b 100644
--- a/components/mus/public/cpp/lib/window_tree_host_factory.cc
+++ b/components/mus/public/cpp/lib/window_tree_host_factory.cc
@@ -21,8 +21,9 @@
       delegate, GetProxy(&tree_client),
       WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED,
       window_manager_delegate);
-  factory->CreateWindowTreeHost(GetProxy(host), host_client.Pass(),
-                                tree_client.Pass(), window_manager.Pass());
+  factory->CreateWindowTreeHost(GetProxy(host), std::move(host_client),
+                                std::move(tree_client),
+                                std::move(window_manager));
 }
 
 void CreateSingleWindowTreeHost(
@@ -34,8 +35,8 @@
     WindowManagerDelegate* window_manager_delegate) {
   mojom::WindowTreeHostFactoryPtr factory;
   app->ConnectToService("mojo:mus", &factory);
-  CreateWindowTreeHost(factory.get(), host_client.Pass(), delegate, host,
-                       window_manager.Pass(), window_manager_delegate);
+  CreateWindowTreeHost(factory.get(), std::move(host_client), delegate, host,
+                       std::move(window_manager), window_manager_delegate);
 }
 
 }  // namespace mus
diff --git a/components/mus/public/cpp/tests/window_server_test_base.cc b/components/mus/public/cpp/tests/window_server_test_base.cc
index e4ccdec..2022faa 100644
--- a/components/mus/public/cpp/tests/window_server_test_base.cc
+++ b/components/mus/public/cpp/tests/window_server_test_base.cc
@@ -99,7 +99,7 @@
     mojo::ApplicationConnection* connection,
     mojo::InterfaceRequest<mojom::WindowTreeClient> request) {
   WindowTreeConnection::Create(
-      this, request.Pass(),
+      this, std::move(request),
       WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
 }
 
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 14542b8..3164536 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
@@ -30,7 +30,7 @@
   mojo::Array<uint8_t> transport_value;
   transport_value.resize(bytes.size());
   memcpy(&transport_value.front(), &(bytes.front()), bytes.size());
-  return transport_value.Pass();
+  return transport_value;
 }
 
 class TestWindowTreeDelegate : public WindowTreeDelegate {
@@ -64,7 +64,7 @@
     root_data->viewport_metrics->size_in_pixels =
         mojo::Size::From(gfx::Size(1000, 1000));
     root_data->viewport_metrics->device_pixel_ratio = 1;
-    tree_client_impl_->OnEmbedImpl(window_tree, 1, root_data.Pass(), 0,
+    tree_client_impl_->OnEmbedImpl(window_tree, 1, std::move(root_data), 0,
                                    access_policy);
   }
 
@@ -444,4 +444,43 @@
   EXPECT_TRUE(child2->HasFocus());
 }
 
+class ToggleVisibilityFromDestroyedObserver : public WindowObserver {
+ public:
+  explicit ToggleVisibilityFromDestroyedObserver(Window* window)
+      : window_(window) {
+    window_->AddObserver(this);
+  }
+
+  ToggleVisibilityFromDestroyedObserver() { EXPECT_FALSE(window_); }
+
+  // WindowObserver:
+  void OnWindowDestroyed(Window* window) override {
+    window_->SetVisible(!window->visible());
+    window_->RemoveObserver(this);
+    window_ = nullptr;
+  }
+
+ private:
+  Window* window_;
+
+  DISALLOW_COPY_AND_ASSIGN(ToggleVisibilityFromDestroyedObserver);
+};
+
+TEST_F(WindowTreeClientImplTest, ToggleVisibilityFromWindowDestroyed) {
+  WindowTreeSetup setup;
+  Window* root = setup.window_tree_connection()->GetRoot();
+  ASSERT_TRUE(root);
+  Window* child1 = setup.window_tree_connection()->NewWindow();
+  root->AddChild(child1);
+  ToggleVisibilityFromDestroyedObserver toggler(child1);
+  // Destroying the window triggers
+  // ToggleVisibilityFromDestroyedObserver::OnWindowDestroyed(), which toggles
+  // the visibility of the window. Ack the change, which should not crash or
+  // trigger DCHECKs.
+  child1->Destroy();
+  uint32_t change_id;
+  ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
+  setup.window_tree_client()->OnChangeCompleted(change_id, true);
+}
+
 }  // namespace mus
diff --git a/components/mus/surfaces/surfaces_scheduler.cc b/components/mus/surfaces/surfaces_scheduler.cc
index f324db7..7338f964 100644
--- a/components/mus/surfaces/surfaces_scheduler.cc
+++ b/components/mus/surfaces/surfaces_scheduler.cc
@@ -19,7 +19,7 @@
                                       rendering_stats_instrumentation_.get()));
   scheduler_ = cc::Scheduler::Create(
       this, settings, 0, base::MessageLoop::current()->task_runner().get(),
-      nullptr, compositor_timing_history.Pass());
+      nullptr, std::move(compositor_timing_history));
   scheduler_->SetVisible(true);
   scheduler_->SetCanDraw(true);
   scheduler_->SetNeedsBeginMainFrame();
diff --git a/components/mus/surfaces/top_level_display_client.cc b/components/mus/surfaces/top_level_display_client.cc
index 7668ce9b..77f9ff0 100644
--- a/components/mus/surfaces/top_level_display_client.cc
+++ b/components/mus/surfaces/top_level_display_client.cc
@@ -61,13 +61,13 @@
 void TopLevelDisplayClient::SubmitCompositorFrame(
     scoped_ptr<cc::CompositorFrame> frame,
     const base::Closure& callback) {
-  pending_frame_ = frame.Pass();
+  pending_frame_ = std::move(frame);
 
   last_submitted_frame_size_ =
       pending_frame_->delegated_frame_data->render_pass_list.back()
           ->output_rect.size();
   display_->Resize(last_submitted_frame_size_);
-  factory_.SubmitCompositorFrame(cc_id_, pending_frame_.Pass(),
+  factory_.SubmitCompositorFrame(cc_id_, std::move(pending_frame_),
                                  base::Bind(&CallCallback, callback));
   surfaces_state_->scheduler()->SetNeedsDraw();
 }
diff --git a/components/mus/ws/client_connection.cc b/components/mus/ws/client_connection.cc
index aa8bf901..91ecd811 100644
--- a/components/mus/ws/client_connection.cc
+++ b/components/mus/ws/client_connection.cc
@@ -13,7 +13,7 @@
 
 ClientConnection::ClientConnection(scoped_ptr<WindowTreeImpl> service,
                                    mojom::WindowTreeClient* client)
-    : service_(service.Pass()), client_(client) {}
+    : service_(std::move(service)), client_(client) {}
 
 ClientConnection::~ClientConnection() {}
 
@@ -22,10 +22,10 @@
     ConnectionManager* connection_manager,
     mojo::InterfaceRequest<mojom::WindowTree> service_request,
     mojom::WindowTreeClientPtr client)
-    : ClientConnection(service_impl.Pass(), client.get()),
+    : ClientConnection(std::move(service_impl), client.get()),
       connection_manager_(connection_manager),
-      binding_(service(), service_request.Pass()),
-      client_(client.Pass()) {
+      binding_(service(), std::move(service_request)),
+      client_(std::move(client)) {
   binding_.set_connection_error_handler(
       [this]() { connection_manager_->OnConnectionError(this); });
 }
diff --git a/components/mus/ws/connection_manager.cc b/components/mus/ws/connection_manager.cc
index 477b4ab..98152b3 100644
--- a/components/mus/ws/connection_manager.cc
+++ b/components/mus/ws/connection_manager.cc
@@ -96,6 +96,11 @@
   for (auto& pair : connection_map_)
     pair.second->service()->OnWillDestroyWindowTreeImpl(connection->service());
 
+  // Notify the host.
+  WindowTreeHostImpl* host = GetWindowTreeHostByWindow(window);
+  if (host)
+    host->OnWindowTreeConnectionError(connection->service());
+
   // Remove any requests from the client that resulted in a call to the window
   // manager and we haven't gotten a response back yet.
   std::set<uint32_t> to_remove;
@@ -139,10 +144,10 @@
   ClientConnection* client_connection =
       delegate_->CreateClientConnectionForEmbedAtWindow(
           this, GetProxy(&service_ptr), creator_id, window_id, policy_bitmask,
-          client.Pass());
+          std::move(client));
   AddConnection(client_connection);
   client_connection->service()->Init(client_connection->client(),
-                                     service_ptr.Pass());
+                                     std::move(service_ptr));
   OnConnectionMessagedClient(client_connection->service()->id());
 
   return client_connection->service();
@@ -201,7 +206,7 @@
 
   mojom::ViewportMetricsPtr metrics = mojom::ViewportMetrics::New();
   metrics->size_in_pixels = mojo::Size::New();
-  return metrics.Pass();
+  return metrics;
 }
 
 const WindowTreeImpl* ConnectionManager::GetConnectionWithRoot(
diff --git a/components/mus/ws/display_manager.cc b/components/mus/ws/display_manager.cc
index d62c488a..3aeafaed 100644
--- a/components/mus/ws/display_manager.cc
+++ b/components/mus/ws/display_manager.cc
@@ -270,8 +270,8 @@
   frame_pending_ = true;
   if (top_level_display_client_) {
     top_level_display_client_->SubmitCompositorFrame(
-        frame.Pass(), base::Bind(&DefaultDisplayManager::DidDraw,
-                                 weak_factory_.GetWeakPtr()));
+        std::move(frame), base::Bind(&DefaultDisplayManager::DidDraw,
+                                     weak_factory_.GetWeakPtr()));
   }
   dirty_rect_ = gfx::Rect();
 }
@@ -325,11 +325,11 @@
 
   scoped_ptr<cc::DelegatedFrameData> frame_data(new cc::DelegatedFrameData);
   frame_data->device_scale_factor = metrics_.device_pixel_ratio;
-  frame_data->render_pass_list.push_back(render_pass.Pass());
+  frame_data->render_pass_list.push_back(std::move(render_pass));
 
   scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
-  frame->delegated_frame_data = frame_data.Pass();
-  return frame.Pass();
+  frame->delegated_frame_data = std::move(frame_data);
+  return frame;
 }
 
 void DefaultDisplayManager::OnBoundsChanged(const gfx::Rect& new_bounds) {
@@ -342,8 +342,7 @@
 }
 
 void DefaultDisplayManager::DispatchEvent(ui::Event* event) {
-  mojom::EventPtr mojo_event(mojom::Event::From(*event));
-  delegate_->OnEvent(mojo_event.Pass());
+  delegate_->OnEvent(*event);
 
   switch (event->type()) {
     case ui::ET_MOUSE_PRESSED:
@@ -375,17 +374,10 @@
     ui::KeyEvent char_event(key_press_event->GetCharacter(),
                             key_press_event->key_code(),
                             key_press_event->flags());
-
     DCHECK_EQ(key_press_event->GetCharacter(), char_event.GetCharacter());
     DCHECK_EQ(key_press_event->key_code(), char_event.key_code());
     DCHECK_EQ(key_press_event->flags(), char_event.flags());
-
-    char_event.SetExtendedKeyEventData(
-        make_scoped_ptr(new mojo::MojoExtendedKeyEventData(
-            key_press_event->GetLocatedWindowsKeyboardCode(),
-            key_press_event->GetText(), key_press_event->GetUnmodifiedText())));
-
-    delegate_->OnEvent(mojom::Event::From(char_event));
+    delegate_->OnEvent(char_event);
   }
 #endif
 }
diff --git a/components/mus/ws/display_manager_delegate.h b/components/mus/ws/display_manager_delegate.h
index ba4652c..228801f 100644
--- a/components/mus/ws/display_manager_delegate.h
+++ b/components/mus/ws/display_manager_delegate.h
@@ -12,6 +12,10 @@
 struct SurfaceId;
 }
 
+namespace ui {
+class Event;
+}
+
 namespace mus {
 
 namespace ws {
@@ -30,7 +34,7 @@
   virtual void OnDisplayClosed() = 0;
 
   // Called when an event arrives.
-  virtual void OnEvent(mojom::EventPtr event) = 0;
+  virtual void OnEvent(const ui::Event& event) = 0;
 
   // Signals that the metrics of this display's viewport has changed.
   virtual void OnViewportMetricsChanged(
diff --git a/components/mus/ws/event_dispatcher.cc b/components/mus/ws/event_dispatcher.cc
index 8da8c8a..7b6c2c58 100644
--- a/components/mus/ws/event_dispatcher.cc
+++ b/components/mus/ws/event_dispatcher.cc
@@ -203,18 +203,18 @@
       !event->key_data->is_char) {
     uint32_t accelerator = 0u;
     if (FindAccelerator(*event, &accelerator)) {
-      delegate_->OnAccelerator(accelerator, event.Pass());
+      delegate_->OnAccelerator(accelerator, std::move(event));
       return;
     }
   }
 
   if (event->key_data) {
-    ProcessKeyEvent(event.Pass());
+    ProcessKeyEvent(std::move(event));
     return;
   }
 
   if (event->pointer_data.get()) {
-    ProcessPointerEvent(event.Pass());
+    ProcessPointerEvent(std::move(event));
     return;
   }
 
@@ -225,7 +225,8 @@
   ServerWindow* focused_window =
       delegate_->GetFocusedWindowForEventDispatcher();
   if (focused_window)
-    delegate_->DispatchInputEventToWindow(focused_window, false, event.Pass());
+    delegate_->DispatchInputEventToWindow(focused_window, false,
+                                          std::move(event));
 }
 
 void EventDispatcher::ProcessPointerEvent(mojom::EventPtr event) {
@@ -247,10 +248,12 @@
       gfx::Point location(EventLocationToPoint(*event));
       pointer_target.window =
           FindDeepestVisibleWindowForEvents(root_, surface_id_, &location);
+      pointer_target.in_nonclient_area =
+          IsLocationInNonclientArea(pointer_target.window, location);
     }
     if (is_mouse_event && !mouse_button_down_)
       mouse_cursor_source_window_ = pointer_target.window;
-    DispatchToPointerTarget(pointer_target, event.Pass());
+    DispatchToPointerTarget(pointer_target, std::move(event));
     return;
   }
 
@@ -298,7 +301,7 @@
         FindDeepestVisibleWindowForEvents(root_, surface_id_, &location);
   }
 
-  DispatchToPointerTarget(pointer_targets_[pointer_id], event.Pass());
+  DispatchToPointerTarget(pointer_targets_[pointer_id], std::move(event));
 
   if (should_reset_target) {
     ServerWindow* target = pointer_targets_[pointer_id].window;
@@ -319,7 +322,7 @@
   event->pointer_data->location->x = location.x();
   event->pointer_data->location->y = location.y();
   delegate_->DispatchInputEventToWindow(target.window, target.in_nonclient_area,
-                                        event.Pass());
+                                        std::move(event));
 }
 
 void EventDispatcher::CancelPointerEventsToTarget(ServerWindow* window) {
diff --git a/components/mus/ws/event_dispatcher_unittest.cc b/components/mus/ws/event_dispatcher_unittest.cc
index 010a017b..aec3a69 100644
--- a/components/mus/ws/event_dispatcher_unittest.cc
+++ b/components/mus/ws/event_dispatcher_unittest.cc
@@ -28,7 +28,7 @@
   ~TestEventDispatcherDelegate() override {}
 
   mojom::EventPtr GetAndClearLastDispatchedEvent() {
-    return last_dispatched_event_.Pass();
+    return std::move(last_dispatched_event_);
   }
 
   uint32_t GetAndClearLastAccelerator() {
@@ -72,7 +72,7 @@
                                   bool in_nonclient_area,
                                   mojom::EventPtr event) override {
     last_target_ = target;
-    last_dispatched_event_ = event.Pass();
+    last_dispatched_event_ = std::move(event);
     last_in_nonclient_area_ = in_nonclient_area;
   }
 
@@ -172,34 +172,34 @@
   uint32_t accelerator_1 = 1;
   mojom::EventMatcherPtr matcher = mus::CreateKeyMatcher(
       mus::mojom::KEYBOARD_CODE_W, mus::mojom::EVENT_FLAGS_CONTROL_DOWN);
-  EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_1, matcher.Pass()));
+  EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_1, std::move(matcher)));
 
   uint32_t accelerator_2 = 2;
   matcher = mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_N,
                                   mus::mojom::EVENT_FLAGS_NONE);
-  EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_2, matcher.Pass()));
+  EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_2, std::move(matcher)));
 
   // Attempting to add a new accelerator with the same id should fail.
   matcher = mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_T,
                                   mus::mojom::EVENT_FLAGS_NONE);
-  EXPECT_FALSE(dispatcher.AddAccelerator(accelerator_2, matcher.Pass()));
+  EXPECT_FALSE(dispatcher.AddAccelerator(accelerator_2, std::move(matcher)));
 
   // Adding the accelerator with the same id should succeed once the existing
   // accelerator is removed.
   dispatcher.RemoveAccelerator(accelerator_2);
   matcher = mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_T,
                                   mus::mojom::EVENT_FLAGS_NONE);
-  EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_2, matcher.Pass()));
+  EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_2, std::move(matcher)));
 
   // Attempting to add an accelerator with the same matcher should fail.
   uint32_t accelerator_3 = 3;
   matcher = mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_T,
                                   mus::mojom::EVENT_FLAGS_NONE);
-  EXPECT_FALSE(dispatcher.AddAccelerator(accelerator_3, matcher.Pass()));
+  EXPECT_FALSE(dispatcher.AddAccelerator(accelerator_3, std::move(matcher)));
 
   matcher = mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_T,
                                   mus::mojom::EVENT_FLAGS_CONTROL_DOWN);
-  EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_3, matcher.Pass()));
+  EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_3, std::move(matcher)));
 }
 
 TEST(EventDispatcherTest, EventMatching) {
@@ -212,7 +212,7 @@
   mojom::EventMatcherPtr matcher = mus::CreateKeyMatcher(
       mus::mojom::KEYBOARD_CODE_W, mus::mojom::EVENT_FLAGS_CONTROL_DOWN);
   uint32_t accelerator_1 = 1;
-  dispatcher.AddAccelerator(accelerator_1, matcher.Pass());
+  dispatcher.AddAccelerator(accelerator_1, std::move(matcher));
 
   ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_CONTROL_DOWN);
   dispatcher.OnEvent(mojom::Event::From(key));
@@ -234,7 +234,7 @@
   uint32_t accelerator_2 = 2;
   matcher = mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_W,
                                   mus::mojom::EVENT_FLAGS_NONE);
-  dispatcher.AddAccelerator(accelerator_2, matcher.Pass());
+  dispatcher.AddAccelerator(accelerator_2, std::move(matcher));
   dispatcher.OnEvent(mojom::Event::From(key));
   EXPECT_EQ(accelerator_2,
             event_dispatcher_delegate.GetAndClearLastAccelerator());
diff --git a/components/mus/ws/forwarding_window_manager.cc b/components/mus/ws/forwarding_window_manager.cc
index 6b27432..7aad498d 100644
--- a/components/mus/ws/forwarding_window_manager.cc
+++ b/components/mus/ws/forwarding_window_manager.cc
@@ -25,7 +25,8 @@
 void ForwardingWindowManager::OpenWindow(
     mus::mojom::WindowTreeClientPtr client,
     mojo::Map<mojo::String, mojo::Array<uint8_t>> properties) {
-  GetActiveWindowManager()->OpenWindow(client.Pass(), properties.Pass());
+  GetActiveWindowManager()->OpenWindow(std::move(client),
+                                       std::move(properties));
 }
 
 void ForwardingWindowManager::GetConfig(const GetConfigCallback& callback) {
diff --git a/components/mus/ws/server_window.cc b/components/mus/ws/server_window.cc
index c0bcffaf..407d698 100644
--- a/components/mus/ws/server_window.cc
+++ b/components/mus/ws/server_window.cc
@@ -75,8 +75,8 @@
 void ServerWindow::CreateSurface(mojom::SurfaceType surface_type,
                                  mojo::InterfaceRequest<mojom::Surface> request,
                                  mojom::SurfaceClientPtr client) {
-  GetOrCreateSurfaceManager()->CreateSurface(surface_type, request.Pass(),
-                                             client.Pass());
+  GetOrCreateSurfaceManager()->CreateSurface(surface_type, std::move(request),
+                                             std::move(client));
 }
 
 void ServerWindow::Add(ServerWindow* child) {
diff --git a/components/mus/ws/server_window_surface.cc b/components/mus/ws/server_window_surface.cc
index 0ee1a52b..ea97b39c 100644
--- a/components/mus/ws/server_window_surface.cc
+++ b/components/mus/ws/server_window_surface.cc
@@ -37,8 +37,8 @@
                            ->GetSurfacesState()
                            ->manager(),
                        this),
-      client_(client.Pass()),
-      binding_(this, request.Pass()) {
+      client_(std::move(client)),
+      binding_(this, std::move(request)) {
   surface_factory_.Create(surface_id_);
 }
 
diff --git a/components/mus/ws/server_window_surface_manager.cc b/components/mus/ws/server_window_surface_manager.cc
index 9b3962ec..0661209 100644
--- a/components/mus/ws/server_window_surface_manager.cc
+++ b/components/mus/ws/server_window_surface_manager.cc
@@ -35,7 +35,7 @@
     mojo::InterfaceRequest<mojom::Surface> request,
     mojom::SurfaceClientPtr client) {
   type_to_surface_map_[surface_type] = make_scoped_ptr(new ServerWindowSurface(
-      this, surface_type, request.Pass(), client.Pass()));
+      this, surface_type, std::move(request), std::move(client)));
 }
 
 ServerWindowSurface* ServerWindowSurfaceManager::GetDefaultSurface() {
diff --git a/components/mus/ws/window_manager_client_apptest.cc b/components/mus/ws/window_manager_client_apptest.cc
index 79e6730..0d88e816 100644
--- a/components/mus/ws/window_manager_client_apptest.cc
+++ b/components/mus/ws/window_manager_client_apptest.cc
@@ -244,7 +244,7 @@
   ConnectToApplicationAndGetWindowServerClient() {
     mus::mojom::WindowTreeClientPtr client;
     application_impl()->ConnectToService(application_impl()->url(), &client);
-    return client.Pass();
+    return client;
   }
 
   // WindowServerTestBase:
diff --git a/components/mus/ws/window_tree_apptest.cc b/components/mus/ws/window_tree_apptest.cc
index d62f95b..92beb78 100644
--- a/components/mus/ws/window_tree_apptest.cc
+++ b/components/mus/ws/window_tree_apptest.cc
@@ -70,7 +70,8 @@
   {
     mojom::WindowTreeClientPtr client;
     app->ConnectToService(url.get(), &client);
-    ws->Embed(root_id, client.Pass(), mojom::WindowTree::ACCESS_POLICY_DEFAULT,
+    ws->Embed(root_id, std::move(client),
+              mojom::WindowTree::ACCESS_POLICY_DEFAULT,
               base::Bind(&EmbedCallbackImpl, &run_loop, &result));
   }
   run_loop.Run();
@@ -81,7 +82,8 @@
   bool result = false;
   base::RunLoop run_loop;
   {
-    ws->Embed(root_id, client.Pass(), mojom::WindowTree::ACCESS_POLICY_DEFAULT,
+    ws->Embed(root_id, std::move(client),
+              mojom::WindowTree::ACCESS_POLICY_DEFAULT,
               base::Bind(&EmbedCallbackImpl, &run_loop, &result));
   }
   run_loop.Run();
@@ -130,7 +132,7 @@
   }
 
   void Bind(mojo::InterfaceRequest<mojom::WindowTreeClient> request) {
-    binding_.Bind(request.Pass());
+    binding_.Bind(std::move(request));
   }
 
   mojom::WindowTree* tree() { return tree_.get(); }
@@ -214,7 +216,7 @@
   Id NewWindowWithCompleteId(Id id) {
     mojo::Map<mojo::String, mojo::Array<uint8_t>> properties;
     const uint32_t change_id = GetAndAdvanceChangeId();
-    tree()->NewWindow(change_id, id, properties.Pass());
+    tree()->NewWindow(change_id, id, std::move(properties));
     return WaitForChangeCompleted(change_id) ? id : 0;
   }
 
@@ -227,7 +229,7 @@
     if (data)
       mojo_data = Array<uint8_t>::From(*data);
     const uint32_t change_id = GetAndAdvanceChangeId();
-    tree()->SetWindowProperty(change_id, window_id, name, mojo_data.Pass());
+    tree()->SetWindowProperty(change_id, window_id, name, std::move(mojo_data));
     return WaitForChangeCompleted(change_id);
   }
 
@@ -268,9 +270,9 @@
                Id focused_window_id,
                uint32_t access_policy) override {
     // TODO(sky): add coverage of |focused_window_id|.
-    tree_ = tree.Pass();
+    tree_ = std::move(tree);
     connection_id_ = connection_id;
-    tracker()->OnEmbed(connection_id, root.Pass());
+    tracker()->OnEmbed(connection_id, std::move(root));
     if (embed_run_loop_)
       embed_run_loop_->Quit();
   }
@@ -286,8 +288,8 @@
     // it is ignored.
     if (window_id == root_window_id_)
       return;
-    tracker()->OnWindowBoundsChanged(window_id, old_bounds.Pass(),
-                                     new_bounds.Pass());
+    tracker()->OnWindowBoundsChanged(window_id, std::move(old_bounds),
+                                     std::move(new_bounds));
   }
   void OnClientAreaChanged(
       uint32_t window_id,
@@ -311,7 +313,7 @@
                                 Id old_parent,
                                 Array<WindowDataPtr> windows) override {
     tracker()->OnWindowHierarchyChanged(window, new_parent, old_parent,
-                                        windows.Pass());
+                                        std::move(windows));
   }
   void OnWindowReordered(Id window_id,
                          Id relative_window_id,
@@ -336,7 +338,7 @@
   void OnWindowSharedPropertyChanged(uint32_t window,
                                      const String& name,
                                      Array<uint8_t> new_data) override {
-    tracker_.OnWindowSharedPropertyChanged(window, name, new_data.Pass());
+    tracker_.OnWindowSharedPropertyChanged(window, name, std::move(new_data));
   }
   // TODO(sky): add testing coverage.
   void OnWindowFocused(uint32_t focused_window_id) override {}
@@ -398,7 +400,7 @@
       run_loop_->Run();
       run_loop_.reset();
     }
-    return client_impl_.Pass();
+    return std::move(client_impl_);
   }
 
  private:
@@ -406,7 +408,7 @@
   void Create(ApplicationConnection* connection,
               InterfaceRequest<WindowTreeClient> request) override {
     client_impl_.reset(new TestWindowTreeClientImpl(app_));
-    client_impl_->Bind(request.Pass());
+    client_impl_->Bind(std::move(request));
     if (run_loop_.get())
       run_loop_->Quit();
   }
@@ -516,7 +518,7 @@
               SingleChangeToDescription(*client->tracker()->changes()));
     if (connection_id)
       *connection_id = (*client->tracker()->changes())[0].connection_id;
-    return client.Pass();
+    return client;
   }
 
   // ApplicationTestBase:
@@ -534,7 +536,7 @@
 
     factory->CreateWindowTreeHost(GetProxy(&host_),
                                   mojom::WindowTreeHostClientPtr(),
-                                  tree_client_ptr.Pass(), nullptr);
+                                  std::move(tree_client_ptr), nullptr);
 
     // Next we should get an embed call on the "window manager" client.
     ws_client1_->WaitForIncomingMethodCall();
@@ -1635,8 +1637,8 @@
   TestWindowTreeClientImpl client2(application_impl());
   mojom::WindowTreeClientPtr client2_ptr;
   mojo::Binding<WindowTreeClient> client2_binding(&client2, &client2_ptr);
-  ASSERT_TRUE(
-      Embed(ws1(), BuildWindowId(connection_id_1(), 1), client2_ptr.Pass()));
+  ASSERT_TRUE(Embed(ws1(), BuildWindowId(connection_id_1(), 1),
+                    std::move(client2_ptr)));
   client2.WaitForOnEmbed();
   EXPECT_EQ("OnEmbed",
             SingleChangeToDescription(*client2.tracker()->changes()));
diff --git a/components/mus/ws/window_tree_host_connection.cc b/components/mus/ws/window_tree_host_connection.cc
index 638b4eb..f488fc4 100644
--- a/components/mus/ws/window_tree_host_connection.cc
+++ b/components/mus/ws/window_tree_host_connection.cc
@@ -14,7 +14,7 @@
 WindowTreeHostConnection::WindowTreeHostConnection(
     scoped_ptr<WindowTreeHostImpl> host_impl,
     ConnectionManager* manager)
-    : host_(host_impl.Pass()),
+    : host_(std::move(host_impl)),
       tree_(nullptr),
       connection_manager_(manager),
       connection_closed_(false) {}
@@ -53,9 +53,9 @@
     scoped_ptr<WindowTreeHostImpl> host_impl,
     mojom::WindowTreeClientPtr client,
     ConnectionManager* manager)
-    : WindowTreeHostConnection(host_impl.Pass(), manager),
-      binding_(window_tree_host(), request.Pass()),
-      client_(client.Pass()) {}
+    : WindowTreeHostConnection(std::move(host_impl), manager),
+      binding_(window_tree_host(), std::move(request)),
+      client_(std::move(client)) {}
 
 WindowTreeHostConnectionImpl::~WindowTreeHostConnectionImpl() {}
 
@@ -63,7 +63,7 @@
   connection_manager()->AddHost(this);
   set_window_tree(connection_manager()->EmbedAtWindow(
       kInvalidConnectionId, window_tree_host()->root_window()->id(),
-      mojom::WindowTree::ACCESS_POLICY_EMBED_ROOT, client_.Pass()));
+      mojom::WindowTree::ACCESS_POLICY_EMBED_ROOT, std::move(client_)));
 }
 
 }  // namespace ws
diff --git a/components/mus/ws/window_tree_host_impl.cc b/components/mus/ws/window_tree_host_impl.cc
index 0c194d2..7478ab3e 100644
--- a/components/mus/ws/window_tree_host_impl.cc
+++ b/components/mus/ws/window_tree_host_impl.cc
@@ -15,6 +15,7 @@
 #include "components/mus/ws/window_tree_impl.h"
 #include "mojo/common/common_type_converters.h"
 #include "mojo/converters/geometry/geometry_type_converters.h"
+#include "mojo/converters/input_events/input_events_type_converters.h"
 
 namespace mus {
 namespace ws {
@@ -28,6 +29,28 @@
 #endif
 }
 
+bool EventsCanBeCoalesced(const mojom::Event& one, const mojom::Event& two) {
+  if (one.action != two.action || one.flags != two.flags)
+    return false;
+  // TODO(sad): wheel events can also be merged.
+  if (one.action != mojom::EVENT_TYPE_POINTER_MOVE)
+    return false;
+  DCHECK(one.pointer_data);
+  DCHECK(two.pointer_data);
+  if (one.pointer_data->kind != two.pointer_data->kind ||
+      one.pointer_data->pointer_id != two.pointer_data->pointer_id)
+    return false;
+
+  return true;
+}
+
+mojom::EventPtr CoalesceEvents(mojom::EventPtr first, mojom::EventPtr second) {
+  DCHECK_EQ(first->action, mojom::EVENT_TYPE_POINTER_MOVE)
+      << " Non-move events cannot be merged yet.";
+  // For mouse moves, the new event just replaces the old event.
+  return second;
+}
+
 }  // namespace
 
 WindowTreeHostImpl::WindowTreeHostImpl(
@@ -39,11 +62,11 @@
     mojom::WindowManagerPtr window_manager)
     : delegate_(nullptr),
       connection_manager_(connection_manager),
-      client_(client.Pass()),
+      client_(std::move(client)),
       event_dispatcher_(this),
       display_manager_(
           DisplayManager::Create(app_impl, gpu_state, surfaces_state)),
-      window_manager_(window_manager.Pass()),
+      window_manager_(std::move(window_manager)),
       tree_awaiting_input_ack_(nullptr),
       last_cursor_(0) {
   display_manager_->Init(this);
@@ -133,6 +156,13 @@
   display_manager_->SetImeVisibility(visible);
 }
 
+void WindowTreeHostImpl::OnWindowTreeConnectionError(WindowTreeImpl* tree) {
+  if (tree_awaiting_input_ack_ != tree)
+    return;
+  // The WindowTree is dying. So it's not going to ack the event.
+  OnEventAck(tree_awaiting_input_ack_);
+}
+
 void WindowTreeHostImpl::OnCursorUpdated(ServerWindow* window) {
   if (window == event_dispatcher_.mouse_cursor_source_window())
     UpdateNativeCursor(window->cursor());
@@ -158,7 +188,7 @@
     uint32_t id,
     mojom::EventMatcherPtr event_matcher,
     const AddAcceleratorCallback& callback) {
-  bool success = event_dispatcher_.AddAccelerator(id, event_matcher.Pass());
+  bool success = event_dispatcher_.AddAccelerator(id, std::move(event_matcher));
   callback.Run(success);
 }
 
@@ -204,7 +234,7 @@
   // can destroy the corresponding WindowTreeHostConnection, and |this|. So
   // setting it to nullptr afterwards in reset() ends up writing on free'd
   // memory. So transfer over to a local scoped_ptr<> before destroying it.
-  scoped_ptr<DisplayManager> temp = display_manager_.Pass();
+  scoped_ptr<DisplayManager> temp = std::move(display_manager_);
 }
 
 void WindowTreeHostImpl::OnEventAck(mojom::WindowTree* tree) {
@@ -227,9 +257,9 @@
 void WindowTreeHostImpl::DispatchNextEventFromQueue() {
   if (event_queue_.empty())
     return;
-  mojom::EventPtr next_event = event_queue_.front().Pass();
+  mojom::EventPtr next_event = std::move(event_queue_.front());
   event_queue_.pop();
-  event_dispatcher_.OnEvent(next_event.Pass());
+  event_dispatcher_.OnEvent(std::move(next_event));
 }
 
 void WindowTreeHostImpl::UpdateNativeCursor(int32_t cursor_id) {
@@ -243,15 +273,21 @@
   return root_.get();
 }
 
-void WindowTreeHostImpl::OnEvent(mojom::EventPtr event) {
+void WindowTreeHostImpl::OnEvent(const ui::Event& event) {
+  mojom::EventPtr mojo_event(mojom::Event::From(event));
   // If this is still waiting for an ack from a previously sent event, then
   // queue up the event to be dispatched once the ack is received.
   if (event_ack_timer_.IsRunning()) {
-    // TODO(sad): Coalesce if possible.
-    event_queue_.push(event.Pass());
+    if (!event_queue_.empty() &&
+        EventsCanBeCoalesced(*event_queue_.back(), *mojo_event)) {
+      event_queue_.back() =
+          CoalesceEvents(std::move(event_queue_.back()), std::move(mojo_event));
+      return;
+    }
+    event_queue_.push(std::move(mojo_event));
     return;
   }
-  event_dispatcher_.OnEvent(event.Pass());
+  event_dispatcher_.OnEvent(std::move(mojo_event));
 }
 
 void WindowTreeHostImpl::OnDisplayClosed() {
@@ -372,7 +408,7 @@
 
 void WindowTreeHostImpl::OnAccelerator(uint32_t accelerator_id,
                                        mojom::EventPtr event) {
-  client()->OnAccelerator(accelerator_id, event.Pass());
+  client()->OnAccelerator(accelerator_id, std::move(event));
 }
 
 void WindowTreeHostImpl::SetFocusedWindowFromEventDispatcher(
@@ -408,7 +444,7 @@
     connection = connection_manager_->GetConnection(target->id().connection_id);
   }
   tree_awaiting_input_ack_ = connection;
-  connection->DispatchInputEvent(target, event.Pass());
+  connection->DispatchInputEvent(target, std::move(event));
 
   // TOOD(sad): Adjust this delay, possibly make this dynamic.
   const base::TimeDelta max_delay = base::debug::BeingDebugged()
diff --git a/components/mus/ws/window_tree_host_impl.h b/components/mus/ws/window_tree_host_impl.h
index 429ef04..a73b837 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 just before |tree| is destroyed after its connection encounters an
+  // error.
+  void OnWindowTreeConnectionError(WindowTreeImpl* tree);
+
   // 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);
@@ -131,7 +135,7 @@
 
   // DisplayManagerDelegate:
   ServerWindow* GetRootWindow() override;
-  void OnEvent(mojom::EventPtr event) override;
+  void OnEvent(const ui::Event& event) override;
   void OnDisplayClosed() override;
   void OnViewportMetricsChanged(
       const mojom::ViewportMetrics& old_metrics,
diff --git a/components/mus/ws/window_tree_impl.cc b/components/mus/ws/window_tree_impl.cc
index b58cc5b..568cdc8 100644
--- a/components/mus/ws/window_tree_impl.cc
+++ b/components/mus/ws/window_tree_impl.cc
@@ -11,6 +11,7 @@
 #include "components/mus/ws/display_manager.h"
 #include "components/mus/ws/operation.h"
 #include "components/mus/ws/server_window.h"
+#include "components/mus/ws/server_window_observer.h"
 #include "components/mus/ws/window_manager_access_policy.h"
 #include "components/mus/ws/window_tree_host_impl.h"
 #include "mojo/converters/geometry/geometry_type_converters.h"
@@ -29,6 +30,34 @@
 
 namespace ws {
 
+class TargetedEvent : public ServerWindowObserver {
+ public:
+  TargetedEvent(ServerWindow* target, mojom::EventPtr event)
+      : target_(target), event_(std::move(event)) {
+    target_->AddObserver(this);
+  }
+  ~TargetedEvent() override {
+    if (target_)
+      target_->RemoveObserver(this);
+  }
+
+  ServerWindow* target() { return target_; }
+  mojom::EventPtr event() { return std::move(event_); }
+
+ private:
+  // ServerWindowObserver:
+  void OnWindowDestroyed(ServerWindow* window) override {
+    DCHECK_EQ(target_, window);
+    target_->RemoveObserver(this);
+    target_ = nullptr;
+  }
+
+  ServerWindow* target_;
+  mojom::EventPtr event_;
+
+  DISALLOW_COPY_AND_ASSIGN(TargetedEvent);
+};
+
 WindowTreeImpl::WindowTreeImpl(ConnectionManager* connection_manager,
                                ConnectionSpecificId creator_id,
                                const WindowId& root_id,
@@ -73,7 +102,7 @@
   const Id focused_window_transport_id(WindowIdToTransportId(
       focused_window ? focused_window->id() : WindowId()));
 
-  client->OnEmbed(id_, WindowToWindowData(to_send.front()), tree.Pass(),
+  client->OnEmbed(id_, WindowToWindowData(to_send.front()), std::move(tree),
                   focused_window_transport_id,
                   is_embed_root_ ? WindowTree::ACCESS_POLICY_EMBED_ROOT
                                  : WindowTree::ACCESS_POLICY_DEFAULT);
@@ -190,7 +219,7 @@
     return false;
   PrepareForEmbed(window_id);
   WindowTreeImpl* new_connection = connection_manager_->EmbedAtWindow(
-      id_, window_id, policy_bitmask, client.Pass());
+      id_, window_id, policy_bitmask, std::move(client));
   if (is_embed_root_)
     *connection_id = new_connection->id();
   return true;
@@ -198,14 +227,25 @@
 
 void WindowTreeImpl::DispatchInputEvent(ServerWindow* target,
                                         mojom::EventPtr event) {
-  DCHECK_EQ(0u, event_ack_id_);
-  // We do not want to create a sequential id for each event, because that can
-  // leak some information to the client. So instead, manufacture the id from
-  // the event pointer.
-  event_ack_id_ =
-      0x1000000 | (reinterpret_cast<uintptr_t>(event.get()) & 0xffffff);
-  client()->OnWindowInputEvent(
-      event_ack_id_, WindowIdToTransportId(target->id()), event.Pass());
+  if (event_ack_id_) {
+    // This is currently waiting for an event ack. Add it to the queue.
+    event_queue_.push(
+        make_scoped_ptr(new TargetedEvent(target, std::move(event))));
+    // TODO(sad): If the |event_queue_| grows too large, then this should notify
+    // WindowTreeHostImpl, so that it can stop sending events.
+    return;
+  }
+
+  // If there are events in the queue, then store this new event in the queue,
+  // and dispatch the latest event from the queue instead that still has a live
+  // target.
+  if (!event_queue_.empty()) {
+    event_queue_.push(
+        make_scoped_ptr(new TargetedEvent(target, std::move(event))));
+    return;
+  }
+
+  DispatchInputEventImpl(target, std::move(event));
 }
 
 void WindowTreeImpl::ProcessWindowBoundsChanged(const ServerWindow* window,
@@ -269,7 +309,7 @@
     data = Array<uint8_t>::From(*new_data);
 
   client()->OnWindowSharedPropertyChanged(WindowIdToTransportId(window->id()),
-                                          String(name), data.Pass());
+                                          String(name), std::move(data));
 }
 
 void WindowTreeImpl::ProcessWindowHierarchyChanged(
@@ -518,8 +558,8 @@
     const std::vector<const ServerWindow*>& windows) {
   Array<mojom::WindowDataPtr> array(windows.size());
   for (size_t i = 0; i < windows.size(); ++i)
-    array[i] = WindowToWindowData(windows[i]).Pass();
-  return array.Pass();
+    array[i] = WindowToWindowData(windows[i]);
+  return array;
 }
 
 mojom::WindowDataPtr WindowTreeImpl::WindowToWindowData(
@@ -541,7 +581,7 @@
   window_data->drawn = window->IsDrawn();
   window_data->viewport_metrics =
       connection_manager_->GetViewportMetricsForWindow(window);
-  return window_data.Pass();
+  return window_data;
 }
 
 void WindowTreeImpl::GetWindowTreeImpl(
@@ -629,6 +669,18 @@
     window->Remove(children[i]);
 }
 
+void WindowTreeImpl::DispatchInputEventImpl(ServerWindow* target,
+                                            mojom::EventPtr event) {
+  DCHECK(!event_ack_id_);
+  // We do not want to create a sequential id for each event, because that can
+  // leak some information to the client. So instead, manufacture the id from
+  // the event pointer.
+  event_ack_id_ =
+      0x1000000 | (reinterpret_cast<uintptr_t>(event.get()) & 0xffffff);
+  client()->OnWindowInputEvent(
+      event_ack_id_, WindowIdToTransportId(target->id()), std::move(event));
+}
+
 void WindowTreeImpl::NewWindow(
     uint32_t change_id,
     Id transport_window_id,
@@ -734,7 +786,7 @@
     const uint32_t wm_change_id =
         connection_manager_->GenerateWindowManagerChangeId(this, change_id);
     GetHost()->GetWindowTree()->client_->WmSetBounds(wm_change_id, window_id,
-                                                     bounds.Pass());
+                                                     std::move(bounds));
     return;
   }
 
@@ -764,7 +816,7 @@
     const uint32_t wm_change_id =
         connection_manager_->GenerateWindowManagerChangeId(this, change_id);
     GetHost()->GetWindowTree()->client_->WmSetProperty(wm_change_id, window_id,
-                                                       name, value.Pass());
+                                                       name, std::move(value));
     return;
   }
   const bool success = window && access_policy_->CanSetWindowProperties(window);
@@ -790,7 +842,7 @@
       window && access_policy_->CanSetWindowSurface(window, type);
   if (!success)
     return;
-  window->CreateSurface(type, surface.Pass(), client.Pass());
+  window->CreateSurface(type, std::move(surface), std::move(client));
 }
 
 void WindowTreeImpl::SetWindowTextInputState(Id window_id,
@@ -824,6 +876,21 @@
   }
   event_ack_id_ = 0;
   GetHost()->OnEventAck(this);
+
+  if (!event_queue_.empty()) {
+    DCHECK(!event_ack_id_);
+    ServerWindow* target = nullptr;
+    mojom::EventPtr event;
+    do {
+      scoped_ptr<TargetedEvent> targeted_event =
+          std::move(event_queue_.front());
+      event_queue_.pop();
+      target = targeted_event->target();
+      event = targeted_event->event();
+    } while (!event_queue_.empty() && !target);
+    if (target)
+      DispatchInputEventImpl(target, std::move(event));
+  }
 }
 
 void WindowTreeImpl::SetClientArea(
@@ -846,7 +913,7 @@
                            const EmbedCallback& callback) {
   ConnectionSpecificId connection_id = kInvalidConnectionId;
   const bool result = Embed(WindowIdFromTransportId(transport_window_id),
-                            client.Pass(), policy_bitmask, &connection_id);
+                            std::move(client), policy_bitmask, &connection_id);
   callback.Run(result, connection_id);
 }
 
diff --git a/components/mus/ws/window_tree_impl.h b/components/mus/ws/window_tree_impl.h
index 7b1ee906d..a979248 100644
--- a/components/mus/ws/window_tree_impl.h
+++ b/components/mus/ws/window_tree_impl.h
@@ -5,7 +5,7 @@
 #ifndef COMPONENTS_MUS_WS_WINDOW_TREE_IMPL_H_
 #define COMPONENTS_MUS_WS_WINDOW_TREE_IMPL_H_
 
-#include <set>
+#include <queue>
 #include <string>
 #include <vector>
 
@@ -30,6 +30,7 @@
 class AccessPolicy;
 class ConnectionManager;
 class ServerWindow;
+class TargetedEvent;
 class WindowTreeHostImpl;
 
 // An instance of WindowTreeImpl is created for every WindowTree request.
@@ -191,6 +192,8 @@
   void PrepareForEmbed(const WindowId& window_id);
   void RemoveChildrenAsPartOfEmbed(const WindowId& window_id);
 
+  void DispatchInputEventImpl(ServerWindow* target, mojom::EventPtr event);
+
   // Calls OnChangeCompleted() on the client.
   void NotifyChangeCompleted(uint32_t change_id,
                              mojom::WindowManagerErrorCode error_code);
@@ -285,6 +288,8 @@
   uint32_t event_ack_id_;
   bool is_embed_root_;
 
+  std::queue<scoped_ptr<TargetedEvent>> event_queue_;
+
   DISALLOW_COPY_AND_ASSIGN(WindowTreeImpl);
 };
 
diff --git a/components/mus/ws/window_tree_unittest.cc b/components/mus/ws/window_tree_unittest.cc
index 55f578ff..71fd138 100644
--- a/components/mus/ws/window_tree_unittest.cc
+++ b/components/mus/ws/window_tree_unittest.cc
@@ -25,6 +25,8 @@
 #include "mojo/converters/geometry/geometry_type_converters.h"
 #include "mojo/services/network/public/interfaces/url_loader.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event.h"
+#include "ui/events/event_utils.h"
 #include "ui/gfx/geometry/rect.h"
 
 using mojo::Array;
@@ -54,7 +56,7 @@
   TestChangeTracker* tracker() { return &tracker_; }
 
   void Bind(mojo::InterfaceRequest<mojom::WindowTreeClient> request) {
-    binding_.Bind(request.Pass());
+    binding_.Bind(std::move(request));
   }
 
  private:
@@ -65,7 +67,7 @@
                Id focused_window_id,
                uint32_t access_policy) override {
     // TODO(sky): add test coverage of |focused_window_id|.
-    tracker_.OnEmbed(connection_id, root.Pass());
+    tracker_.OnEmbed(connection_id, std::move(root));
   }
   void OnEmbeddedAppDisconnected(uint32_t window) override {
     tracker_.OnEmbeddedAppDisconnected(window);
@@ -74,8 +76,8 @@
   void OnWindowBoundsChanged(uint32_t window,
                              mojo::RectPtr old_bounds,
                              mojo::RectPtr new_bounds) override {
-    tracker_.OnWindowBoundsChanged(window, old_bounds.Pass(),
-                                   new_bounds.Pass());
+    tracker_.OnWindowBoundsChanged(window, std::move(old_bounds),
+                                   std::move(new_bounds));
   }
   void OnClientAreaChanged(
       uint32_t window_id,
@@ -88,15 +90,15 @@
   void OnWindowViewportMetricsChanged(
       mojom::ViewportMetricsPtr old_metrics,
       mojom::ViewportMetricsPtr new_metrics) override {
-    tracker_.OnWindowViewportMetricsChanged(old_metrics.Pass(),
-                                            new_metrics.Pass());
+    tracker_.OnWindowViewportMetricsChanged(std::move(old_metrics),
+                                            std::move(new_metrics));
   }
   void OnWindowHierarchyChanged(uint32_t window,
                                 uint32_t new_parent,
                                 uint32_t old_parent,
                                 Array<WindowDataPtr> windows) override {
     tracker_.OnWindowHierarchyChanged(window, new_parent, old_parent,
-                                      windows.Pass());
+                                      std::move(windows));
   }
   void OnWindowReordered(uint32_t window_id,
                          uint32_t relative_window_id,
@@ -115,12 +117,12 @@
   void OnWindowSharedPropertyChanged(uint32_t window,
                                      const String& name,
                                      Array<uint8_t> new_data) override {
-    tracker_.OnWindowSharedPropertyChanged(window, name, new_data.Pass());
+    tracker_.OnWindowSharedPropertyChanged(window, name, std::move(new_data));
   }
   void OnWindowInputEvent(uint32_t event_id,
                           uint32_t window,
                           EventPtr event) override {
-    tracker_.OnWindowInputEvent(window, event.Pass());
+    tracker_.OnWindowInputEvent(window, std::move(event));
   }
   void OnWindowFocused(uint32_t focused_window_id) override {
     tracker_.OnWindowFocused(focused_window_id);
@@ -151,7 +153,7 @@
 class TestClientConnection : public ClientConnection {
  public:
   explicit TestClientConnection(scoped_ptr<WindowTreeImpl> service_impl)
-      : ClientConnection(service_impl.Pass(), &client_) {}
+      : ClientConnection(std::move(service_impl), &client_) {}
 
   TestWindowTreeClient* client() { return &client_; }
 
@@ -191,7 +193,7 @@
     // Used by ConnectionManager::AddRoot.
     scoped_ptr<WindowTreeImpl> service(new WindowTreeImpl(
         connection_manager, creator_id, root_id, policy_bitmask));
-    last_connection_ = new TestClientConnection(service.Pass());
+    last_connection_ = new TestClientConnection(std::move(service));
     return last_connection_;
   }
 
@@ -206,7 +208,7 @@
  public:
   TestWindowTreeHostConnection(scoped_ptr<WindowTreeHostImpl> host_impl,
                                ConnectionManager* manager)
-      : WindowTreeHostConnection(host_impl.Pass(), manager) {}
+      : WindowTreeHostConnection(std::move(host_impl), manager) {}
   ~TestWindowTreeHostConnection() override {}
 
  private:
@@ -278,56 +280,31 @@
   DISALLOW_COPY_AND_ASSIGN(TestDisplayManagerFactory);
 };
 
-EventPtr CreatePointerDownEvent(int x, int y) {
-  EventPtr event(Event::New());
-  event->action = mus::mojom::EVENT_TYPE_POINTER_DOWN;
-  event->pointer_data = PointerData::New();
-  event->pointer_data->pointer_id = 1u;
-  event->pointer_data->location = LocationData::New();
-  event->pointer_data->location->x = x;
-  event->pointer_data->location->y = y;
-  event->pointer_data->kind = mojom::POINTER_KIND_TOUCH;
-  return event.Pass();
+ui::TouchEvent CreatePointerDownEvent(int x, int y) {
+  return ui::TouchEvent(ui::ET_TOUCH_PRESSED, gfx::Point(x, y), 1,
+                        ui::EventTimeForNow());
 }
 
-EventPtr CreatePointerUpEvent(int x, int y) {
-  EventPtr event(Event::New());
-  event->action = mus::mojom::EVENT_TYPE_POINTER_UP;
-  event->pointer_data = PointerData::New();
-  event->pointer_data->pointer_id = 1u;
-  event->pointer_data->location = LocationData::New();
-  event->pointer_data->location->x = x;
-  event->pointer_data->location->y = y;
-  event->pointer_data->kind = mojom::POINTER_KIND_TOUCH;
-  return event.Pass();
+ui::TouchEvent CreatePointerUpEvent(int x, int y) {
+  return ui::TouchEvent(ui::ET_TOUCH_RELEASED, gfx::Point(x, y), 1,
+                        ui::EventTimeForNow());
 }
 
-EventPtr CreateMouseMoveEvent(int x, int y) {
-  EventPtr event(Event::New());
-  event->action = mus::mojom::EVENT_TYPE_POINTER_MOVE;
-  event->pointer_data = PointerData::New();
-  event->pointer_data->pointer_id = std::numeric_limits<uint32_t>::max();
-  event->pointer_data->location = LocationData::New();
-  event->pointer_data->location->x = x;
-  event->pointer_data->location->y = y;
-  event->pointer_data->kind = mojom::POINTER_KIND_MOUSE;
-  return event.Pass();
+ui::MouseEvent CreateMouseMoveEvent(int x, int y) {
+  return ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(x, y), gfx::Point(x, y),
+                        ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
 }
 
-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();
+ui::MouseEvent CreateMouseDownEvent(int x, int y) {
+  return ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(x, y),
+                        gfx::Point(x, y), ui::EventTimeForNow(),
+                        ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
 }
 
-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();
+ui::MouseEvent CreateMouseUpEvent(int x, int y) {
+  return ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(x, y),
+                        gfx::Point(x, y), ui::EventTimeForNow(),
+                        ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
 }
 
 }  // namespace
@@ -362,8 +339,8 @@
 
   TestWindowTreeHostConnection* host_connection() { return host_connection_; }
 
-  void DispatchEventWithoutAck(mojom::EventPtr event) {
-    host_connection()->window_tree_host()->OnEvent(event.Pass());
+  void DispatchEventWithoutAck(const ui::Event& event) {
+    host_connection()->window_tree_host()->OnEvent(event);
   }
 
   void AckPreviousEvent() {
@@ -372,8 +349,8 @@
         ->tree_awaiting_input_ack_->OnWindowInputEventAck(0);
   }
 
-  void DispatchEventAndAckImmediately(mojom::EventPtr event) {
-    DispatchEventWithoutAck(event.Pass());
+  void DispatchEventAndAckImmediately(const ui::Event& event) {
+    DispatchEventWithoutAck(event);
     AckPreviousEvent();
   }
 
@@ -430,9 +407,9 @@
   mojom::WindowTreeClientPtr client;
   mojo::InterfaceRequest<mojom::WindowTreeClient> client_request =
       GetProxy(&client);
-  wm_client()->Bind(client_request.Pass());
+  wm_client()->Bind(std::move(client_request));
   ConnectionSpecificId connection_id = 0;
-  wm_connection()->Embed(embed_window_id, client.Pass(),
+  wm_connection()->Embed(embed_window_id, std::move(client),
                          mojom::WindowTree::ACCESS_POLICY_DEFAULT,
                          &connection_id);
   WindowTreeImpl* connection1 =
@@ -477,10 +454,9 @@
   mojom::WindowTreeClientPtr client;
   mojo::InterfaceRequest<mojom::WindowTreeClient> client_request =
       GetProxy(&client);
-  wm_client()->Bind(client_request.Pass());
+  wm_client()->Bind(std::move(client_request));
   ConnectionSpecificId connection_id = 0;
-  wm_connection()->Embed(embed_window_id,
-                         client.Pass(),
+  wm_connection()->Embed(embed_window_id, std::move(client),
                          mojom::WindowTree::ACCESS_POLICY_DEFAULT,
                          &connection_id);
   WindowTreeImpl* connection1 =
diff --git a/components/nacl/loader/nacl_helper_linux.cc b/components/nacl/loader/nacl_helper_linux.cc
index 010239a..462cca9 100644
--- a/components/nacl/loader/nacl_helper_linux.cc
+++ b/components/nacl/loader/nacl_helper_linux.cc
@@ -16,6 +16,7 @@
 #include <sys/types.h>
 
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/at_exit.h"
@@ -23,7 +24,6 @@
 #include "base/files/scoped_file.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
 #include "base/message_loop/message_loop.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/posix/global_descriptors.h"
@@ -132,7 +132,7 @@
 }
 
 // Start the NaCl loader in a child created by the NaCl loader Zygote.
-void ChildNaClLoaderInit(ScopedVector<base::ScopedFD> child_fds,
+void ChildNaClLoaderInit(std::vector<base::ScopedFD> child_fds,
                          const NaClLoaderSystemInfo& system_info,
                          bool uses_nonsfi_mode,
                          nacl::NaClSandbox* nacl_sandbox,
@@ -143,25 +143,25 @@
 
   // Ping the PID oracle socket.
   CHECK(content::SendZygoteChildPing(
-      child_fds[content::ZygoteForkDelegate::kPIDOracleFDIndex]->get()));
+      child_fds[content::ZygoteForkDelegate::kPIDOracleFDIndex].get()));
 
   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
       switches::kProcessChannelID, channel_id);
 
   // Save the browser socket and close the rest.
   base::ScopedFD browser_fd(
-      child_fds[content::ZygoteForkDelegate::kBrowserFDIndex]->Pass());
+      std::move(child_fds[content::ZygoteForkDelegate::kBrowserFDIndex]));
   child_fds.clear();
 
-  BecomeNaClLoader(
-      browser_fd.Pass(), system_info, uses_nonsfi_mode, nacl_sandbox);
+  BecomeNaClLoader(std::move(browser_fd), system_info, uses_nonsfi_mode,
+                   nacl_sandbox);
   _exit(1);
 }
 
 // Handle a fork request from the Zygote.
 // Some of this code was lifted from
 // content/browser/zygote_main_linux.cc:ForkWithRealPid()
-bool HandleForkRequest(ScopedVector<base::ScopedFD> child_fds,
+bool HandleForkRequest(std::vector<base::ScopedFD> child_fds,
                        const NaClLoaderSystemInfo& system_info,
                        nacl::NaClSandbox* nacl_sandbox,
                        base::PickleIterator* input_iter,
@@ -207,11 +207,8 @@
       // is fine.
       sandbox::NamespaceSandbox::InstallDefaultTerminationSignalHandlers();
     }
-    ChildNaClLoaderInit(child_fds.Pass(),
-                        system_info,
-                        uses_nonsfi_mode,
-                        nacl_sandbox,
-                        channel_id);
+    ChildNaClLoaderInit(std::move(child_fds), system_info, uses_nonsfi_mode,
+                        nacl_sandbox, channel_id);
     NOTREACHED();
   }
 
@@ -261,7 +258,7 @@
 // Reply to the command on |reply_fds|.
 bool HonorRequestAndReply(int reply_fd,
                           int command_type,
-                          ScopedVector<base::ScopedFD> attached_fds,
+                          std::vector<base::ScopedFD> attached_fds,
                           const NaClLoaderSystemInfo& system_info,
                           nacl::NaClSandbox* nacl_sandbox,
                           base::PickleIterator* input_iter) {
@@ -270,11 +267,9 @@
   // Commands must write anything to send back to |write_pickle|.
   switch (command_type) {
     case nacl::kNaClForkRequest:
-      have_to_reply = HandleForkRequest(attached_fds.Pass(),
-                                        system_info,
-                                        nacl_sandbox,
-                                        input_iter,
-                                        &write_pickle);
+      have_to_reply =
+          HandleForkRequest(std::move(attached_fds), system_info, nacl_sandbox,
+                            input_iter, &write_pickle);
       break;
     case nacl::kNaClGetTerminationStatusRequest:
       have_to_reply =
@@ -300,7 +295,7 @@
 bool HandleZygoteRequest(int zygote_ipc_fd,
                          const NaClLoaderSystemInfo& system_info,
                          nacl::NaClSandbox* nacl_sandbox) {
-  ScopedVector<base::ScopedFD> fds;
+  std::vector<base::ScopedFD> fds;
   char buf[kNaClMaxIPCMessageLength];
   const ssize_t msglen = base::UnixDomainSocket::RecvMsg(zygote_ipc_fd,
       &buf, sizeof(buf), &fds);
@@ -327,12 +322,8 @@
     LOG(ERROR) << "Unable to read command from Zygote";
     return false;
   }
-  return HonorRequestAndReply(zygote_ipc_fd,
-                              command_type,
-                              fds.Pass(),
-                              system_info,
-                              nacl_sandbox,
-                              &read_iter);
+  return HonorRequestAndReply(zygote_ipc_fd, command_type, std::move(fds),
+                              system_info, nacl_sandbox, &read_iter);
 }
 
 #if !defined(OS_NACL_NONSFI)
diff --git a/components/nacl/renderer/plugin/pnacl_translate_thread.cc b/components/nacl/renderer/plugin/pnacl_translate_thread.cc
index c7d64c7..3396a88 100644
--- a/components/nacl/renderer/plugin/pnacl_translate_thread.cc
+++ b/components/nacl/renderer/plugin/pnacl_translate_thread.cc
@@ -7,12 +7,12 @@
 #include <iterator>
 #include <sstream>
 
+#include "base/logging.h"
 #include "components/nacl/renderer/plugin/plugin.h"
 #include "components/nacl/renderer/plugin/plugin_error.h"
 #include "components/nacl/renderer/plugin/srpc_params.h"
 #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/zygote/nacl_fork_delegate_linux.cc b/components/nacl/zygote/nacl_fork_delegate_linux.cc
index ae625643..e05e2ec 100644
--- a/components/nacl/zygote/nacl_fork_delegate_linux.cc
+++ b/components/nacl/zygote/nacl_fork_delegate_linux.cc
@@ -113,7 +113,7 @@
   }
 
   // Then read the remote reply.
-  ScopedVector<base::ScopedFD> received_fds;
+  std::vector<base::ScopedFD> received_fds;
   const ssize_t msg_len =
       base::UnixDomainSocket::RecvMsg(ipc_channel, reply_data_buffer,
                                       reply_data_buffer_size, &received_fds);
diff --git a/components/net_log/chrome_net_log.cc b/components/net_log/chrome_net_log.cc
index b30842d4c..3fa79d4 100644
--- a/components/net_log/chrome_net_log.cc
+++ b/components/net_log/chrome_net_log.cc
@@ -9,6 +9,8 @@
 #include "base/command_line.h"
 #include "base/files/scoped_file.h"
 #include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/sys_info.h"
 #include "base/values.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.h"
 #include "components/net_log/net_log_temp_file.h"
@@ -88,7 +90,11 @@
     dict->SetString("version_mod", channel_string);
     dict->SetString("official", version_info::IsOfficialBuild() ? "official"
                                                                 : "unofficial");
-    dict->SetString("os_type", version_info::GetOSType());
+    std::string os_type = base::StringPrintf(
+        "%s: %s (%s)", base::SysInfo::OperatingSystemName().c_str(),
+        base::SysInfo::OperatingSystemVersion().c_str(),
+        base::SysInfo::OperatingSystemArchitecture().c_str());
+    dict->SetString("os_type", os_type);
     dict->SetString("command_line", command_line_string);
 
     constants_dict->Set("clientInfo", dict);
diff --git a/components/offline_pages.gypi b/components/offline_pages.gypi
index 322f676..33e34ae4 100644
--- a/components/offline_pages.gypi
+++ b/components/offline_pages.gypi
@@ -37,6 +37,23 @@
       ],
     },
     {
+      # GN version: //components/offline_pages:test_support
+      'target_name': 'offline_pages_test_support',
+      'type': 'static_library',
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../testing/gtest.gyp:gtest',
+        '../url/url.gyp:url_lib',
+        'offline_pages',
+      ],
+      'sources': [
+        'offline_pages/offline_page_test_archiver.h',
+        'offline_pages/offline_page_test_archiver.cc',
+        'offline_pages/offline_page_test_store.h',
+        'offline_pages/offline_page_test_store.cc',
+      ],
+    },
+    {
       # Protobuf compiler / generator for the offline page item protocol buffer.
       # GN version: //components/offline_pages/proto
       'target_name': 'offline_pages_proto',
diff --git a/components/offline_pages/BUILD.gn b/components/offline_pages/BUILD.gn
index 2884333..517444bc 100644
--- a/components/offline_pages/BUILD.gn
+++ b/components/offline_pages/BUILD.gn
@@ -36,6 +36,23 @@
   ]
 }
 
+static_library("test_support") {
+  testonly = true
+  sources = [
+    "offline_page_test_archiver.cc",
+    "offline_page_test_archiver.h",
+    "offline_page_test_store.cc",
+    "offline_page_test_store.h",
+  ]
+
+  deps = [
+    ":offline_pages",
+    "//base",
+    "//testing/gtest",
+    "//url",
+  ]
+}
+
 source_set("unit_tests") {
   testonly = true
   sources = [
@@ -45,7 +62,9 @@
 
   deps = [
     ":offline_pages",
+    ":test_support",
     "//base",
+    "//base/test:test_support",
     "//components/bookmarks/browser",
     "//components/leveldb_proto",
     "//components/offline_pages/proto:offline_pages_proto",
diff --git a/components/offline_pages/offline_page_metadata_store_impl.cc b/components/offline_pages/offline_page_metadata_store_impl.cc
index d1b9ce8..ee2fb85 100644
--- a/components/offline_pages/offline_page_metadata_store_impl.cc
+++ b/components/offline_pages/offline_page_metadata_store_impl.cc
@@ -10,7 +10,6 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/sequenced_task_runner.h"
 #include "base/strings/string_number_conversions.h"
@@ -216,8 +215,8 @@
     // Callback is invoked through message loop to avoid improper retry and
     // simplify testing.
     DVLOG(1) << "Offline pages database not available in UpdateEntries.";
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::Bind(callback, false));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  base::Bind(callback, false));
     return;
   }
 
diff --git a/components/offline_pages/offline_page_metadata_store_impl_unittest.cc b/components/offline_pages/offline_page_metadata_store_impl_unittest.cc
index f0f15c4..4965d38 100644
--- a/components/offline_pages/offline_page_metadata_store_impl_unittest.cc
+++ b/components/offline_pages/offline_page_metadata_store_impl_unittest.cc
@@ -8,9 +8,9 @@
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "components/leveldb_proto/proto_database_impl.h"
 #include "components/offline_pages/offline_page_item.h"
 #include "components/offline_pages/proto/offline_pages.pb.h"
@@ -36,7 +36,10 @@
   OfflinePageMetadataStoreImplTest();
   ~OfflinePageMetadataStoreImplTest() override;
 
-  void TearDown() override { message_loop_.RunUntilIdle(); }
+  void TearDown() override {
+    // Wait for all the pieces of the store to delete itself properly.
+    PumpLoop();
+  }
 
   scoped_ptr<OfflinePageMetadataStoreImpl> BuildStore();
   void PumpLoop();
@@ -53,12 +56,15 @@
   std::vector<OfflinePageItem> offline_pages_;
 
   base::ScopedTempDir temp_directory_;
-  base::MessageLoop message_loop_;
-  scoped_ptr<base::RunLoop> run_loop_;
+  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+  base::ThreadTaskRunnerHandle task_runner_handle_;
 };
 
 OfflinePageMetadataStoreImplTest::OfflinePageMetadataStoreImplTest()
-    : last_called_callback_(NONE), last_status_(STATUS_NONE) {
+    : last_called_callback_(NONE),
+      last_status_(STATUS_NONE),
+      task_runner_(new base::TestSimpleTaskRunner),
+      task_runner_handle_(task_runner_) {
   EXPECT_TRUE(temp_directory_.CreateUniqueTempDir());
 }
 
@@ -66,13 +72,13 @@
 }
 
 void OfflinePageMetadataStoreImplTest::PumpLoop() {
-  base::RunLoop().RunUntilIdle();
+  task_runner_->RunUntilIdle();
 }
 
 scoped_ptr<OfflinePageMetadataStoreImpl>
 OfflinePageMetadataStoreImplTest::BuildStore() {
   scoped_ptr<OfflinePageMetadataStoreImpl> store(
-      new OfflinePageMetadataStoreImpl(message_loop_.task_runner(),
+      new OfflinePageMetadataStoreImpl(base::ThreadTaskRunnerHandle::Get(),
                                        temp_directory_.path()));
   store->Load(base::Bind(&OfflinePageMetadataStoreImplTest::LoadCallback,
                          base::Unretained(this)));
diff --git a/components/offline_pages/offline_page_model.cc b/components/offline_pages/offline_page_model.cc
index 60a9b2e4..d0c536a 100644
--- a/components/offline_pages/offline_page_model.cc
+++ b/components/offline_pages/offline_page_model.cc
@@ -170,6 +170,10 @@
   if (iter == offline_pages_.end())
     return;
 
+  // MarkPageAccessed should not be called for a page that is being marked for
+  // deletion.
+  DCHECK(!iter->second.IsMarkedForDeletion());
+
   // Make a copy of the cached item and update it. The cached item should only
   // be updated upon the successful store operation.
   OfflinePageItem offline_page_item = iter->second;
diff --git a/components/offline_pages/offline_page_model_unittest.cc b/components/offline_pages/offline_page_model_unittest.cc
index a2df42e..f1f817b 100644
--- a/components/offline_pages/offline_page_model_unittest.cc
+++ b/components/offline_pages/offline_page_model_unittest.cc
@@ -9,15 +9,15 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "components/bookmarks/browser/bookmark_node.h"
 #include "components/offline_pages/offline_page_item.h"
-#include "components/offline_pages/offline_page_metadata_store.h"
+#include "components/offline_pages/offline_page_test_archiver.h"
+#include "components/offline_pages/offline_page_test_store.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -36,158 +36,12 @@
 const int64 kTestPageBookmarkId3 = 42LL;
 const int64 kTestFileSize = 876543LL;
 
-class OfflinePageTestStore : public OfflinePageMetadataStore {
- public:
-  enum class TestScenario {
-    SUCCESSFUL,
-    WRITE_FAILED,
-    LOAD_FAILED,
-    REMOVE_FAILED,
-  };
-
-  explicit OfflinePageTestStore(
-      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
-  explicit OfflinePageTestStore(const OfflinePageTestStore& other_store);
-  ~OfflinePageTestStore() override;
-
-  // OfflinePageMetadataStore overrides:
-  void Load(const LoadCallback& callback) override;
-  void AddOrUpdateOfflinePage(const OfflinePageItem& offline_page,
-                              const UpdateCallback& callback) override;
-  void RemoveOfflinePages(const std::vector<int64>& bookmark_ids,
-                          const UpdateCallback& callback) override;
-  void Reset(const ResetCallback& callback) override;
-
-  void UpdateLastAccessTime(int64 bookmark_id,
-                            const base::Time& last_access_time);
-
-  const OfflinePageItem& last_saved_page() const { return last_saved_page_; }
-
-  void set_test_scenario(TestScenario scenario) { scenario_ = scenario; };
-
-  const std::vector<OfflinePageItem>& offline_pages() const {
-    return offline_pages_;
-  }
-
- private:
-  OfflinePageItem last_saved_page_;
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-  TestScenario scenario_;
-
-  std::vector<OfflinePageItem> offline_pages_;
-
-  DISALLOW_ASSIGN(OfflinePageTestStore);
-};
-
-OfflinePageTestStore::OfflinePageTestStore(
-    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
-    : task_runner_(task_runner),
-      scenario_(TestScenario::SUCCESSFUL) {
-}
-
-OfflinePageTestStore::OfflinePageTestStore(
-    const OfflinePageTestStore& other_store)
-    : task_runner_(other_store.task_runner_),
-      scenario_(other_store.scenario_),
-      offline_pages_(other_store.offline_pages_) {}
-
-OfflinePageTestStore::~OfflinePageTestStore() {
-}
-
-void OfflinePageTestStore::Load(const LoadCallback& callback) {
-  OfflinePageMetadataStore::LoadStatus load_status;
-  if (scenario_ != TestScenario::LOAD_FAILED) {
-    load_status = OfflinePageMetadataStore::LOAD_SUCCEEDED;
-  } else {
-    load_status = OfflinePageMetadataStore::STORE_LOAD_FAILED;
-    offline_pages_.clear();
-  }
-  task_runner_->PostTask(
-      FROM_HERE, base::Bind(callback, load_status, offline_pages_));
-}
-
-void OfflinePageTestStore::AddOrUpdateOfflinePage(
-    const OfflinePageItem& offline_page, const UpdateCallback& callback) {
-  last_saved_page_ = offline_page;
-  bool result = scenario_ != TestScenario::WRITE_FAILED;
-  if (result) {
-    offline_pages_.push_back(offline_page);
-  }
-  task_runner_->PostTask(FROM_HERE, base::Bind(callback, result));
-}
-
-void OfflinePageTestStore::RemoveOfflinePages(
-    const std::vector<int64>& bookmark_ids,
-    const UpdateCallback& callback) {
-  ASSERT_FALSE(bookmark_ids.empty());
-  bool result = false;
-  if (scenario_ != TestScenario::REMOVE_FAILED) {
-    for (auto iter = offline_pages_.begin();
-         iter != offline_pages_.end(); ++iter) {
-      if (iter->bookmark_id == bookmark_ids[0]) {
-        offline_pages_.erase(iter);
-        result = true;
-        break;
-      }
-    }
-  }
-
-  task_runner_->PostTask(FROM_HERE, base::Bind(callback, result));
-}
-
-void OfflinePageTestStore::Reset(const ResetCallback& callback) {
-  offline_pages_.clear();
-  task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
-}
-
-void OfflinePageTestStore:: UpdateLastAccessTime(
-    int64 bookmark_id, const base::Time& last_access_time) {
-  for (auto& offline_page : offline_pages_) {
-    if (offline_page.bookmark_id == bookmark_id) {
-      offline_page.last_access_time = last_access_time;
-      return;
-    }
-  }
-}
-
 }  // namespace
 
-class OfflinePageModelTest;
-
-class OfflinePageTestArchiver : public OfflinePageArchiver {
- public:
-  OfflinePageTestArchiver(
-      OfflinePageModelTest* test,
-      const GURL& url,
-      ArchiverResult result,
-      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
-  ~OfflinePageTestArchiver() override;
-
-  // OfflinePageArchiver implementation:
-  void CreateArchive(const base::FilePath& archives_dir,
-                     const CreateArchiveCallback& callback) override;
-
-  void CompleteCreateArchive();
-
-  void set_delayed(bool delayed) { delayed_ = delayed; }
-
-  bool create_archive_called() const { return create_archive_called_; }
-
- private:
-  OfflinePageModelTest* test_;  // Outlive OfflinePageTestArchiver.
-  GURL url_;
-  base::FilePath archives_dir_;
-  ArchiverResult result_;
-  bool create_archive_called_;
-  bool delayed_;
-  CreateArchiveCallback callback_;
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-  DISALLOW_COPY_AND_ASSIGN(OfflinePageTestArchiver);
-};
-
 class OfflinePageModelTest
     : public testing::Test,
       public OfflinePageModel::Observer,
+      public OfflinePageTestArchiver::Observer,
       public base::SupportsWeakPtr<OfflinePageModelTest> {
  public:
   OfflinePageModelTest();
@@ -201,6 +55,9 @@
   void OfflinePageModelChanged(OfflinePageModel* model) override;
   void OfflinePageDeleted(int64 bookmark_id) override;
 
+  // OfflinePageTestArchiver::Observer implementation.
+  void SetLastPathCreatedByArchiver(const base::FilePath& file_path) override;
+
   // OfflinePageModel callbacks.
   void OnSavePageDone(SavePageResult result);
   void OnDeletePageDone(DeletePageResult result);
@@ -218,13 +75,11 @@
   void ResetModel();
 
   // Utility methods.
+  // Runs until all of the tasks that are not delayed are gone from the task
+  // queue.
   void PumpLoop();
   void ResetResults();
 
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner() {
-    return message_loop_.task_runner();
-  }
-
   OfflinePageModel* model() { return model_.get(); }
 
   OfflinePageTestStore* GetStore();
@@ -242,12 +97,10 @@
   }
 
   const base::FilePath& last_archiver_path() { return last_archiver_path_; }
-  void set_last_archiver_path(const base::FilePath& last_archiver_path) {
-    last_archiver_path_ = last_archiver_path;
-  }
 
  private:
-  base::MessageLoop message_loop_;
+  scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+  base::ThreadTaskRunnerHandle task_runner_handle_;
   base::ScopedTempDir temp_dir_;
 
   scoped_ptr<OfflinePageModel> model_;
@@ -257,44 +110,10 @@
   int64 last_deleted_bookmark_id_;
 };
 
-OfflinePageTestArchiver::OfflinePageTestArchiver(
-    OfflinePageModelTest* test,
-    const GURL& url,
-    ArchiverResult result,
-    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
-    : test_(test),
-      url_(url),
-      result_(result),
-      create_archive_called_(false),
-      delayed_(false),
-      task_runner_(task_runner) {
-}
-
-OfflinePageTestArchiver::~OfflinePageTestArchiver() {
-  EXPECT_TRUE(create_archive_called_);
-}
-
-void OfflinePageTestArchiver::CreateArchive(
-    const base::FilePath& archives_dir,
-    const CreateArchiveCallback& callback) {
-  create_archive_called_ = true;
-  callback_ = callback;
-  archives_dir_ = archives_dir;
-  if (!delayed_)
-    CompleteCreateArchive();
-}
-
-void OfflinePageTestArchiver::CompleteCreateArchive() {
-  DCHECK(!callback_.is_null());
-  base::FilePath archive_path;
-  ASSERT_TRUE(base::CreateTemporaryFileInDir(archives_dir_, &archive_path));
-  test_->set_last_archiver_path(archive_path);
-  task_runner_->PostTask(FROM_HERE, base::Bind(callback_, this, result_, url_,
-                                               archive_path, kTestFileSize));
-}
-
 OfflinePageModelTest::OfflinePageModelTest()
-    : last_save_result_(SavePageResult::CANCELLED),
+    : task_runner_(new base::TestMockTimeTaskRunner),
+      task_runner_handle_(task_runner_),
+      last_save_result_(SavePageResult::CANCELLED),
       last_delete_result_(DeletePageResult::CANCELLED),
       last_deleted_bookmark_id_(-1) {
 }
@@ -306,12 +125,12 @@
   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
   model_ = BuildModel(BuildStore().Pass()).Pass();
   model_->AddObserver(this);
-  base::RunLoop().RunUntilIdle();
+  PumpLoop();
 }
 
 void OfflinePageModelTest::TearDown() {
   model_->RemoveObserver(this);
-  base::RunLoop().RunUntilIdle();
+  PumpLoop();
 }
 
 void OfflinePageModelTest::OfflinePageModelLoaded(OfflinePageModel* model) {
@@ -326,6 +145,11 @@
   last_deleted_bookmark_id_ = bookmark_id;
 }
 
+void OfflinePageModelTest::SetLastPathCreatedByArchiver(
+    const base::FilePath& file_path) {
+  last_archiver_path_ = file_path;
+}
+
 void OfflinePageModelTest::OnSavePageDone(
     OfflinePageModel::SavePageResult result) {
   last_save_result_ = result;
@@ -336,7 +160,7 @@
 }
 
 void OfflinePageModelTest::OnClearAllDone() {
-  base::RunLoop().RunUntilIdle();
+  PumpLoop();
 }
 
 void OfflinePageModelTest::OnStoreUpdateDone(bool /* success - ignored */) {
@@ -345,19 +169,19 @@
 scoped_ptr<OfflinePageTestArchiver> OfflinePageModelTest::BuildArchiver(
     const GURL& url,
     OfflinePageArchiver::ArchiverResult result) {
-  return scoped_ptr<OfflinePageTestArchiver>(
-      new OfflinePageTestArchiver(this, url, result, task_runner()));
+  return scoped_ptr<OfflinePageTestArchiver>(new OfflinePageTestArchiver(
+      this, url, result, kTestFileSize, base::ThreadTaskRunnerHandle::Get()));
 }
 
 scoped_ptr<OfflinePageMetadataStore> OfflinePageModelTest::BuildStore() {
   return scoped_ptr<OfflinePageMetadataStore>(
-      new OfflinePageTestStore(task_runner()));
+      new OfflinePageTestStore(base::ThreadTaskRunnerHandle::Get()));
 }
 
 scoped_ptr<OfflinePageModel> OfflinePageModelTest::BuildModel(
     scoped_ptr<OfflinePageMetadataStore> store) {
-  return scoped_ptr<OfflinePageModel>(
-      new OfflinePageModel(store.Pass(), temp_dir_.path(), task_runner()));
+  return scoped_ptr<OfflinePageModel>(new OfflinePageModel(
+      store.Pass(), temp_dir_.path(), base::ThreadTaskRunnerHandle::Get()));
 }
 
 void OfflinePageModelTest::ResetModel() {
@@ -371,7 +195,7 @@
 }
 
 void OfflinePageModelTest::PumpLoop() {
-  base::RunLoop().RunUntilIdle();
+  task_runner_->RunUntilIdle();
 }
 
 void OfflinePageModelTest::ResetResults() {
@@ -404,7 +228,6 @@
   EXPECT_EQ(archiver_path, store->last_saved_page().file_path);
   EXPECT_EQ(kTestFileSize, store->last_saved_page().file_size);
   EXPECT_EQ(SavePageResult::SUCCESS, last_save_result());
-
   ResetResults();
 
   const std::vector<OfflinePageItem>& offline_pages = model()->GetAllPages();
@@ -579,7 +402,7 @@
 
   // This will increase access_count by one.
   model()->MarkPageAccessed(kTestPageBookmarkId1);
-  base::RunLoop().RunUntilIdle();
+  PumpLoop();
 
   const std::vector<OfflinePageItem>& offline_pages = model()->GetAllPages();
 
@@ -619,7 +442,7 @@
 
   // Undo the deletion.
   model()->UndoPageDeletion(kTestPageBookmarkId1);
-  base::RunLoop().RunUntilIdle();
+  PumpLoop();
 
   // GetAllPages will now return the restored page.
   const std::vector<OfflinePageItem>& offline_pages_after_undo =
diff --git a/components/offline_pages/offline_page_test_archiver.cc b/components/offline_pages/offline_page_test_archiver.cc
new file mode 100644
index 0000000..6dfe954
--- /dev/null
+++ b/components/offline_pages/offline_page_test_archiver.cc
@@ -0,0 +1,52 @@
+// 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/offline_pages/offline_page_test_archiver.h"
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/location.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace offline_pages {
+
+OfflinePageTestArchiver::OfflinePageTestArchiver(
+    Observer* observer,
+    const GURL& url,
+    ArchiverResult result,
+    int64 size_to_report,
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
+    : observer_(observer),
+      url_(url),
+      result_(result),
+      size_to_report_(size_to_report),
+      create_archive_called_(false),
+      delayed_(false),
+      task_runner_(task_runner) {}
+
+OfflinePageTestArchiver::~OfflinePageTestArchiver() {
+  EXPECT_TRUE(create_archive_called_);
+}
+
+void OfflinePageTestArchiver::CreateArchive(
+    const base::FilePath& archives_dir,
+    const CreateArchiveCallback& callback) {
+  create_archive_called_ = true;
+  callback_ = callback;
+  archives_dir_ = archives_dir;
+  if (!delayed_)
+    CompleteCreateArchive();
+}
+
+void OfflinePageTestArchiver::CompleteCreateArchive() {
+  DCHECK(!callback_.is_null());
+  base::FilePath archive_path;
+  ASSERT_TRUE(base::CreateTemporaryFileInDir(archives_dir_, &archive_path));
+  observer_->SetLastPathCreatedByArchiver(archive_path);
+  task_runner_->PostTask(FROM_HERE, base::Bind(callback_, this, result_, url_,
+                                               archive_path, size_to_report_));
+}
+
+}  // namespace offline_pages
diff --git a/components/offline_pages/offline_page_test_archiver.h b/components/offline_pages/offline_page_test_archiver.h
new file mode 100644
index 0000000..7375c186
--- /dev/null
+++ b/components/offline_pages/offline_page_test_archiver.h
@@ -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.
+
+#ifndef COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_TEST_ARCHIVER_H_
+#define COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_TEST_ARCHIVER_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "components/offline_pages/offline_page_archiver.h"
+
+class GURL;
+
+namespace base {
+class FilePath;
+}  // namespace
+
+namespace offline_pages {
+
+// A test archiver class, which allows for testing offline pages without a need
+// for an actual web contents.
+class OfflinePageTestArchiver : public OfflinePageArchiver {
+ public:
+  class Observer {
+   public:
+    virtual ~Observer() {}
+    virtual void SetLastPathCreatedByArchiver(
+        const base::FilePath& file_path) = 0;
+  };
+
+  OfflinePageTestArchiver(
+      Observer* observer,
+      const GURL& url,
+      ArchiverResult result,
+      int64 size_to_report,
+      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+  ~OfflinePageTestArchiver() override;
+
+  // OfflinePageArchiver implementation:
+  void CreateArchive(const base::FilePath& archives_dir,
+                     const CreateArchiveCallback& callback) override;
+
+  // Completes the creation of archive. Should be used with |set_delayed| set to
+  // ture.
+  void CompleteCreateArchive();
+
+  // When set to true, |CompleteCreateArchive| should be called explicitly for
+  // the process to finish.
+  void set_delayed(bool delayed) { delayed_ = delayed; }
+
+  bool create_archive_called() const { return create_archive_called_; }
+
+ private:
+  // Not owned. Outlives OfflinePageTestArchiver.
+  Observer* observer_;
+  GURL url_;
+  base::FilePath archives_dir_;
+  ArchiverResult result_;
+  int64 size_to_report_;
+  bool create_archive_called_;
+  bool delayed_;
+  CreateArchiveCallback callback_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(OfflinePageTestArchiver);
+};
+
+}  // namespace offline_pages
+
+#endif  // COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_TEST_ARCHIVER_H_
diff --git a/components/offline_pages/offline_page_test_store.cc b/components/offline_pages/offline_page_test_store.cc
new file mode 100644
index 0000000..3a5b256
--- /dev/null
+++ b/components/offline_pages/offline_page_test_store.cc
@@ -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.
+
+#include "components/offline_pages/offline_page_test_store.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+OfflinePageTestStore::OfflinePageTestStore(
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
+    : task_runner_(task_runner), scenario_(TestScenario::SUCCESSFUL) {}
+
+OfflinePageTestStore::OfflinePageTestStore(
+    const OfflinePageTestStore& other_store)
+    : task_runner_(other_store.task_runner_),
+      scenario_(other_store.scenario_),
+      offline_pages_(other_store.offline_pages_) {}
+
+OfflinePageTestStore::~OfflinePageTestStore() {}
+
+void OfflinePageTestStore::Load(const LoadCallback& callback) {
+  OfflinePageMetadataStore::LoadStatus load_status;
+  if (scenario_ == TestScenario::LOAD_FAILED) {
+    load_status = OfflinePageMetadataStore::STORE_LOAD_FAILED;
+    offline_pages_.clear();
+  } else {
+    load_status = OfflinePageMetadataStore::LOAD_SUCCEEDED;
+  }
+  task_runner_->PostTask(FROM_HERE,
+                         base::Bind(callback, load_status, offline_pages_));
+}
+
+void OfflinePageTestStore::AddOrUpdateOfflinePage(
+    const OfflinePageItem& offline_page,
+    const UpdateCallback& callback) {
+  last_saved_page_ = offline_page;
+  bool result = scenario_ != TestScenario::WRITE_FAILED;
+  if (result)
+    offline_pages_.push_back(offline_page);
+  task_runner_->PostTask(FROM_HERE, base::Bind(callback, result));
+}
+
+void OfflinePageTestStore::RemoveOfflinePages(
+    const std::vector<int64>& bookmark_ids,
+    const UpdateCallback& callback) {
+  ASSERT_FALSE(bookmark_ids.empty());
+  bool result = false;
+  if (scenario_ != TestScenario::REMOVE_FAILED) {
+    for (auto iter = offline_pages_.begin(); iter != offline_pages_.end();
+         ++iter) {
+      if (iter->bookmark_id == bookmark_ids[0]) {
+        offline_pages_.erase(iter);
+        result = true;
+        break;
+      }
+    }
+  }
+
+  task_runner_->PostTask(FROM_HERE, base::Bind(callback, result));
+}
+
+void OfflinePageTestStore::Reset(const ResetCallback& callback) {
+  offline_pages_.clear();
+  task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
+}
+
+void OfflinePageTestStore::UpdateLastAccessTime(
+    int64 bookmark_id,
+    const base::Time& last_access_time) {
+  for (auto& offline_page : offline_pages_) {
+    if (offline_page.bookmark_id == bookmark_id) {
+      offline_page.last_access_time = last_access_time;
+      return;
+    }
+  }
+}
+
+}  // namespace offline_pages
diff --git a/components/offline_pages/offline_page_test_store.h b/components/offline_pages/offline_page_test_store.h
new file mode 100644
index 0000000..f24ac3c
--- /dev/null
+++ b/components/offline_pages/offline_page_test_store.h
@@ -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.
+
+#ifndef COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_TEST_STORE_H_
+#define COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_TEST_STORE_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "components/offline_pages/offline_page_item.h"
+#include "components/offline_pages/offline_page_metadata_store.h"
+
+namespace offline_pages {
+
+// Offline page store to be used for testing purposes. It stores offline pages
+// in memory. All callbacks are posted immediately through a provided
+// |task_runner|.
+class OfflinePageTestStore : public OfflinePageMetadataStore {
+ public:
+  enum class TestScenario {
+    SUCCESSFUL,
+    WRITE_FAILED,
+    LOAD_FAILED,
+    REMOVE_FAILED,
+  };
+
+  explicit OfflinePageTestStore(
+      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+  explicit OfflinePageTestStore(const OfflinePageTestStore& other_store);
+  ~OfflinePageTestStore() override;
+
+  // OfflinePageMetadataStore overrides:
+  void Load(const LoadCallback& callback) override;
+  void AddOrUpdateOfflinePage(const OfflinePageItem& offline_page,
+                              const UpdateCallback& callback) override;
+  void RemoveOfflinePages(const std::vector<int64>& bookmark_ids,
+                          const UpdateCallback& callback) override;
+  void Reset(const ResetCallback& callback) override;
+
+  void UpdateLastAccessTime(int64 bookmark_id,
+                            const base::Time& last_access_time);
+
+  const OfflinePageItem& last_saved_page() const { return last_saved_page_; }
+
+  void set_test_scenario(TestScenario scenario) { scenario_ = scenario; };
+
+  const std::vector<OfflinePageItem>& offline_pages() const {
+    return offline_pages_;
+  }
+
+ private:
+  OfflinePageItem last_saved_page_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+  TestScenario scenario_;
+
+  std::vector<OfflinePageItem> offline_pages_;
+
+  DISALLOW_ASSIGN(OfflinePageTestStore);
+};
+
+}  // namespace offline_pages
+
+#endif  // COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_TEST_STORE_H_
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn
index 3c17dbd7e..d37199a 100644
--- a/components/omnibox/browser/BUILD.gn
+++ b/components/omnibox/browser/BUILD.gn
@@ -182,6 +182,7 @@
     "answers_cache_unittest.cc",
     "autocomplete_input_unittest.cc",
     "autocomplete_match_unittest.cc",
+    "autocomplete_provider_unittest.cc",
     "autocomplete_result_unittest.cc",
     "base_search_provider_unittest.cc",
     "clipboard_url_provider_unittest.cc",
diff --git a/chrome/browser/autocomplete/autocomplete_provider_unittest.cc b/components/omnibox/browser/autocomplete_provider_unittest.cc
similarity index 80%
rename from chrome/browser/autocomplete/autocomplete_provider_unittest.cc
rename to components/omnibox/browser/autocomplete_provider_unittest.cc
index 3c876a2..edf06f6 100644
--- a/chrome/browser/autocomplete/autocomplete_provider_unittest.cc
+++ b/components/omnibox/browser/autocomplete_provider_unittest.cc
@@ -8,32 +8,25 @@
 #include "base/command_line.h"
 #include "base/location.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/thread_task_runner_handle.h"
-#include "chrome/browser/autocomplete/chrome_autocomplete_provider_client.h"
-#include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/test/base/testing_browser_process.h"
-#include "chrome/test/base/testing_profile.h"
 #include "components/metrics/proto/omnibox_event.pb.h"
 #include "components/omnibox/browser/autocomplete_controller.h"
 #include "components/omnibox/browser/autocomplete_input.h"
 #include "components/omnibox/browser/autocomplete_match.h"
 #include "components/omnibox/browser/autocomplete_provider_listener.h"
 #include "components/omnibox/browser/keyword_provider.h"
+#include "components/omnibox/browser/mock_autocomplete_provider_client.h"
 #include "components/omnibox/browser/search_provider.h"
 #include "components/search_engines/search_engines_switches.h"
 #include "components/search_engines/template_url.h"
 #include "components/search_engines/template_url_service.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/test/test_browser_thread_bundle.h"
+#include "components/search_engines/template_url_service_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 static std::ostream& operator<<(std::ostream& os,
@@ -42,24 +35,64 @@
 }
 
 namespace {
+
 const size_t kResultsPerProvider = 3;
 const char kTestTemplateURLKeyword[] = "t";
-}
+
+class TestingSchemeClassifier : public AutocompleteSchemeClassifier {
+ public:
+  TestingSchemeClassifier() {}
+
+  metrics::OmniboxInputType::Type GetInputTypeForScheme(
+      const std::string& scheme) const override {
+    return net::URLRequest::IsHandledProtocol(scheme)
+               ? metrics::OmniboxInputType::URL
+               : metrics::OmniboxInputType::INVALID;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestingSchemeClassifier);
+};
+
+// AutocompleteProviderClient implementation that calls the specified closure
+// when the result is ready.
+class AutocompleteProviderClientWithClosure
+    : public MockAutocompleteProviderClient {
+ public:
+  AutocompleteProviderClientWithClosure() {}
+
+  void set_closure(const base::Closure& closure) { closure_ = closure; }
+
+ private:
+  void OnAutocompleteControllerResultReady(
+      AutocompleteController* controller) override {
+    if (!closure_.is_null())
+      closure_.Run();
+    if (base::MessageLoop::current()->is_running())
+      base::MessageLoop::current()->QuitWhenIdle();
+  }
+
+  base::Closure closure_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutocompleteProviderClientWithClosure);
+};
+
+}  // namespace
 
 // Autocomplete provider that provides known results. Note that this is
 // refcounted so that it can also be a task on the message loop.
 class TestProvider : public AutocompleteProvider {
  public:
-  TestProvider(int relevance, const base::string16& prefix,
-               Profile* profile,
-               const base::string16 match_keyword)
+  TestProvider(int relevance,
+               const base::string16& prefix,
+               const base::string16 match_keyword,
+               AutocompleteProviderClient* client)
       : AutocompleteProvider(AutocompleteProvider::TYPE_SEARCH),
-        listener_(NULL),
-        profile_(profile),
+        listener_(nullptr),
         relevance_(relevance),
         prefix_(prefix),
-        match_keyword_(match_keyword) {
-  }
+        match_keyword_(match_keyword),
+        client_(client) {}
 
   void Start(const AutocompleteInput& input, bool minimal_changes) override;
 
@@ -80,10 +113,12 @@
       const TemplateURLRef::SearchTermsArgs& search_terms_args);
 
   AutocompleteProviderListener* listener_;
-  Profile* profile_;
   int relevance_;
   const base::string16 prefix_;
   const base::string16 match_keyword_;
+  AutocompleteProviderClient* client_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestProvider);
 };
 
 void TestProvider::Start(const AutocompleteInput& input, bool minimal_changes) {
@@ -115,7 +150,6 @@
 }
 
 void TestProvider::Run() {
-  DCHECK_GT(kResultsPerProvider, 0U);
   AddResults(1, kResultsPerProvider);
   done_ = true;
   DCHECK(listener_);
@@ -123,11 +157,9 @@
 }
 
 void TestProvider::AddResults(int start_at, int num) {
-  AddResultsWithSearchTermsArgs(start_at,
-                                num,
-                                AutocompleteMatchType::URL_WHAT_YOU_TYPED,
-                                TemplateURLRef::SearchTermsArgs(
-                                    base::string16()));
+  AddResultsWithSearchTermsArgs(
+      start_at, num, AutocompleteMatchType::URL_WHAT_YOU_TYPED,
+      TemplateURLRef::SearchTermsArgs(base::string16()));
 }
 
 void TestProvider::AddResultsWithSearchTermsArgs(
@@ -152,17 +184,19 @@
         new TemplateURLRef::SearchTermsArgs(search_terms_args));
     if (!match_keyword_.empty()) {
       match.keyword = match_keyword_;
-      TemplateURLService* service =
-          TemplateURLServiceFactory::GetForProfile(profile_);
-      ASSERT_TRUE(match.GetTemplateURL(service, false) != NULL);
+      ASSERT_NE(nullptr,
+                match.GetTemplateURL(client_->GetTemplateURLService(), false));
     }
 
     matches_.push_back(match);
   }
 }
 
-class AutocompleteProviderTest : public testing::Test,
-                                 public content::NotificationObserver {
+class AutocompleteProviderTest : public testing::Test {
+ public:
+  AutocompleteProviderTest();
+  ~AutocompleteProviderTest() override;
+
  protected:
   struct KeywordTestData {
     const base::string16 fill_into_edit;
@@ -175,8 +209,7 @@
     const std::string expected_aqs;
   };
 
- protected:
-   // Registers a test TemplateURL under the given keyword.
+  // Registers a test TemplateURL under the given keyword.
   void RegisterTemplateURL(const base::string16 keyword,
                            const std::string& template_url);
 
@@ -202,7 +235,7 @@
       const AssistedQueryStatsTestData* aqs_test_data,
       size_t size);
 
-  void RunQuery(const base::string16 query);
+  void RunQuery(const std::string& query, bool allow_exact_keyword_match);
 
   void ResetControllerWithKeywordAndSearchProviders();
   void ResetControllerWithKeywordProvider();
@@ -229,31 +262,42 @@
   AutocompleteResult result_;
 
  private:
-  // content::NotificationObserver:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
+  // Resets the controller with the given |type|. |type| is a bitmap containing
+  // AutocompleteProvider::Type values that will (potentially, depending on
+  // platform, flags, etc.) be instantiated.
+  void ResetControllerWithType(int type);
 
-  content::TestBrowserThreadBundle thread_bundle_;
-  content::NotificationRegistrar registrar_;
-  TestingProfile profile_;
+  base::MessageLoop message_loop_;
   scoped_ptr<AutocompleteController> controller_;
+  // Owned by |controller_|.
+  AutocompleteProviderClientWithClosure* client_;
+  // Used to ensure that |client_| ownership has been passed to |controller_|
+  // exactly once.
+  bool client_owned_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutocompleteProviderTest);
 };
 
+AutocompleteProviderTest::AutocompleteProviderTest()
+    : client_(new AutocompleteProviderClientWithClosure()),
+      client_owned_(false) {
+  client_->set_template_url_service(
+      make_scoped_ptr(new TemplateURLService(nullptr, 0)));
+}
+
+AutocompleteProviderTest::~AutocompleteProviderTest() {
+  EXPECT_TRUE(client_owned_);
+}
+
 void AutocompleteProviderTest::RegisterTemplateURL(
     const base::string16 keyword,
     const std::string& template_url) {
-  if (TemplateURLServiceFactory::GetForProfile(&profile_) == NULL) {
-    TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-        &profile_, &TemplateURLServiceFactory::BuildInstanceFor);
-  }
   TemplateURLData data;
   data.SetURL(template_url);
   data.SetShortName(keyword);
   data.SetKeyword(keyword);
   TemplateURL* default_t_url = new TemplateURL(data);
-  TemplateURLService* turl_model =
-      TemplateURLServiceFactory::GetForProfile(&profile_);
+  TemplateURLService* turl_model = client_->GetTemplateURLService();
   turl_model->Add(default_t_url);
   turl_model->SetUserSelectedDefaultSearchProvider(default_t_url);
   turl_model->Load();
@@ -281,26 +325,20 @@
   AutocompleteController::Providers providers;
 
   // Construct two new providers, with either the same or different prefixes.
-  TestProvider* provider1 = new TestProvider(
-      kResultsPerProvider,
-      base::ASCIIToUTF16("http://a"),
-      &profile_,
-      base::ASCIIToUTF16(kTestTemplateURLKeyword));
+  TestProvider* provider1 =
+      new TestProvider(kResultsPerProvider, base::ASCIIToUTF16("http://a"),
+                       base::ASCIIToUTF16(kTestTemplateURLKeyword), client_);
   providers.push_back(provider1);
 
   TestProvider* provider2 = new TestProvider(
       kResultsPerProvider * 2,
-      same_destinations ? base::ASCIIToUTF16("http://a")
-                        : base::ASCIIToUTF16("http://b"),
-      &profile_,
-      base::string16());
+      base::ASCIIToUTF16(same_destinations ? "http://a" : "http://b"),
+      base::string16(), client_);
   providers.push_back(provider2);
 
   // Reset the controller to contain our new providers.
-  controller_.reset(new AutocompleteController(
+  ResetControllerWithType(0);
 
-      make_scoped_ptr(new ChromeAutocompleteProviderClient(&profile_)), NULL,
-      0));
   // We're going to swap the providers vector, but the old vector should be
   // empty so no elements need to be freed at this point.
   EXPECT_TRUE(controller_->providers_.empty());
@@ -308,11 +346,8 @@
   provider1->set_listener(controller_.get());
   provider2->set_listener(controller_.get());
 
-  // The providers don't complete synchronously, so listen for "result updated"
-  // notifications.
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY,
-                 content::Source<AutocompleteController>(controller_.get()));
+  client_->set_closure(base::Bind(&AutocompleteProviderTest::CopyResults,
+                                  base::Unretained(this)));
 
   if (provider1_ptr)
     *provider1_ptr = provider1;
@@ -320,19 +355,14 @@
     *provider2_ptr = provider2;
 }
 
-void AutocompleteProviderTest::
-    ResetControllerWithKeywordAndSearchProviders() {
-  TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-      &profile_, &TemplateURLServiceFactory::BuildInstanceFor);
-
+void AutocompleteProviderTest::ResetControllerWithKeywordAndSearchProviders() {
   // Reset the default TemplateURL.
   TemplateURLData data;
   data.SetShortName(base::ASCIIToUTF16("default"));
   data.SetKeyword(base::ASCIIToUTF16("default"));
   data.SetURL("http://defaultturl/{searchTerms}");
   TemplateURL* default_t_url = new TemplateURL(data);
-  TemplateURLService* turl_model =
-      TemplateURLServiceFactory::GetForProfile(&profile_);
+  TemplateURLService* turl_model = client_->GetTemplateURLService();
   turl_model->Add(default_t_url);
   turl_model->SetUserSelectedDefaultSearchProvider(default_t_url);
   TemplateURLID default_provider_id = default_t_url->id();
@@ -347,18 +377,12 @@
   turl_model->Add(keyword_t_url);
   ASSERT_NE(0, keyword_t_url->id());
 
-  controller_.reset(new AutocompleteController(
-
-      make_scoped_ptr(new ChromeAutocompleteProviderClient(&profile_)), NULL,
-      AutocompleteProvider::TYPE_KEYWORD | AutocompleteProvider::TYPE_SEARCH));
+  ResetControllerWithType(AutocompleteProvider::TYPE_KEYWORD |
+                          AutocompleteProvider::TYPE_SEARCH);
 }
 
 void AutocompleteProviderTest::ResetControllerWithKeywordProvider() {
-  TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-      &profile_, &TemplateURLServiceFactory::BuildInstanceFor);
-
-  TemplateURLService* turl_model =
-      TemplateURLServiceFactory::GetForProfile(&profile_);
+  TemplateURLService* turl_model = client_->GetTemplateURLService();
 
   // Create a TemplateURL for KeywordProvider.
   TemplateURLData data;
@@ -386,13 +410,18 @@
   turl_model->Add(keyword_t_url);
   ASSERT_NE(0, keyword_t_url->id());
 
-  controller_.reset(new AutocompleteController(
-      make_scoped_ptr(new ChromeAutocompleteProviderClient(&profile_)), NULL,
-      AutocompleteProvider::TYPE_KEYWORD));
+  ResetControllerWithType(AutocompleteProvider::TYPE_KEYWORD);
+}
+
+void AutocompleteProviderTest::ResetControllerWithType(int type) {
+  EXPECT_FALSE(client_owned_);
+  controller_.reset(
+      new AutocompleteController(make_scoped_ptr(client_), nullptr, type));
+  client_owned_ = true;
 }
 
 void AutocompleteProviderTest::RunTest() {
-  RunQuery(base::ASCIIToUTF16("a"));
+  RunQuery("a", true);
 }
 
 void AutocompleteProviderTest::RunKeywordTest(const base::string16& input,
@@ -412,17 +441,15 @@
   controller_->input_ = AutocompleteInput(
       input, base::string16::npos, std::string(), GURL(),
       metrics::OmniboxEventProto::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS,
-      false, true, true, true, false,
-      ChromeAutocompleteSchemeClassifier(&profile_));
+      false, true, true, true, false, TestingSchemeClassifier());
   AutocompleteResult result;
   result.AppendMatches(controller_->input_, matches);
   controller_->UpdateAssociatedKeywords(&result);
-
   for (size_t j = 0; j < result.size(); ++j) {
     EXPECT_EQ(match_data[j].expected_associated_keyword,
-              result.match_at(j)->associated_keyword.get() ?
-                  result.match_at(j)->associated_keyword->keyword :
-                  base::string16());
+              result.match_at(j)->associated_keyword.get()
+                  ? result.match_at(j)->associated_keyword->keyword
+                  : base::string16());
   }
 }
 
@@ -433,7 +460,7 @@
   const size_t kMaxRelevance = 1000;
   ACMatches matches;
   for (size_t i = 0; i < size; ++i) {
-    AutocompleteMatch match(NULL, kMaxRelevance - i, false,
+    AutocompleteMatch match(nullptr, kMaxRelevance - i, false,
                             aqs_test_data[i].match_type);
     match.allowed_to_be_default_match = true;
     match.keyword = base::ASCIIToUTF16(kTestTemplateURLKeyword);
@@ -454,12 +481,13 @@
   }
 }
 
-void AutocompleteProviderTest::RunQuery(const base::string16 query) {
+void AutocompleteProviderTest::RunQuery(const std::string& query,
+                                        bool allow_exact_keyword_match) {
   result_.Reset();
   controller_->Start(AutocompleteInput(
-      query, base::string16::npos, std::string(), GURL(),
-      metrics::OmniboxEventProto::INVALID_SPEC, true, false, true, true, false,
-      ChromeAutocompleteSchemeClassifier(&profile_)));
+      base::ASCIIToUTF16(query), base::string16::npos, std::string(), GURL(),
+      metrics::OmniboxEventProto::INVALID_SPEC, true, false,
+      allow_exact_keyword_match, true, false, TestingSchemeClassifier()));
 
   if (!controller_->done())
     // The message loop will terminate when all autocomplete input has been
@@ -475,18 +503,13 @@
   // |allow_exact_keyword_match| is true.  Regardless, the match should
   // be from SearchProvider.  (It provides all verbatim search matches,
   // keyword or not.)
-  controller_->Start(AutocompleteInput(
-      base::ASCIIToUTF16("k test"), base::string16::npos, std::string(), GURL(),
-      metrics::OmniboxEventProto::INVALID_SPEC, true, false,
-      allow_exact_keyword_match, false, false,
-      ChromeAutocompleteSchemeClassifier(&profile_)));
-  EXPECT_TRUE(controller_->done());
+  RunQuery("k test", allow_exact_keyword_match);
   EXPECT_EQ(AutocompleteProvider::TYPE_SEARCH,
-      controller_->result().default_match()->provider->type());
-  EXPECT_EQ(allow_exact_keyword_match ?
-      AutocompleteMatchType::SEARCH_OTHER_ENGINE :
-      AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
-      controller_->result().default_match()->type);
+            controller_->result().default_match()->provider->type());
+  EXPECT_EQ(allow_exact_keyword_match
+                ? AutocompleteMatchType::SEARCH_OTHER_ENGINE
+                : AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+            controller_->result().default_match()->type);
 }
 
 void AutocompleteProviderTest::CopyResults() {
@@ -501,20 +524,10 @@
   return match.destination_url;
 }
 
-void AutocompleteProviderTest::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  if (controller_->done()) {
-    CopyResults();
-    base::MessageLoop::current()->QuitWhenIdle();
-  }
-}
-
 // Tests that the default selection is set properly when updating results.
 TEST_F(AutocompleteProviderTest, Query) {
-  TestProvider* provider1 = NULL;
-  TestProvider* provider2 = NULL;
+  TestProvider* provider1 = nullptr;
+  TestProvider* provider2 = nullptr;
   ResetControllerWithTestProviders(false, &provider1, &provider2);
   RunTest();
 
@@ -527,7 +540,7 @@
 
 // Tests assisted query stats.
 TEST_F(AutocompleteProviderTest, AssistedQueryStats) {
-  ResetControllerWithTestProviders(false, NULL, NULL);
+  ResetControllerWithTestProviders(false, nullptr, nullptr);
   RunTest();
 
   ASSERT_EQ(kResultsPerProvider * 2, result_.size());
@@ -546,8 +559,8 @@
 }
 
 TEST_F(AutocompleteProviderTest, RemoveDuplicates) {
-  TestProvider* provider1 = NULL;
-  TestProvider* provider2 = NULL;
+  TestProvider* provider1 = nullptr;
+  TestProvider* provider2 = nullptr;
   ResetControllerWithTestProviders(true, &provider1, &provider2);
   RunTest();
 
@@ -658,7 +671,7 @@
 }
 
 TEST_F(AutocompleteProviderTest, UpdateAssistedQueryStats) {
-  ResetControllerWithTestProviders(false, NULL, NULL);
+  ResetControllerWithTestProviders(false, nullptr, nullptr);
 
   {
     AssistedQueryStatsTestData test_data[] = {
@@ -707,7 +720,7 @@
 
   // For the destination URL to have aqs parameters for query formulation time
   // and the field trial triggered bit, many conditions need to be satisfied.
-  AutocompleteMatch match(NULL, 1100, false,
+  AutocompleteMatch match(nullptr, 1100, false,
                           AutocompleteMatchType::SEARCH_SUGGEST);
   GURL url(GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456)));
   EXPECT_TRUE(url.path().empty());
diff --git a/components/omnibox/browser/omnibox_edit_controller.h b/components/omnibox/browser/omnibox_edit_controller.h
index 26b453fd..622c485 100644
--- a/components/omnibox/browser/omnibox_edit_controller.h
+++ b/components/omnibox/browser/omnibox_edit_controller.h
@@ -22,9 +22,7 @@
                                     WindowOpenDisposition disposition,
                                     ui::PageTransition transition);
 
-  // Called when the the controller should update itself without restoring any
-  // tab state.
-  virtual void UpdateWithoutTabRestore() = 0;
+  virtual void OnInputInProgress(bool in_progress) = 0;
 
   // Called when anything has changed that might affect the layout or contents
   // of the views around the edit, including the text of the edit and the
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc
index e6efb0e..e194a03 100644
--- a/components/omnibox/browser/omnibox_edit_model.cc
+++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -451,8 +451,7 @@
     autocomplete_controller()->ResetSession();
   }
 
-  controller_->GetToolbarModel()->set_input_in_progress(in_progress);
-  controller_->UpdateWithoutTabRestore();
+  controller_->OnInputInProgress(in_progress);
 
   if (user_input_in_progress_ || !in_revert_)
     client_->OnInputStateChanged();
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index eb60cfc1..7254beb3 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -892,7 +892,7 @@
 
   bool success = autofill_manager->download_manager()->StartUploadRequest(
       form_structure, false /* was_autofilled */, available_field_types,
-      login_form_signature);
+      login_form_signature, true /* observed_submission */);
 
   UMA_HISTOGRAM_BOOLEAN("PasswordGeneration.UploadStarted", success);
   return success;
@@ -970,7 +970,7 @@
 
   return autofill_manager->download_manager()->StartUploadRequest(
       form_structure, false /* was_autofilled */, available_field_types,
-      login_form_signature);
+      login_form_signature, true /* observed_submission */);
 }
 
 void PasswordFormManager::CreatePendingCredentials() {
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc
index 8c828402..3a4f97f 100644
--- a/components/password_manager/core/browser/password_form_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -102,11 +102,12 @@
       autofill::AutofillDownloadManager::Observer* observer)
       : AutofillDownloadManager(driver, pref_service, observer) {}
 
-  MOCK_METHOD4(StartUploadRequest,
+  MOCK_METHOD5(StartUploadRequest,
                bool(const autofill::FormStructure&,
                     bool,
                     const autofill::ServerFieldTypeSet&,
-                    const std::string&));
+                    const std::string&,
+                    bool));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockAutofillDownloadManager);
@@ -397,15 +398,15 @@
           autofill::NOT_ACCOUNT_CREATION_PASSWORD;
     }
     if (field_type) {
-      EXPECT_CALL(
-          *client()->mock_driver()->mock_autofill_download_manager(),
-          StartUploadRequest(
-              CheckUploadFormStructure(pending_structure.FormSignature(),
-                                       expected_types),
-              false, expected_available_field_types, expected_login_signature));
+      EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
+                  StartUploadRequest(
+                      CheckUploadFormStructure(
+                          pending_structure.FormSignature(), expected_types),
+                      false, expected_available_field_types,
+                      expected_login_signature, true));
     } else {
       EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
-                  StartUploadRequest(_, _, _, _))
+                  StartUploadRequest(_, _, _, _, _))
           .Times(0);
     }
     form_manager.ProvisionallySave(
@@ -475,11 +476,11 @@
       autofill::FormStructure pending_structure(saved_match()->form_data);
       expected_login_signature = pending_structure.FormSignature();
     }
-    EXPECT_CALL(
-        *client()->mock_driver()->mock_autofill_download_manager(),
-        StartUploadRequest(
-            CheckUploadFormStructure(observed_form_signature, expected_types),
-            false, expected_available_field_types, expected_login_signature));
+    EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
+                StartUploadRequest(CheckUploadFormStructure(
+                                       observed_form_signature, expected_types),
+                                   false, expected_available_field_types,
+                                   expected_login_signature, true));
 
     switch (field_type) {
       case autofill::NEW_PASSWORD:
@@ -735,8 +736,9 @@
   autofill::ServerFieldTypeSet expected_available_field_types;
   expected_available_field_types.insert(autofill::USERNAME);
   expected_available_field_types.insert(autofill::ACCOUNT_CREATION_PASSWORD);
-  EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
-              StartUploadRequest(_, false, expected_available_field_types, _))
+  EXPECT_CALL(
+      *client()->mock_driver()->mock_autofill_download_manager(),
+      StartUploadRequest(_, false, expected_available_field_types, _, true))
       .Times(1);
   EXPECT_CALL(*mock_store(), AddLogin(_))
       .WillOnce(SaveArg<0>(&actual_saved_form));
@@ -1561,8 +1563,9 @@
   autofill::ServerFieldTypeSet expected_available_field_types;
   expected_available_field_types.insert(autofill::USERNAME);
   expected_available_field_types.insert(autofill::PASSWORD);
-  EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
-              StartUploadRequest(_, false, expected_available_field_types, _));
+  EXPECT_CALL(
+      *client()->mock_driver()->mock_autofill_download_manager(),
+      StartUploadRequest(_, false, expected_available_field_types, _, true));
   form_manager.ProvisionallySave(
       form_to_save, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
   form_manager.Save();
@@ -1577,7 +1580,7 @@
   expected_available_field_types.insert(autofill::USERNAME);
   expected_available_field_types.insert(autofill::PASSWORD);
   EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
-              StartUploadRequest(_, _, expected_available_field_types, _))
+              StartUploadRequest(_, _, expected_available_field_types, _, true))
       .Times(0);
   blacklist_form_manager.PermanentlyBlacklist();
   Mock::VerifyAndClearExpectations(&blacklist_form_manager);
diff --git a/components/password_manager/core/browser/password_manager_constants.cc b/components/password_manager/core/browser/password_manager_constants.cc
index 392b024..ecfb8e7 100644
--- a/components/password_manager/core/browser/password_manager_constants.cc
+++ b/components/password_manager/core/browser/password_manager_constants.cc
@@ -12,6 +12,6 @@
     FILE_PATH_LITERAL("Login Data");
 
 const char kPasswordManagerAccountDashboardURL[] =
-    "https://passwords.google.com/settings/passwords";
+    "https://passwords.google.com";
 
 }  // namespace password_manager
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 211bcc6..e7997c7 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -62,6 +62,9 @@
 #     where the value of the policy can be entered. 'main' policies on
 #     Windows ignore this. Policies on Mac are using this instead of caption.
 #
+# Non-translateable strings should be tagged using <ph name="..."></ph> as
+# described in https://code.google.com/p/grit-i18n/wiki/GritUsersGuide.
+#
 # Generated grd names:
 #   Each name has two parts: the second part is either CAPTION, DESC or LABEL,
 #   and the first part identifies the item the text applies to:
@@ -154,7 +157,7 @@
 #   cloud), if the optional key 'default_for_enterprise_users' is set, its value
 #   is applied as mandatory policy unless a different setting is received from
 #   the cloud.
-#
+
   'risk_tag_definitions' : [
     # All following tags are ordered by severity of their impact.
     # TODO(fhorschig|tnagel): Revisit user-descriptions after reviews.
@@ -1916,11 +1919,11 @@
           },
           'example_value': 'com.example.spnego',
           'id': 305,
-          'caption': '''Account type for HTTP Negotiate authentication''',
+          'caption': '''Account type for <ph name="HTTP_NEGOTIATE">HTTP Negotiate</ph> authentication''',
           'tags': [],
-          'desc': '''Specifies the account type of the accounts provided by the Android authentication app that supports HTTP Negotiate authentication (e.g. Kerberos authentication). This information should be available from the supplier of the authentication app. For more details see https://goo.gl/hajyfN.
+          'desc': '''Specifies the account type of the accounts provided by the Android authentication app that supports <ph name="HTTP_NEGOTIATE">HTTP Negotiate</ph> authentication (e.g. Kerberos authentication). This information should be available from the supplier of the authentication app. For more details see https://goo.gl/hajyfN.
 
-          If no setting is provided, HTTP Negotiate authentication is disabled on Android.''',
+          If no setting is provided, <ph name="HTTP_NEGOTIATE">HTTP Negotiate</ph> authentication is disabled on Android.''',
         },
         {
           'name': 'AllowCrossOriginAuthPrompt',
@@ -4409,7 +4412,7 @@
         }
       }
 
-      Printers connected to Google Cloud Print are considered "cloud", the rest of the printers are classified as "local".
+      Printers connected to <ph name="CLOUD_PRINT_NAME">Google Cloud Print</ph> are considered <ph name="PRINTER_TYPE_CLOUD">"cloud"</ph>, the rest of the printers are classified as <ph name="PRINTER_TYPE_LOCAL">"local"</ph>.
       Omitting a field means all values match, for example, not specifying connectivity will cause Print Preview to initiate the discovery of all kinds of printers, local and cloud.
       Regular expression patterns must follow the JavaScript RegExp syntax and matches are case sensistive.''',
     },
@@ -4426,9 +4429,9 @@
       'id': 118,
       'caption': '''Disable TLS False Start''',
       'tags': [],
-      'desc': '''Specifies whether the TLS False Start optimization should be disabled. For historical reasons, this policy is named DisableSSLRecordSplitting.
+      'desc': '''Specifies whether the <ph name="TLS_FALSE_START">TLS False Start</ph> optimization should be disabled. For historical reasons, this policy is named DisableSSLRecordSplitting.
 
-      If the policy is not set, or is set to false, then TLS False Start will be enabled. If it is set to true, TLS False Start will be disabled.''',
+      If the policy is not set, or is set to false, then <ph name="TLS_FALSE_START">TLS False Start</ph> will be enabled. If it is set to true, <ph name="TLS_FALSE_START">TLS False Start</ph> will be disabled.''',
     },
     {
       'name': 'EnableOnlineRevocationChecks',
@@ -7379,15 +7382,18 @@
       'desc': '''Configures a list of managed bookmarks.
 
       The policy consists of a list of bookmarks whereas each bookmark is a
-      dictionary containing the keys "name" and "url" which hold the bookmark's
-      name and its target. A subfolder may be configured by defining a bookmark
-      without an "url" key but with an additional "children" key which itself
-      contains a list of bookmarks as defined above (some of which may be
-      folders again). <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>
-      amends incomplete URLs as if they were submitted via the Omnibox, for
-      example "google.com" becomes "https://google.com/".
+      dictionary containing the keys <ph name="NAME">"name"</ph> and <ph
+      name="URL">"url"</ph> which hold the bookmark's name and its target. A
+      subfolder may be configured by defining a bookmark without an <ph
+      name="URL">"url"</ph> key but with an additional <ph
+      name="CHILDREN">"children"</ph> key which itself contains a list of
+      bookmarks as defined above (some of which may be folders again). <ph
+      name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> amends incomplete URLs
+      as if they were submitted via the Omnibox, for example <ph
+      name="GOOGLE_COM">"google.com"</ph> becomes <ph
+      name="HTTPS_GOOGLE_COM">"https://google.com/"</ph>.
 
-      These bookmarks are placed in a Managed bookmarks folder that can't be modified by the user, but the user can choose to hide it from the bookmark bar. Managed bookmarks are not synced to the user account and can't be modified by extensions.''',
+      These bookmarks are placed in a "Managed bookmarks" folder that can't be modified by the user, but the user can choose to hide it from the bookmark bar. Managed bookmarks are not synced to the user account and can't be modified by extensions.''',
     },
     {
       'name': 'DataCompressionProxyEnabled',
@@ -8115,7 +8121,7 @@
       'desc': '''Introduction text for the generated policy documentation''',
       'text': '''Both Chromium and Google Chrome support the same set of
       policies. Please note that this document may include policies that are
-      targeted for unreleased software versions (i.e. their 'supported on' entry
+      targeted for unreleased software versions (i.e. their 'Supported on' entry
       refers to an unreleased version) and that such policies are subject to
       change or removal without prior notice.
 
diff --git a/components/printing/common/print_messages.h b/components/printing/common/print_messages.h
index 34d9613..1458d3b 100644
--- a/components/printing/common/print_messages.h
+++ b/components/printing/common/print_messages.h
@@ -222,7 +222,7 @@
   IPC_STRUCT_MEMBER(base::SharedMemoryHandle, metafile_data_handle)
 
   // Size of metafile data.
-  IPC_STRUCT_MEMBER(uint32, data_size)
+  IPC_STRUCT_MEMBER(uint32_t, data_size)
 
   // Cookie for the document to ensure correctness.
   IPC_STRUCT_MEMBER(int, document_cookie)
@@ -243,10 +243,9 @@
   IPC_STRUCT_MEMBER(base::SharedMemoryHandle, metafile_data_handle)
 
   // Size of metafile data.
-  IPC_STRUCT_MEMBER(uint32, data_size)
+  IPC_STRUCT_MEMBER(uint32_t, data_size)
 
-  // |page_number| is zero-based and can be |printing::INVALID_PAGE_INDEX| if it
-  // is just a check.
+  // |page_number| is zero-based and should not be negative.
   IPC_STRUCT_MEMBER(int, page_number)
 
   // The id of the preview request.
@@ -278,7 +277,7 @@
   IPC_STRUCT_MEMBER(base::SharedMemoryHandle, metafile_data_handle)
 
   // Size of the metafile data.
-  IPC_STRUCT_MEMBER(uint32, data_size)
+  IPC_STRUCT_MEMBER(uint32_t, data_size)
 
   // Cookie for the document to ensure correctness.
   IPC_STRUCT_MEMBER(int, document_cookie)
diff --git a/components/printing/renderer/print_web_view_helper.cc b/components/printing/renderer/print_web_view_helper.cc
index f2dc502..6164ca1 100644
--- a/components/printing/renderer/print_web_view_helper.cc
+++ b/components/printing/renderer/print_web_view_helper.cc
@@ -1411,32 +1411,6 @@
   prep_frame_view_.reset();
 }
 
-#if defined(OS_MACOSX)
-bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
-                                          int page_count) {
-  const PrintMsg_PrintPages_Params& params = *print_pages_params_;
-  const PrintMsg_Print_Params& print_params = params.params;
-
-  PrintMsg_PrintPage_Params page_params;
-  page_params.params = print_params;
-  if (params.pages.empty()) {
-    for (int i = 0; i < page_count; ++i) {
-      page_params.page_number = i;
-      PrintPageInternal(page_params, frame);
-    }
-  } else {
-    for (size_t i = 0; i < params.pages.size(); ++i) {
-      if (params.pages[i] >= page_count)
-        break;
-      page_params.page_number = params.pages[i];
-      PrintPageInternal(page_params, frame);
-    }
-  }
-  return true;
-}
-
-#endif  // OS_MACOSX
-
 // static - Not anonymous so that platform implementations can use it.
 void PrintWebViewHelper::ComputePageLayoutInPointsForCss(
     blink::WebFrame* frame,
@@ -1453,6 +1427,25 @@
   CalculatePageLayoutFromPrintParams(params, page_layout_in_points);
 }
 
+// static - Not anonymous so that platform implementations can use it.
+std::vector<int> PrintWebViewHelper::GetPrintedPages(
+    const PrintMsg_PrintPages_Params& params,
+    int page_count) {
+  std::vector<int> printed_pages;
+  if (params.pages.empty()) {
+    for (int i = 0; i < page_count; ++i) {
+      printed_pages.push_back(i);
+    }
+  } else {
+    for (int page : params.pages) {
+      if (page >= 0 && page < page_count) {
+        printed_pages.push_back(page);
+      }
+    }
+  }
+  return printed_pages;
+}
+
 bool PrintWebViewHelper::InitPrintSettings(bool fit_to_paper_size) {
   PrintMsg_PrintPages_Params settings;
   Send(new PrintHostMsg_GetDefaultPrintSettings(routing_id(),
diff --git a/components/printing/renderer/print_web_view_helper.h b/components/printing/renderer/print_web_view_helper.h
index d9ea441..98a7567 100644
--- a/components/printing/renderer/print_web_view_helper.h
+++ b/components/printing/renderer/print_web_view_helper.h
@@ -309,6 +309,12 @@
       double* scale_factor,
       PageSizeMargins* page_layout_in_points);
 
+  // Return an array of pages to print given the print |params| and an expected
+  // |page_count|. Page numbers are zero-based.
+  static std::vector<int> GetPrintedPages(
+      const PrintMsg_PrintPages_Params& params,
+      int page_count);
+
 #if defined(ENABLE_PRINT_PREVIEW)
   // Given the |device| and |canvas| to draw on, prints the appropriate headers
   // and footers using strings from |header_footer_info| on to the canvas.
diff --git a/components/printing/renderer/print_web_view_helper_linux.cc b/components/printing/renderer/print_web_view_helper_linux.cc
index 3e4033d..fe84cbdc 100644
--- a/components/printing/renderer/print_web_view_helper_linux.cc
+++ b/components/printing/renderer/print_web_view_helper_linux.cc
@@ -13,11 +13,11 @@
 #include "printing/pdf_metafile_skia.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
-#include "base/process/process_handle.h"
-#else
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
 #include "base/file_descriptor_posix.h"
-#endif  // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+#else
+#include "base/process/process_handle.h"
+#endif  // defined(OS_CHROMEOS) || defined(OS_ANDROID)
 
 namespace printing {
 
@@ -60,28 +60,14 @@
     return false;
 
   const PrintMsg_PrintPages_Params& params = *print_pages_params_;
-  std::vector<int> printed_pages;
-
-  if (params.pages.empty()) {
-    for (int i = 0; i < page_count; ++i) {
-      printed_pages.push_back(i);
-    }
-  } else {
-    // TODO(vitalybuka): redesign to make more code cross platform.
-    for (size_t i = 0; i < params.pages.size(); ++i) {
-      if (params.pages[i] >= 0 && params.pages[i] < page_count) {
-        printed_pages.push_back(params.pages[i]);
-      }
-    }
-  }
-
+  std::vector<int> printed_pages = GetPrintedPages(params, page_count);
   if (printed_pages.empty())
     return false;
 
   PrintMsg_PrintPage_Params page_params;
   page_params.params = params.params;
-  for (size_t i = 0; i < printed_pages.size(); ++i) {
-    page_params.page_number = printed_pages[i];
+  for (int page_number : printed_pages) {
+    page_params.page_number = page_number;
     PrintPageInternal(page_params, frame, &metafile);
   }
 
diff --git a/components/printing/renderer/print_web_view_helper_mac.mm b/components/printing/renderer/print_web_view_helper_mac.mm
index 293f567a..e682fa3 100644
--- a/components/printing/renderer/print_web_view_helper_mac.mm
+++ b/components/printing/renderer/print_web_view_helper_mac.mm
@@ -20,6 +20,24 @@
 
 using blink::WebFrame;
 
+bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
+                                          int page_count) {
+  const PrintMsg_PrintPages_Params& params = *print_pages_params_;
+  const PrintMsg_Print_Params& print_params = params.params;
+
+  std::vector<int> printed_pages = GetPrintedPages(params, page_count);
+  if (printed_pages.empty())
+    return false;
+
+  PrintMsg_PrintPage_Params page_params;
+  page_params.params = print_params;
+  for (int page_number : printed_pages) {
+    page_params.page_number = page_number;
+    PrintPageInternal(page_params, frame);
+  }
+  return true;
+}
+
 void PrintWebViewHelper::PrintPageInternal(
     const PrintMsg_PrintPage_Params& params,
     WebFrame* frame) {
diff --git a/components/printing/renderer/print_web_view_helper_pdf_win.cc b/components/printing/renderer/print_web_view_helper_pdf_win.cc
index 13ad735..1d07291 100644
--- a/components/printing/renderer/print_web_view_helper_pdf_win.cc
+++ b/components/printing/renderer/print_web_view_helper_pdf_win.cc
@@ -58,19 +58,7 @@
     return false;
 
   const PrintMsg_PrintPages_Params& params = *print_pages_params_;
-  std::vector<int> printed_pages;
-  if (params.pages.empty()) {
-    for (int i = 0; i < page_count; ++i) {
-      printed_pages.push_back(i);
-    }
-  } else {
-    // TODO(vitalybuka): redesign to make more code cross platform.
-    for (size_t i = 0; i < params.pages.size(); ++i) {
-      if (params.pages[i] >= 0 && params.pages[i] < page_count) {
-        printed_pages.push_back(params.pages[i]);
-      }
-    }
-  }
+  std::vector<int> printed_pages = GetPrintedPages(params, page_count);
   if (printed_pages.empty())
     return false;
 
diff --git a/components/proximity_auth/BUILD.gn b/components/proximity_auth/BUILD.gn
index c031eba..565e1d2 100644
--- a/components/proximity_auth/BUILD.gn
+++ b/components/proximity_auth/BUILD.gn
@@ -75,6 +75,7 @@
     "//components/proximity_auth/ble",
     "//components/proximity_auth/cryptauth",
     "//components/proximity_auth/logging",
+    "//components/signin/core/account_id:account_id",
     "//device/bluetooth",
     "//net",
   ]
diff --git a/components/proximity_auth/DEPS b/components/proximity_auth/DEPS
index 24229c6..5b55479 100644
--- a/components/proximity_auth/DEPS
+++ b/components/proximity_auth/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+components/signin/core/account_id/account_id.h",
   "+device/bluetooth",
   "+net",
 ]
diff --git a/components/proximity_auth/proximity_auth_system.cc b/components/proximity_auth/proximity_auth_system.cc
index 704a5d71..286c38a 100644
--- a/components/proximity_auth/proximity_auth_system.cc
+++ b/components/proximity_auth/proximity_auth_system.cc
@@ -40,9 +40,10 @@
     return;
   started_ = true;
   ScreenlockBridge::Get()->AddObserver(this);
-  std::string focused_user_id = ScreenlockBridge::Get()->focused_user_id();
-  if (!focused_user_id.empty())
-    OnFocusedUserChanged(focused_user_id);
+  const AccountId& focused_account_id =
+      ScreenlockBridge::Get()->focused_account_id();
+  if (focused_account_id.is_valid())
+    OnFocusedUserChanged(focused_account_id);
 }
 
 void ProximityAuthSystem::Stop() {
@@ -50,29 +51,30 @@
     return;
   started_ = false;
   ScreenlockBridge::Get()->RemoveObserver(this);
-  OnFocusedUserChanged(std::string());
+  OnFocusedUserChanged(EmptyAccountId());
 }
 
 void ProximityAuthSystem::SetRemoteDevicesForUser(
-    const std::string& user_id,
+    const AccountId& account_id,
     const RemoteDeviceList& remote_devices) {
-  remote_devices_map_[user_id] = remote_devices;
+  remote_devices_map_[account_id] = remote_devices;
   if (started_) {
-    std::string focused_user_id = ScreenlockBridge::Get()->focused_user_id();
-    if (!focused_user_id.empty())
-      OnFocusedUserChanged(focused_user_id);
+    const AccountId& focused_account_id =
+        ScreenlockBridge::Get()->focused_account_id();
+    if (focused_account_id.is_valid())
+      OnFocusedUserChanged(focused_account_id);
   }
 }
 
 RemoteDeviceList ProximityAuthSystem::GetRemoteDevicesForUser(
-    const std::string& user_id) const {
-  if (remote_devices_map_.find(user_id) == remote_devices_map_.end())
+    const AccountId& account_id) const {
+  if (remote_devices_map_.find(account_id) == remote_devices_map_.end())
     return RemoteDeviceList();
-  return remote_devices_map_.at(user_id);
+  return remote_devices_map_.at(account_id);
 }
 
-void ProximityAuthSystem::OnAuthAttempted(const std::string& user_id) {
-  // TODO(tengs): There is no reason to pass the |user_id| argument anymore.
+void ProximityAuthSystem::OnAuthAttempted(const AccountId& /* account_id */) {
+  // TODO(tengs): There is no reason to pass the |account_id| argument anymore.
   unlock_manager_->OnAuthAttempted(ScreenlockBridge::LockHandler::USER_CLICK);
 }
 
@@ -110,7 +112,7 @@
   } else if (!started_) {
     PA_LOG(INFO) << "Suspend done, but not system started.";
   } else {
-    OnFocusedUserChanged(ScreenlockBridge::Get()->focused_user_id());
+    OnFocusedUserChanged(ScreenlockBridge::Get()->focused_account_id());
   }
 }
 
@@ -122,7 +124,7 @@
 
 void ProximityAuthSystem::OnScreenDidLock(
     ScreenlockBridge::LockHandler::ScreenType screen_type) {
-  OnFocusedUserChanged(ScreenlockBridge::Get()->focused_user_id());
+  OnFocusedUserChanged(ScreenlockBridge::Get()->focused_account_id());
 }
 
 void ProximityAuthSystem::OnScreenDidUnlock(
@@ -131,28 +133,30 @@
   remote_device_life_cycle_.reset();
 }
 
-void ProximityAuthSystem::OnFocusedUserChanged(const std::string& user_id) {
+void ProximityAuthSystem::OnFocusedUserChanged(const AccountId& account_id) {
   // Update the current RemoteDeviceLifeCycle to the focused user.
-  if (!user_id.empty() && remote_device_life_cycle_ &&
-      remote_device_life_cycle_->GetRemoteDevice().user_id != user_id) {
+  if (account_id.is_valid() && remote_device_life_cycle_ &&
+      remote_device_life_cycle_->GetRemoteDevice().user_id !=
+          account_id.GetUserEmail()) {
     PA_LOG(INFO) << "Focused user changed, destroying life cycle for "
-                 << user_id << ".";
+                 << account_id.Serialize() << ".";
     unlock_manager_->SetRemoteDeviceLifeCycle(nullptr);
     remote_device_life_cycle_.reset();
   }
 
-  if (remote_devices_map_.find(user_id) == remote_devices_map_.end() ||
-      remote_devices_map_[user_id].size() == 0) {
-    PA_LOG(INFO) << "User " << user_id << " does not have a RemoteDevice.";
+  if (remote_devices_map_.find(account_id) == remote_devices_map_.end() ||
+      remote_devices_map_[account_id].size() == 0) {
+    PA_LOG(INFO) << "User " << account_id.Serialize()
+                 << " does not have a RemoteDevice.";
     return;
   }
 
   // TODO(tengs): We currently assume each user has only one RemoteDevice, so we
   // can simply take the first item in the list.
-  RemoteDevice remote_device = remote_devices_map_[user_id][0];
+  RemoteDevice remote_device = remote_devices_map_[account_id][0];
   if (!suspended_) {
     PA_LOG(INFO) << "Creating RemoteDeviceLifeCycle for focused user: "
-                 << user_id;
+                 << account_id.Serialize();
     remote_device_life_cycle_.reset(
         new RemoteDeviceLifeCycleImpl(remote_device, proximity_auth_client_));
     unlock_manager_->SetRemoteDeviceLifeCycle(remote_device_life_cycle_.get());
diff --git a/components/proximity_auth/proximity_auth_system.h b/components/proximity_auth/proximity_auth_system.h
index d5bd587..a4e0a7f 100644
--- a/components/proximity_auth/proximity_auth_system.h
+++ b/components/proximity_auth/proximity_auth_system.h
@@ -13,6 +13,7 @@
 #include "components/proximity_auth/remote_device.h"
 #include "components/proximity_auth/remote_device_life_cycle.h"
 #include "components/proximity_auth/screenlock_bridge.h"
+#include "components/signin/core/account_id/account_id.h"
 
 namespace proximity_auth {
 
@@ -41,18 +42,19 @@
   // Stops the system.
   void Stop();
 
-  // Registers a list of |remote_devices| for |user_id| that can be used for
+  // Registers a list of |remote_devices| for |account_id| that can be used for
   // sign-in/unlock. If devices were previously registered for the user, then
   // they will be replaced.
-  void SetRemoteDevicesForUser(const std::string& user_id,
+  void SetRemoteDevicesForUser(const AccountId& account_id,
                                const RemoteDeviceList& remote_devices);
 
-  // Returns the RemoteDevices registered for |user_id|. Returns an empty list
-  // if no devices are registered for |user_id|.
-  RemoteDeviceList GetRemoteDevicesForUser(const std::string& user_id) const;
+  // Returns the RemoteDevices registered for |account_id|. Returns an empty
+  // list
+  // if no devices are registered for |account_id|.
+  RemoteDeviceList GetRemoteDevicesForUser(const AccountId& account_id) const;
 
   // Called when the user clicks the user pod and attempts to unlock/sign-in.
-  void OnAuthAttempted(const std::string& user_id);
+  void OnAuthAttempted(const AccountId& account_id);
 
   // Called when the system suspends.
   void OnSuspend();
@@ -70,14 +72,14 @@
       ScreenlockBridge::LockHandler::ScreenType screen_type) override;
   void OnScreenDidUnlock(
       ScreenlockBridge::LockHandler::ScreenType screen_type) override;
-  void OnFocusedUserChanged(const std::string& user_id) override;
+  void OnFocusedUserChanged(const AccountId& account_id) override;
 
   // Resumes |remote_device_life_cycle_| after device wakes up and waits a
   // timeout.
   void ResumeAfterWakeUpTimeout();
 
-  // Lists of remote devices, keyed by user id.
-  std::map<std::string, RemoteDeviceList> remote_devices_map_;
+  // Lists of remote devices, keyed by user account id.
+  std::map<AccountId, RemoteDeviceList> remote_devices_map_;
 
   // Delegate for Chrome dependent functionality.
   ProximityAuthClient* proximity_auth_client_;
diff --git a/components/proximity_auth/screenlock_bridge.cc b/components/proximity_auth/screenlock_bridge.cc
index fd822ec2..835317d 100644
--- a/components/proximity_auth/screenlock_bridge.cc
+++ b/components/proximity_auth/screenlock_bridge.cc
@@ -131,7 +131,7 @@
   else
     screen_type = lock_handler->GetScreenType();
 
-  focused_user_id_ = std::string();
+  focused_account_id_ = EmptyAccountId();
   lock_handler_ = lock_handler;
   if (lock_handler_)
     FOR_EACH_OBSERVER(Observer, observers_, OnScreenDidLock(screen_type));
@@ -139,12 +139,12 @@
     FOR_EACH_OBSERVER(Observer, observers_, OnScreenDidUnlock(screen_type));
 }
 
-void ScreenlockBridge::SetFocusedUser(const std::string& user_id) {
-  if (user_id == focused_user_id_)
+void ScreenlockBridge::SetFocusedUser(const AccountId& account_id) {
+  if (account_id == focused_account_id_)
     return;
-  PA_LOG(INFO) << "Focused user changed to " << user_id;
-  focused_user_id_ = user_id;
-  FOR_EACH_OBSERVER(Observer, observers_, OnFocusedUserChanged(user_id));
+  PA_LOG(INFO) << "Focused user changed to " << account_id.Serialize();
+  focused_account_id_ = account_id;
+  FOR_EACH_OBSERVER(Observer, observers_, OnFocusedUserChanged(account_id));
 }
 
 bool ScreenlockBridge::IsLocked() const {
@@ -161,9 +161,9 @@
 #endif
 }
 
-void ScreenlockBridge::Unlock(const std::string& user_email) {
+void ScreenlockBridge::Unlock(const AccountId& account_id) {
   if (lock_handler_)
-    lock_handler_->Unlock(user_email);
+    lock_handler_->Unlock(account_id);
 }
 
 void ScreenlockBridge::AddObserver(Observer* observer) {
@@ -174,8 +174,8 @@
   observers_.RemoveObserver(observer);
 }
 
-ScreenlockBridge::ScreenlockBridge() : lock_handler_(nullptr) {
-}
+ScreenlockBridge::ScreenlockBridge()
+    : lock_handler_(nullptr), focused_account_id_(EmptyAccountId()) {}
 
 ScreenlockBridge::~ScreenlockBridge() {
 }
diff --git a/components/proximity_auth/screenlock_bridge.h b/components/proximity_auth/screenlock_bridge.h
index 21a32dd7..0311569 100644
--- a/components/proximity_auth/screenlock_bridge.h
+++ b/components/proximity_auth/screenlock_bridge.h
@@ -15,6 +15,7 @@
 #include "base/observer_list.h"
 #include "base/strings/string16.h"
 #include "base/values.h"
+#include "components/signin/core/account_id/account_id.h"
 
 namespace proximity_auth {
 
@@ -106,31 +107,31 @@
 
     // Shows a custom icon in the user pod on the lock screen.
     virtual void ShowUserPodCustomIcon(
-        const std::string& user_email,
+        const AccountId& account_id,
         const UserPodCustomIconOptions& icon) = 0;
 
     // Hides the custom icon in user pod for a user.
-    virtual void HideUserPodCustomIcon(const std::string& user_email) = 0;
+    virtual void HideUserPodCustomIcon(const AccountId& account_id) = 0;
 
     // (Re)enable lock screen UI.
     virtual void EnableInput() = 0;
 
     // Set the authentication type to be used on the lock screen.
-    virtual void SetAuthType(const std::string& user_email,
+    virtual void SetAuthType(const AccountId& account_id,
                              AuthType auth_type,
                              const base::string16& auth_value) = 0;
 
     // Returns the authentication type used for a user.
-    virtual AuthType GetAuthType(const std::string& user_email) const = 0;
+    virtual AuthType GetAuthType(const AccountId& account_id) const = 0;
 
     // Returns the type of the screen -- a signin or a lock screen.
     virtual ScreenType GetScreenType() const = 0;
 
     // Unlocks from easy unlock app for a user.
-    virtual void Unlock(const std::string& user_email) = 0;
+    virtual void Unlock(const AccountId& account_id) = 0;
 
     // Attempts to login the user using an easy unlock key.
-    virtual void AttemptEasySignin(const std::string& user_email,
+    virtual void AttemptEasySignin(const AccountId& account_id,
                                    const std::string& secret,
                                    const std::string& key_label) = 0;
 
@@ -147,7 +148,7 @@
     virtual void OnScreenDidUnlock(LockHandler::ScreenType screen_type) = 0;
 
     // Invoked when the user focused on the lock screen changes.
-    virtual void OnFocusedUserChanged(const std::string& user_id) = 0;
+    virtual void OnFocusedUserChanged(const AccountId& account_id) = 0;
 
    protected:
     virtual ~Observer() {}
@@ -156,20 +157,20 @@
   static ScreenlockBridge* Get();
 
   void SetLockHandler(LockHandler* lock_handler);
-  void SetFocusedUser(const std::string& user_id);
+  void SetFocusedUser(const AccountId& account_id);
 
   bool IsLocked() const;
   void Lock();
 
-  // Unlocks the screen for the authenticated user with the given |user_email|.
-  void Unlock(const std::string& user_email);
+  // Unlocks the screen for the authenticated user with the given |user_id|.
+  void Unlock(const AccountId& account_id);
 
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
 
   LockHandler* lock_handler() { return lock_handler_; }
 
-  std::string focused_user_id() const { return focused_user_id_; }
+  const AccountId& focused_account_id() const { return focused_account_id_; }
 
  private:
   friend struct base::DefaultLazyInstanceTraits<ScreenlockBridge>;
@@ -181,7 +182,7 @@
   LockHandler* lock_handler_;  // Not owned
 
   // The last focused user's id.
-  std::string focused_user_id_;
+  AccountId focused_account_id_;
   base::ObserverList<Observer, true> observers_;
 
   DISALLOW_COPY_AND_ASSIGN(ScreenlockBridge);
diff --git a/components/proximity_auth/unlock_manager.cc b/components/proximity_auth/unlock_manager.cc
index 15f1fabe..3b6d1cd0 100644
--- a/components/proximity_auth/unlock_manager.cc
+++ b/components/proximity_auth/unlock_manager.cc
@@ -234,7 +234,7 @@
   OnScreenLockedOrUnlocked(false);
 }
 
-void UnlockManager::OnFocusedUserChanged(const std::string& user_id) {}
+void UnlockManager::OnFocusedUserChanged(const AccountId& account_id) {}
 
 void UnlockManager::OnScreenLockedOrUnlocked(bool is_locked) {
   // TODO(tengs): Chrome will only start connecting to the phone when
diff --git a/components/proximity_auth/unlock_manager.h b/components/proximity_auth/unlock_manager.h
index 0ff771c..696f0ec 100644
--- a/components/proximity_auth/unlock_manager.h
+++ b/components/proximity_auth/unlock_manager.h
@@ -85,7 +85,7 @@
       ScreenlockBridge::LockHandler::ScreenType screen_type) override;
   void OnScreenDidUnlock(
       ScreenlockBridge::LockHandler::ScreenType screen_type) override;
-  void OnFocusedUserChanged(const std::string& user_id) override;
+  void OnFocusedUserChanged(const AccountId& account_id) override;
 
   // Called when the screenlock state changes.
   void OnScreenLockedOrUnlocked(bool is_locked);
diff --git a/components/proximity_auth/unlock_manager_unittest.cc b/components/proximity_auth/unlock_manager_unittest.cc
index 2bb786c..d6b3383f 100644
--- a/components/proximity_auth/unlock_manager_unittest.cc
+++ b/components/proximity_auth/unlock_manager_unittest.cc
@@ -114,19 +114,19 @@
   // LockHandler:
   void ShowBannerMessage(const base::string16& message) override {}
   void ShowUserPodCustomIcon(
-      const std::string& user_email,
+      const AccountId& account_id,
       const ScreenlockBridge::UserPodCustomIconOptions& icon) override {}
-  void HideUserPodCustomIcon(const std::string& user_email) override {}
+  void HideUserPodCustomIcon(const AccountId& account_id) override {}
   void EnableInput() override {}
-  void SetAuthType(const std::string& user_email,
+  void SetAuthType(const AccountId& account_id,
                    AuthType auth_type,
                    const base::string16& auth_value) override {}
-  AuthType GetAuthType(const std::string& user_email) const override {
+  AuthType GetAuthType(const AccountId& account_id) const override {
     return USER_CLICK;
   }
   ScreenType GetScreenType() const override { return LOCK_SCREEN; }
-  void Unlock(const std::string& user_email) override {}
-  void AttemptEasySignin(const std::string& user_email,
+  void Unlock(const AccountId& account_id) override {}
+  void AttemptEasySignin(const AccountId& account_id,
                          const std::string& secret,
                          const std::string& key_label) override {}
 
diff --git a/components/scheduler/base/enqueue_order.cc b/components/scheduler/base/enqueue_order.cc
new file mode 100644
index 0000000..dd04bbd4
--- /dev/null
+++ b/components/scheduler/base/enqueue_order.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/scheduler/base/enqueue_order.h"
+
+namespace scheduler {
+namespace internal {
+
+EnqueueOrderGenerator::EnqueueOrderGenerator() : enqueue_order_(0) {}
+
+EnqueueOrderGenerator::~EnqueueOrderGenerator() {}
+
+EnqueueOrder EnqueueOrderGenerator::GenerateNext() {
+  base::AutoLock lock(lock_);
+  return enqueue_order_++;
+}
+
+}  // namespace internal
+}  // namespace scheduler
diff --git a/components/scheduler/base/enqueue_order.h b/components/scheduler/base/enqueue_order.h
new file mode 100644
index 0000000..21001ff
--- /dev/null
+++ b/components/scheduler/base/enqueue_order.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 COMPONENTS_SCHEDULER_BASE_ENQUEUE_ORDER_H_
+#define COMPONENTS_SCHEDULER_BASE_ENQUEUE_ORDER_H_
+
+#include <stdint.h>
+
+#include "base/synchronization/lock.h"
+
+namespace scheduler {
+namespace internal {
+
+using EnqueueOrder = uint64_t;
+
+class EnqueueOrderGenerator {
+ public:
+  EnqueueOrderGenerator();
+  ~EnqueueOrderGenerator();
+
+  EnqueueOrder GenerateNext();
+
+ private:
+  base::Lock lock_;
+  EnqueueOrder enqueue_order_;
+};
+
+}  // namespace internal
+}  // namespace scheduler
+
+#endif  // COMPONENTS_SCHEDULER_BASE_ENQUEUE_ORDER_H_
diff --git a/components/scheduler/base/task_queue_impl.cc b/components/scheduler/base/task_queue_impl.cc
index 1d2b249..8ec8ce2 100644
--- a/components/scheduler/base/task_queue_impl.cc
+++ b/components/scheduler/base/task_queue_impl.cc
@@ -54,7 +54,7 @@
 TaskQueueImpl::Task::Task(const tracked_objects::Location& posted_from,
                           const base::Closure& task,
                           base::TimeTicks desired_run_time,
-                          int sequence_number,
+                          EnqueueOrder sequence_number,
                           bool nestable)
     : PendingTask(posted_from, task, base::TimeTicks(), nestable),
 #ifndef NDEBUG
@@ -68,9 +68,9 @@
 TaskQueueImpl::Task::Task(const tracked_objects::Location& posted_from,
                           const base::Closure& task,
                           base::TimeTicks desired_run_time,
-                          int sequence_number,
+                          EnqueueOrder sequence_number,
                           bool nestable,
-                          int enqueue_order)
+                          EnqueueOrder enqueue_order)
     : PendingTask(posted_from, task, base::TimeTicks(), nestable),
 #ifndef NDEBUG
       enqueue_order_set_(true),
@@ -162,7 +162,7 @@
     base::TimeTicks desired_run_time,
     TaskType task_type) {
   DCHECK(any_thread().task_queue_manager);
-  int sequence_number =
+  EnqueueOrder sequence_number =
       any_thread().task_queue_manager->GetNextSequenceNumber();
   if (!desired_run_time.is_null()) {
     PushOntoDelayedIncomingQueueLocked(
@@ -193,7 +193,7 @@
     // 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 =
+    EnqueueOrder thread_hop_task_sequence_number =
         any_thread().task_queue_manager->GetNextSequenceNumber();
     PushOntoImmediateIncomingQueueLocked(Task(
         FROM_HERE,
@@ -282,7 +282,7 @@
     return false;
   }
 
-  int enqueue_order;
+  EnqueueOrder enqueue_order;
   if (!main_thread_only().delayed_work_queue->GetFrontTaskEnqueueOrder(
           &enqueue_order)) {
     return true;
@@ -335,7 +335,7 @@
   if (!ShouldAutoPumpQueueLocked(should_trigger_wakeup, previous_task))
     return;
 
-  main_thread_only().immediate_work_queue->Swap(
+  main_thread_only().immediate_work_queue->SwapLocked(
       any_thread().immediate_incoming_queue);
 
   // |any_thread().immediate_incoming_queue| is now empty so
@@ -350,6 +350,12 @@
                                      &is_tracing);
   if (!is_tracing)
     return;
+
+  // It's only safe to access the work queues from the main thread.
+  // TODO(alexclarke): We should find another way of tracing this
+  if (base::PlatformThread::CurrentId() != thread_id_)
+    return;
+
   if (!is_locked)
     any_thread_lock_.Acquire();
   else
diff --git a/components/scheduler/base/task_queue_impl.h b/components/scheduler/base/task_queue_impl.h
index 7f85f9a..98977a2 100644
--- a/components/scheduler/base/task_queue_impl.h
+++ b/components/scheduler/base/task_queue_impl.h
@@ -11,6 +11,7 @@
 #include "base/threading/thread_checker.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
+#include "components/scheduler/base/enqueue_order.h"
 #include "components/scheduler/base/task_queue.h"
 #include "components/scheduler/scheduler_export.h"
 
@@ -37,24 +38,24 @@
     Task(const tracked_objects::Location& posted_from,
          const base::Closure& task,
          base::TimeTicks desired_run_time,
-         int sequence_number,
+         EnqueueOrder sequence_number,
          bool nestable);
 
     Task(const tracked_objects::Location& posted_from,
          const base::Closure& task,
          base::TimeTicks desired_run_time,
-         int sequence_number,
+         EnqueueOrder sequence_number,
          bool nestable,
-         int enqueue_order);
+         EnqueueOrder enqueue_order);
 
-    int enqueue_order() const {
+    EnqueueOrder enqueue_order() const {
 #ifndef NDEBUG
       DCHECK(enqueue_order_set_);
 #endif
       return enqueue_order_;
     }
 
-    void set_enqueue_order(int enqueue_order) {
+    void set_enqueue_order(EnqueueOrder enqueue_order) {
 #ifndef NDEBUG
       DCHECK(!enqueue_order_set_);
       enqueue_order_set_ = true;
@@ -69,7 +70,7 @@
     // 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 |immediate_incoming_queue_|.
-    int enqueue_order_;
+    EnqueueOrder enqueue_order_;
   };
 
   // TaskQueue implementation.
@@ -203,6 +204,7 @@
 
   void MoveReadyImmediateTasksToImmediateWorkQueueLocked();
 
+  // Note this does nothing if its not called from the main thread.
   void PumpQueueLocked(bool may_post_dowork);
   bool TaskIsOlderThanQueuedTasks(const Task* task);
   bool ShouldAutoPumpQueueLocked(bool should_trigger_wakeup,
diff --git a/components/scheduler/base/task_queue_manager.cc b/components/scheduler/base/task_queue_manager.cc
index 6fec6e0..01a3ca1 100644
--- a/components/scheduler/base/task_queue_manager.cc
+++ b/components/scheduler/base/task_queue_manager.cc
@@ -312,8 +312,8 @@
   return delegate_;
 }
 
-int TaskQueueManager::GetNextSequenceNumber() {
-  return task_sequence_num_.GetNext();
+internal::EnqueueOrder TaskQueueManager::GetNextSequenceNumber() {
+  return enqueue_order_generator_.GenerateNext();
 }
 
 LazyNow TaskQueueManager::CreateLazyNow() const {
diff --git a/components/scheduler/base/task_queue_manager.h b/components/scheduler/base/task_queue_manager.h
index b9705547..545c3991 100644
--- a/components/scheduler/base/task_queue_manager.h
+++ b/components/scheduler/base/task_queue_manager.h
@@ -15,6 +15,7 @@
 #include "base/pending_task.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
+#include "components/scheduler/base/enqueue_order.h"
 #include "components/scheduler/base/task_queue_impl.h"
 #include "components/scheduler/base/task_queue_selector.h"
 #include "components/scheduler/scheduler_export.h"
@@ -176,7 +177,7 @@
                                   const base::Closure& task,
                                   base::TimeDelta delay);
 
-  int GetNextSequenceNumber();
+  internal::EnqueueOrder GetNextSequenceNumber();
 
   bool TryAdvanceTimeDomains();
 
@@ -193,8 +194,7 @@
   // raw pointers and doesn't expect the rug to be pulled out from underneath.
   std::set<scoped_refptr<internal::TaskQueueImpl>> queues_to_delete_;
 
-
-  base::AtomicSequenceNumber task_sequence_num_;
+  internal::EnqueueOrderGenerator enqueue_order_generator_;
   base::debug::TaskAnnotator task_annotator_;
 
   base::ThreadChecker main_thread_checker_;
diff --git a/components/scheduler/base/task_queue_manager_unittest.cc b/components/scheduler/base/task_queue_manager_unittest.cc
index 6396d362..b1b76d0 100644
--- a/components/scheduler/base/task_queue_manager_unittest.cc
+++ b/components/scheduler/base/task_queue_manager_unittest.cc
@@ -22,7 +22,9 @@
 #include "testing/gmock/include/gmock/gmock.h"
 
 using testing::ElementsAre;
+using testing::ElementsAreArray;
 using testing::_;
+using scheduler::internal::EnqueueOrder;
 
 namespace scheduler {
 
@@ -131,14 +133,14 @@
 
 void NullTask() {}
 
-void TestTask(int value, std::vector<int>* out_result) {
+void TestTask(EnqueueOrder value, std::vector<EnqueueOrder>* out_result) {
   out_result->push_back(value);
 }
 
 TEST_F(TaskQueueManagerTest, SingleQueuePosting) {
   Initialize(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
@@ -150,7 +152,7 @@
 TEST_F(TaskQueueManagerTest, MultiQueuePosting) {
   Initialize(3u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
   runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
@@ -165,7 +167,7 @@
 TEST_F(TaskQueueManagerTest, NonNestableTaskPosting) {
   InitializeWithRealMessageLoop(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostNonNestableTask(FROM_HERE,
                                    base::Bind(&TestTask, 1, &run_order));
 
@@ -176,7 +178,7 @@
 TEST_F(TaskQueueManagerTest, NonNestableTaskExecutesInExpectedOrder) {
   InitializeWithRealMessageLoop(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
@@ -191,7 +193,7 @@
 TEST_F(TaskQueueManagerTest, NonNestableTaskDoesntExecuteInNestedLoop) {
   InitializeWithRealMessageLoop(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
 
@@ -216,7 +218,7 @@
 TEST_F(TaskQueueManagerTest, QueuePolling) {
   Initialize(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   EXPECT_FALSE(runners_[0]->HasPendingImmediateWork());
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
   EXPECT_TRUE(runners_[0]->HasPendingImmediateWork());
@@ -228,7 +230,7 @@
 TEST_F(TaskQueueManagerTest, DelayedTaskPosting) {
   Initialize(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
   runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
                                delay);
@@ -266,7 +268,7 @@
 TEST_F(TaskQueueManagerTest, DelayedTaskPosting_MultipleTasks_DecendingOrder) {
   Initialize(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
                                base::TimeDelta::FromMilliseconds(10));
 
@@ -296,7 +298,7 @@
 TEST_F(TaskQueueManagerTest, DelayedTaskPosting_MultipleTasks_AscendingOrder) {
   Initialize(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
                                base::TimeDelta::FromMilliseconds(1));
 
@@ -326,7 +328,7 @@
 TEST_F(TaskQueueManagerTest, PostDelayedTask_SharesUnderlyingDelayedTasks) {
   Initialize(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
   runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
                                delay);
@@ -370,7 +372,7 @@
   Initialize(1u);
   runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   // Posting a task when pumping is disabled doesn't result in work getting
   // posted.
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
@@ -390,7 +392,7 @@
   Initialize(1u);
   runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   // Posting a task when pumping is disabled doesn't result in work getting
   // posted.
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
@@ -406,7 +408,7 @@
 TEST_F(TaskQueueManagerTest, DenyRunning_BeforePosting) {
   Initialize(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->SetQueuePriority(TaskQueue::DISABLED_PRIORITY);
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
 
@@ -421,7 +423,7 @@
 TEST_F(TaskQueueManagerTest, DenyRunning_AfterPosting) {
   Initialize(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
   runners_[0]->SetQueuePriority(TaskQueue::DISABLED_PRIORITY);
 
@@ -436,7 +438,7 @@
 TEST_F(TaskQueueManagerTest, DenyRunning_ManuallyPumpedTransitionsToAuto) {
   Initialize(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
   runners_[0]->SetQueuePriority(TaskQueue::DISABLED_PRIORITY);
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
@@ -454,7 +456,7 @@
   Initialize(1u);
   runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   // Posting a delayed task when pumping will apply the delay, but won't cause
   // work to executed afterwards.
   base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
@@ -478,7 +480,7 @@
   Initialize(1u);
   runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   // Posting a delayed task when pumping will apply the delay, but won't cause
   // work to executed afterwards.
   base::TimeDelta delay1(base::TimeDelta::FromMilliseconds(1));
@@ -505,7 +507,7 @@
   Initialize(1u);
   runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
   runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
                                delay);
@@ -518,7 +520,7 @@
   Initialize(1u);
   runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   // 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));
@@ -531,7 +533,7 @@
 
 void ReentrantTestTask(scoped_refptr<base::SingleThreadTaskRunner> runner,
                        int countdown,
-                       std::vector<int>* out_result) {
+                       std::vector<EnqueueOrder>* out_result) {
   out_result->push_back(countdown);
   if (--countdown) {
     runner->PostTask(FROM_HERE,
@@ -542,7 +544,7 @@
 TEST_F(TaskQueueManagerTest, ReentrantPosting) {
   Initialize(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostTask(FROM_HERE,
                         Bind(&ReentrantTestTask, runners_[0], 3, &run_order));
 
@@ -553,7 +555,7 @@
 TEST_F(TaskQueueManagerTest, NoTasksAfterShutdown) {
   Initialize(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
   manager_.reset();
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
@@ -563,14 +565,14 @@
 }
 
 void PostTaskToRunner(scoped_refptr<base::SingleThreadTaskRunner> runner,
-                      std::vector<int>* run_order) {
+                      std::vector<EnqueueOrder>* run_order) {
   runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, run_order));
 }
 
 TEST_F(TaskQueueManagerTest, PostFromThread) {
   InitializeWithRealMessageLoop(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   base::Thread thread("TestThread");
   thread.Start();
   thread.task_runner()->PostTask(
@@ -605,7 +607,7 @@
 TEST_F(TaskQueueManagerTest, PostFromNestedRunloop) {
   InitializeWithRealMessageLoop(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   std::vector<std::pair<base::Closure, bool>> tasks_to_post_from_nested_loop;
   tasks_to_post_from_nested_loop.push_back(
       std::make_pair(base::Bind(&TestTask, 1, &run_order), true));
@@ -627,7 +629,7 @@
 
   manager_->SetWorkBatchSize(2);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
@@ -649,7 +651,7 @@
   Initialize(2u);
   runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
   test_task_runner_->RunUntilIdle();
   EXPECT_TRUE(run_order.empty());  // Shouldn't run - no other task to wake TQM.
@@ -668,7 +670,7 @@
   Initialize(2u);
   runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
   runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
   test_task_runner_->RunUntilIdle();
@@ -681,7 +683,7 @@
   runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP);
   runners_[1]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
   test_task_runner_->RunUntilIdle();
   EXPECT_TRUE(run_order.empty());  // Shouldn't run - no other task to wake TQM.
@@ -706,7 +708,7 @@
   Initialize(2u);
   runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   // Check that a task which posts a task to an auto pump after wakeup queue
   // doesn't cause the queue to wake up.
   base::Closure after_wakeup_task = base::Bind(&TestTask, 1, &run_order);
@@ -725,7 +727,7 @@
   Initialize(2u);
   runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   // Check that a task which posts a task to an auto pump after wakeup queue
   // doesn't cause the queue to wake up.
   base::Closure after_wakeup_task_1 = base::Bind(&TestTask, 1, &run_order);
@@ -773,7 +775,7 @@
           .SetWakeupPolicy(TaskQueue::WakeupPolicy::DONT_WAKE_OTHER_QUEUES));
   scoped_refptr<internal::TaskQueueImpl> queue2 = runners_[0];
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   queue0->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
   queue1->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
   test_task_runner_->RunUntilIdle();
@@ -801,7 +803,7 @@
   manager_->SetWorkBatchSize(2);
   manager_->AddTaskObserver(&observer);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
 
@@ -817,7 +819,7 @@
   manager_->AddTaskObserver(&observer);
   manager_->RemoveTaskObserver(&observer);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
 
   EXPECT_CALL(observer, WillProcessTask(_)).Times(0);
@@ -852,7 +854,7 @@
   manager_->SetWorkBatchSize(2);
   runners_[0]->AddTaskObserver(&observer);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
   runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
 
@@ -868,7 +870,7 @@
   runners_[0]->AddTaskObserver(&observer);
   runners_[0]->RemoveTaskObserver(&observer);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
 
   EXPECT_CALL(observer, WillProcessTask(_)).Times(0);
@@ -1082,51 +1084,47 @@
 
 void ExpensiveTestTask(int value,
                        base::SimpleTestTickClock* clock,
-                       std::vector<int>* out_result) {
+                       std::vector<EnqueueOrder>* out_result) {
   out_result->push_back(value);
   clock->Advance(base::TimeDelta::FromMilliseconds(1));
 }
 
-TEST_F(TaskQueueManagerTest, ImmediateAndDelayedTaskRoundRobbin) {
+TEST_F(TaskQueueManagerTest, ImmediateAndDelayedTaskInterleaving) {
   Initialize(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> 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);
+  for (int i = 10; i < 19; i++) {
+    runners_[0]->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&ExpensiveTestTask, i, 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));
+  for (int i = 0; i < 9; i++) {
+    runners_[0]->PostTask(
+        FROM_HERE,
+        base::Bind(&ExpensiveTestTask, i, 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));
+  // Delayed tasks are not allowed to starve out immediate work which is why
+  // some of the immediate tasks run out of order.
+  int expected_run_order[] = {
+    10, 11, 12, 13, 0, 14, 15, 16, 1, 17, 18, 2, 3, 4, 5, 6, 7, 8
+  };
+  EXPECT_THAT(run_order, ElementsAreArray(expected_run_order));
 }
 
 TEST_F(TaskQueueManagerTest,
        DelayedTaskDoesNotSkipAHeadOfNonDelayedTask_SameQueue) {
   Initialize(1u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> 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));
@@ -1143,7 +1141,7 @@
        DelayedTaskDoesNotSkipAHeadOfNonDelayedTask_DifferentQueues) {
   Initialize(2u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
   runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
   runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
@@ -1159,7 +1157,7 @@
 TEST_F(TaskQueueManagerTest, DelayedTaskDoesNotSkipAHeadOfShorterDelayedTask) {
   Initialize(2u);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(10);
   base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(5);
   runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
@@ -1213,10 +1211,12 @@
     sequence_numbers_.push_back(pending_task.sequence_num);
   }
 
-  const std::vector<int>& sequence_numbers() const { return sequence_numbers_; }
+  const std::vector<EnqueueOrder>& sequence_numbers() const {
+    return sequence_numbers_;
+  }
 
  private:
-  std::vector<int> sequence_numbers_;
+  std::vector<EnqueueOrder> sequence_numbers_;
 };
 
 TEST_F(TaskQueueManagerTest, SequenceNumSetWhenTaskIsPosted) {
@@ -1226,7 +1226,7 @@
   manager_->AddTaskObserver(&observer);
 
   // Register four tasks that will run in reverse order.
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
                                base::TimeDelta::FromMilliseconds(30));
   runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order),
@@ -1260,7 +1260,7 @@
   ASSERT_NE(queue1, queue3);
   ASSERT_NE(queue2, queue3);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   queue1->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
   queue2->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
   queue3->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
@@ -1283,7 +1283,7 @@
   ASSERT_NE(queue1, queue3);
   ASSERT_NE(queue2, queue3);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   queue1->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
   queue2->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
   queue3->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
@@ -1298,7 +1298,7 @@
   Initialize(2u);
 
   // Register three delayed tasks
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
                                base::TimeDelta::FromMilliseconds(10));
   runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order),
@@ -1317,7 +1317,7 @@
     base::MessageLoop* message_loop,
     scoped_refptr<base::SingleThreadTaskRunner> main_runner,
     scoped_refptr<base::SingleThreadTaskRunner> wake_up_runner,
-    std::vector<int>* run_order) {
+    std::vector<EnqueueOrder>* run_order) {
   base::MessageLoop::ScopedNestableTaskAllower allow(message_loop);
   main_runner->PostNonNestableTask(FROM_HERE,
                                    base::Bind(&TestTask, 1, run_order));
@@ -1332,7 +1332,7 @@
   InitializeWithRealMessageLoop(2u);
   runners_[1]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP);
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostTask(
       FROM_HERE,
       base::Bind(&PostTestTasksFromNestedMessageLoop, message_loop_.get(),
@@ -1426,7 +1426,7 @@
   runners_[0]->SetTimeDomain(domain_a.get());
   runners_[1]->SetTimeDomain(domain_b.get());
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
                                base::TimeDelta::FromMilliseconds(10));
   runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order),
@@ -1466,7 +1466,7 @@
   manager_->RegisterTimeDomain(domain_a.get());
   runners_[0]->SetTimeDomain(domain_a.get());
 
-  std::vector<int> run_order;
+  std::vector<EnqueueOrder> run_order;
   runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
                                base::TimeDelta::FromMilliseconds(10));
   runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order),
@@ -1593,7 +1593,8 @@
 
 }  // namespace
 
-TEST_F(TaskQueueManagerTest, DelayedTasksDontStarveNonDelayedWork_SameQueue) {
+TEST_F(TaskQueueManagerTest,
+       DelayedTasksDontBadlyStarveNonDelayedWork_SameQueue) {
   Initialize(1u);
 
   QuadraticTask quadratic_delayed_task(
@@ -1614,7 +1615,7 @@
   double ratio = static_cast<double>(linear_immediate_task.count()) /
                  static_cast<double>(quadratic_delayed_task.count());
 
-  EXPECT_GT(ratio, 0.9);
+  EXPECT_GT(ratio, 0.333);
   EXPECT_LT(ratio, 1.1);
 }
 
@@ -1647,7 +1648,7 @@
 }
 
 TEST_F(TaskQueueManagerTest,
-       DelayedTasksDontStarveNonDelayedWork_DifferentQueue) {
+       DelayedTasksDontBadlyStarveNonDelayedWork_DifferentQueue) {
   Initialize(2u);
 
   QuadraticTask quadratic_delayed_task(
@@ -1668,7 +1669,7 @@
   double ratio = static_cast<double>(linear_immediate_task.count()) /
                  static_cast<double>(quadratic_delayed_task.count());
 
-  EXPECT_GT(ratio, 0.9);
+  EXPECT_GT(ratio, 0.333);
   EXPECT_LT(ratio, 1.1);
 }
 
diff --git a/components/scheduler/base/task_queue_selector.cc b/components/scheduler/base/task_queue_selector.cc
index c72c33a3..b064bd6 100644
--- a/components/scheduler/base/task_queue_selector.cc
+++ b/components/scheduler/base/task_queue_selector.cc
@@ -15,8 +15,8 @@
 TaskQueueSelector::TaskQueueSelector()
     : delayed_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT),
       immediate_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT),
-      force_select_immediate_(true),
-      starvation_count_(0),
+      immediate_starvation_count_(0),
+      high_priority_starvation_count_(0),
       task_queue_selector_observer_(nullptr) {}
 
 TaskQueueSelector::~TaskQueueSelector() {}
@@ -81,6 +81,7 @@
 
 bool TaskQueueSelector::ChooseOldestImmediateOrDelayedTaskWithPriority(
     TaskQueue::QueuePriority priority,
+    bool* out_chose_delayed_over_immediate,
     WorkQueue** out_work_queue) const {
   WorkQueue* immediate_queue;
   if (immediate_work_queue_sets_.GetOldestQueueInSet(priority,
@@ -88,8 +89,8 @@
     WorkQueue* delayed_queue;
     if (delayed_work_queue_sets_.GetOldestQueueInSet(priority,
                                                      &delayed_queue)) {
-      int immediate_enqueue_order;
-      int delayed_enqueue_order;
+      EnqueueOrder immediate_enqueue_order;
+      EnqueueOrder delayed_enqueue_order;
       bool have_immediate_task =
           immediate_queue->GetFrontTaskEnqueueOrder(&immediate_enqueue_order);
       bool have_delayed_task =
@@ -99,6 +100,7 @@
       if (immediate_enqueue_order < delayed_enqueue_order) {
         *out_work_queue = immediate_queue;
       } else {
+        *out_chose_delayed_over_immediate = true;
         *out_work_queue = delayed_queue;
       }
     } else {
@@ -117,8 +119,10 @@
 
 bool TaskQueueSelector::ChooseOldestWithPriority(
     TaskQueue::QueuePriority priority,
+    bool* out_chose_delayed_over_immediate,
     WorkQueue** out_work_queue) const {
-  if (force_select_immediate_) {
+  // Select an immediate work queue if we are starving immediate tasks.
+  if (immediate_starvation_count_ >= kMaxDelayedStarvationTasks) {
     if (ChooseOldestImmediateTaskWithPriority(priority, out_work_queue)) {
       return true;
     }
@@ -127,31 +131,36 @@
     }
     return false;
   } else {
-    return ChooseOldestImmediateOrDelayedTaskWithPriority(priority,
-                                                          out_work_queue);
+    return ChooseOldestImmediateOrDelayedTaskWithPriority(
+        priority, out_chose_delayed_over_immediate, out_work_queue);
   }
 }
 
 bool TaskQueueSelector::SelectWorkQueueToService(WorkQueue** out_work_queue) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
-  force_select_immediate_ = !force_select_immediate_;
+  bool chose_delayed_over_immediate = false;
   // Always service the control queue if it has any work.
-  if (ChooseOldestWithPriority(TaskQueue::CONTROL_PRIORITY, out_work_queue)) {
-    DidSelectQueueWithPriority(TaskQueue::CONTROL_PRIORITY);
+  if (ChooseOldestWithPriority(TaskQueue::CONTROL_PRIORITY,
+                               &chose_delayed_over_immediate, out_work_queue)) {
+    DidSelectQueueWithPriority(TaskQueue::CONTROL_PRIORITY,
+                               chose_delayed_over_immediate);
     return true;
   }
   // Select from the normal priority queue if we are starving it.
-  if (starvation_count_ >= kMaxStarvationTasks &&
-      ChooseOldestWithPriority(TaskQueue::NORMAL_PRIORITY, out_work_queue)) {
-    DidSelectQueueWithPriority(TaskQueue::NORMAL_PRIORITY);
+  if (high_priority_starvation_count_ >= kMaxHighPriorityStarvationTasks &&
+      ChooseOldestWithPriority(TaskQueue::NORMAL_PRIORITY,
+                               &chose_delayed_over_immediate, out_work_queue)) {
+    DidSelectQueueWithPriority(TaskQueue::NORMAL_PRIORITY,
+                               chose_delayed_over_immediate);
     return true;
   }
   // Otherwise choose in priority order.
   for (TaskQueue::QueuePriority priority = TaskQueue::HIGH_PRIORITY;
        priority < TaskQueue::DISABLED_PRIORITY;
        priority = NextPriority(priority)) {
-    if (ChooseOldestWithPriority(priority, out_work_queue)) {
-      DidSelectQueueWithPriority(priority);
+    if (ChooseOldestWithPriority(priority, &chose_delayed_over_immediate,
+                                 out_work_queue)) {
+      DidSelectQueueWithPriority(priority, chose_delayed_over_immediate);
       return true;
     }
   }
@@ -159,27 +168,34 @@
 }
 
 void TaskQueueSelector::DidSelectQueueWithPriority(
-    TaskQueue::QueuePriority priority) {
+    TaskQueue::QueuePriority priority,
+    bool chose_delayed_over_immediate) {
   switch (priority) {
     case TaskQueue::CONTROL_PRIORITY:
       break;
     case TaskQueue::HIGH_PRIORITY:
-      starvation_count_++;
+      high_priority_starvation_count_++;
       break;
     case TaskQueue::NORMAL_PRIORITY:
     case TaskQueue::BEST_EFFORT_PRIORITY:
-      starvation_count_ = 0;
+      high_priority_starvation_count_ = 0;
       break;
     default:
       NOTREACHED();
   }
+  if (chose_delayed_over_immediate) {
+    immediate_starvation_count_++;
+  } else {
+    immediate_starvation_count_ = 0;
+  }
 }
 
 void TaskQueueSelector::AsValueInto(
     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_);
+  state->SetInteger("high_priority_starvation_count",
+                    high_priority_starvation_count_);
+  state->SetInteger("immediate_starvation_count", immediate_starvation_count_);
 }
 
 void TaskQueueSelector::SetTaskQueueSelectorObserver(Observer* observer) {
@@ -198,9 +214,9 @@
   return true;
 }
 
-void TaskQueueSelector::SetForceSelectImmediateForTest(
-    bool force_select_immediate) {
-  force_select_immediate_ = force_select_immediate;
+void TaskQueueSelector::SetImmediateStarvationCountForTest(
+    size_t immediate_starvation_count) {
+  immediate_starvation_count_ = immediate_starvation_count;
 }
 
 }  // namespace internal
diff --git a/components/scheduler/base/task_queue_selector.h b/components/scheduler/base/task_queue_selector.h
index 2093528..c594657 100644
--- a/components/scheduler/base/task_queue_selector.h
+++ b/components/scheduler/base/task_queue_selector.h
@@ -72,11 +72,15 @@
  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.
+  // priority are empty. In addition |out_chose_delayed_over_immediate| is set
+  // to true iff we chose a delayed work queue in favour of an immediate work
+  // queue.  This method will force select an immediate task if those are being
+  // starved by delayed tasks.
   bool ChooseOldestWithPriority(TaskQueue::QueuePriority priority,
+                                bool* out_chose_delayed_over_immediate,
                                 WorkQueue** out_work_queue) const;
 
-  void SetForceSelectImmediateForTest(bool force_select_immediate);
+  void SetImmediateStarvationCountForTest(size_t immediate_starvation_count);
 
  private:
   // Returns the priority which is next after |priority|.
@@ -89,26 +93,36 @@
   bool ChooseOldestDelayedTaskWithPriority(TaskQueue::QueuePriority priority,
                                            WorkQueue** out_work_queue) const;
 
+  // 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. In addition |out_chose_delayed_over_immediate| is set
+  // to true iff we chose a delayed work queue in favour of an immediate work
+  // queue.
   bool ChooseOldestImmediateOrDelayedTaskWithPriority(
       TaskQueue::QueuePriority priority,
+      bool* out_chose_delayed_over_immediate,
       WorkQueue** out_work_queue) const;
 
   // Called whenever the selector chooses a task queue for execution with the
   // priority |priority|.
-  void DidSelectQueueWithPriority(TaskQueue::QueuePriority priority);
+  void DidSelectQueueWithPriority(TaskQueue::QueuePriority priority,
+                                  bool chose_delayed_over_immediate);
 
   // Number of high priority tasks which can be run before a normal priority
   // task should be selected to prevent starvation.
   // TODO(rmcilroy): Check if this is a good value.
-  static const size_t kMaxStarvationTasks = 5;
+  static const size_t kMaxHighPriorityStarvationTasks = 5;
+
+  // Maximum number of delayed tasks tasks which can be run while there's a
+  // waiting non-delayed task.
+  static const size_t kMaxDelayedStarvationTasks = 3;
 
  private:
   base::ThreadChecker main_thread_checker_;
   WorkQueueSets delayed_work_queue_sets_;
   WorkQueueSets immediate_work_queue_sets_;
-  bool force_select_immediate_;
-
-  size_t starvation_count_;
+  size_t immediate_starvation_count_;
+  size_t high_priority_starvation_count_;
   Observer* task_queue_selector_observer_;  // NOT OWNED
   DISALLOW_COPY_AND_ASSIGN(TaskQueueSelector);
 };
diff --git a/components/scheduler/base/task_queue_selector_unittest.cc b/components/scheduler/base/task_queue_selector_unittest.cc
index 6eb4457..ad50960 100644
--- a/components/scheduler/base/task_queue_selector_unittest.cc
+++ b/components/scheduler/base/task_queue_selector_unittest.cc
@@ -33,7 +33,7 @@
 class TaskQueueSelectorForTest : public TaskQueueSelector {
  public:
   using TaskQueueSelector::ChooseOldestWithPriority;
-  using TaskQueueSelector::SetForceSelectImmediateForTest;
+  using TaskQueueSelector::SetImmediateStarvationCountForTest;
 };
 
 class TaskQueueSelectorTest : public testing::Test {
@@ -284,8 +284,11 @@
 
 TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_Empty) {
   WorkQueue* chosen_work_queue = nullptr;
+  bool chose_delayed_over_immediate = false;
   EXPECT_FALSE(selector_.ChooseOldestWithPriority(TaskQueue::NORMAL_PRIORITY,
+                                                  &chose_delayed_over_immediate,
                                                   &chosen_work_queue));
+  EXPECT_FALSE(chose_delayed_over_immediate);
 }
 
 TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_OnlyDelayed) {
@@ -295,9 +298,12 @@
       task_queues_[0]->delayed_work_queue());
 
   WorkQueue* chosen_work_queue = nullptr;
+  bool chose_delayed_over_immediate = false;
   EXPECT_TRUE(selector_.ChooseOldestWithPriority(TaskQueue::NORMAL_PRIORITY,
+                                                 &chose_delayed_over_immediate,
                                                  &chosen_work_queue));
   EXPECT_EQ(chosen_work_queue, task_queues_[0]->delayed_work_queue());
+  EXPECT_FALSE(chose_delayed_over_immediate);
 }
 
 TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_OnlyImmediate) {
@@ -307,24 +313,31 @@
       task_queues_[0]->immediate_work_queue());
 
   WorkQueue* chosen_work_queue = nullptr;
+  bool chose_delayed_over_immediate = false;
   EXPECT_TRUE(selector_.ChooseOldestWithPriority(TaskQueue::NORMAL_PRIORITY,
+                                                 &chose_delayed_over_immediate,
                                                  &chosen_work_queue));
   EXPECT_EQ(chosen_work_queue, task_queues_[0]->immediate_work_queue());
+  EXPECT_FALSE(chose_delayed_over_immediate);
 }
 
 struct ChooseOldestWithPriorityTestParam {
   int delayed_task_enqueue_order;
   int immediate_task_enqueue_order;
-  bool force_select_immediate;
+  int immediate_starvation_count;
   const char* expected_work_queue_name;
+  bool expected_did_starve_immediate_queue;
 };
 
 static const ChooseOldestWithPriorityTestParam
     kChooseOldestWithPriorityTestCases[] = {
-        {1, 2, false, "delayed"},
-        {1, 2, true, "immediate"},
-        {2, 1, false, "immediate"},
-        {2, 1, true, "immediate"},
+        {1, 2, 0, "delayed", true},
+        {1, 2, 1, "delayed", true},
+        {1, 2, 2, "delayed", true},
+        {1, 2, 3, "immediate", false},
+        {1, 2, 4, "immediate", false},
+        {2, 1, 4, "immediate", false},
+        {2, 1, 4, "immediate", false},
 };
 
 class ChooseOldestWithPriorityTest
@@ -346,13 +359,18 @@
   selector_.delayed_task_queue_sets()->OnPushQueue(
       task_queues_[0]->delayed_work_queue());
 
-  selector_.SetForceSelectImmediateForTest(GetParam().force_select_immediate);
+  selector_.SetImmediateStarvationCountForTest(
+      GetParam().immediate_starvation_count);
 
   WorkQueue* chosen_work_queue = nullptr;
+  bool chose_delayed_over_immediate = false;
   EXPECT_TRUE(selector_.ChooseOldestWithPriority(TaskQueue::NORMAL_PRIORITY,
+                                                 &chose_delayed_over_immediate,
                                                  &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);
+  EXPECT_EQ(chose_delayed_over_immediate,
+            GetParam().expected_did_starve_immediate_queue);
 }
 
 INSTANTIATE_TEST_CASE_P(ChooseOldestWithPriorityTest,
diff --git a/components/scheduler/base/work_queue.cc b/components/scheduler/base/work_queue.cc
index 1e46c42b..6b063e0 100644
--- a/components/scheduler/base/work_queue.cc
+++ b/components/scheduler/base/work_queue.cc
@@ -31,7 +31,7 @@
   work_queue_ = std::queue<TaskQueueImpl::Task>();
 }
 
-bool WorkQueue::GetFrontTaskEnqueueOrder(int* enqueue_order) const {
+bool WorkQueue::GetFrontTaskEnqueueOrder(EnqueueOrder* enqueue_order) const {
   if (work_queue_.empty())
     return false;
   *enqueue_order = work_queue_.front().enqueue_order();
@@ -50,7 +50,7 @@
 }
 
 void WorkQueue::PushAndSetEnqueueOrder(const TaskQueueImpl::Task&& task,
-                                       int enqueue_order) {
+                                       EnqueueOrder enqueue_order) {
   bool was_empty = work_queue_.empty();
   work_queue_.push(task);
   work_queue_.back().set_enqueue_order(enqueue_order);
@@ -63,12 +63,12 @@
   work_queue_.pop();
 }
 
-void WorkQueue::Swap(std::queue<TaskQueueImpl::Task>& incoming_queue) {
+void WorkQueue::SwapLocked(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);
+  task_queue_->TraceQueueSize(true);
 }
 
 TaskQueueImpl::Task WorkQueue::TakeTaskFromWorkQueue() {
diff --git a/components/scheduler/base/work_queue.h b/components/scheduler/base/work_queue.h
index 635766f9..fb101f2 100644
--- a/components/scheduler/base/work_queue.h
+++ b/components/scheduler/base/work_queue.h
@@ -9,6 +9,7 @@
 
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
+#include "components/scheduler/base/enqueue_order.h"
 #include "components/scheduler/base/task_queue_impl.h"
 #include "components/scheduler/scheduler_export.h"
 
@@ -34,7 +35,7 @@
   // 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;
+  bool GetFrontTaskEnqueueOrder(EnqueueOrder* enqueue_order) const;
 
   // Pushes the task onto the |work_queue_| and informs the WorkQueueSets if
   // the head changed.
@@ -43,11 +44,12 @@
   // 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);
+                              EnqueueOrder 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);
+  // WorkQueueSets if the head changed. Assumes |task_queue_->any_thread_lock_|
+  // is locked.
+  void SwapLocked(std::queue<TaskQueueImpl::Task>& incoming_queue);
 
   size_t Size() const { return work_queue_.size(); }
 
diff --git a/components/scheduler/base/work_queue_sets.cc b/components/scheduler/base/work_queue_sets.cc
index b4a9d5a9..7b4dc56d 100644
--- a/components/scheduler/base/work_queue_sets.cc
+++ b/components/scheduler/base/work_queue_sets.cc
@@ -16,7 +16,7 @@
 WorkQueueSets::~WorkQueueSets() {}
 
 void WorkQueueSets::RemoveQueue(WorkQueue* work_queue) {
-  int enqueue_order;
+  EnqueueOrder enqueue_order;
   bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order);
   if (!has_enqueue_order)
     return;
@@ -30,7 +30,7 @@
 
 void WorkQueueSets::AssignQueueToSet(WorkQueue* work_queue, size_t set_index) {
   DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size());
-  int enqueue_order;
+  EnqueueOrder 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());
@@ -43,7 +43,7 @@
 }
 
 void WorkQueueSets::OnPushQueue(WorkQueue* work_queue) {
-  int enqueue_order;
+  EnqueueOrder 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();
@@ -64,7 +64,7 @@
   // O(1) amortised.
   enqueue_order_to_work_queue_maps_[set_index].erase(
       enqueue_order_to_work_queue_maps_[set_index].begin());
-  int enqueue_order;
+  EnqueueOrder enqueue_order;
   bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order);
   if (!has_enqueue_order)
     return;
diff --git a/components/scheduler/base/work_queue_sets.h b/components/scheduler/base/work_queue_sets.h
index 9e7c569..fdb6fe4 100644
--- a/components/scheduler/base/work_queue_sets.h
+++ b/components/scheduler/base/work_queue_sets.h
@@ -41,31 +41,7 @@
   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
-    // to preserve the ordering of the map when this happens.
-    // NOTE we assume that tasks don't get starved for extended periods so that
-    // the task queue ages in a set have at most one roll-over.
-    // NOTE signed integer overflow behavior is undefined in C++ so we can't
-    // use the (a - b) < 0 trick here, because the optimizer won't necessarily
-    // do what we expect.
-    // TODO(alexclarke): Consider making age and sequence_num unsigned, because
-    // unsigned integer overflow behavior is defined.
-    bool operator()(int a, int b) const {
-      if (a < 0 && b >= 0)
-        return false;
-      if (b < 0 && a >= 0)
-        return true;
-      return a < b;
-    }
-  };
-
-  typedef std::map<int, WorkQueue*, EnqueueOrderComparitor>
-      EnqueueOrderToWorkQueueMap;
+  typedef std::map<EnqueueOrder, WorkQueue*> EnqueueOrderToWorkQueueMap;
   std::vector<EnqueueOrderToWorkQueueMap> enqueue_order_to_work_queue_maps_;
 
   DISALLOW_COPY_AND_ASSIGN(WorkQueueSets);
diff --git a/components/scheduler/scheduler.gypi b/components/scheduler/scheduler.gypi
index 21ca898..2fb6b2a8 100644
--- a/components/scheduler/scheduler.gypi
+++ b/components/scheduler/scheduler.gypi
@@ -34,6 +34,8 @@
       'base/pollable_thread_safe_flag.h',
       'base/virtual_time_domain.cc',
       'base/virtual_time_domain.h',
+      'base/enqueue_order.h',
+      'base/enqueue_order.cc',
       'child/child_scheduler.h',
       'child/idle_helper.cc',
       'child/idle_helper.h',
diff --git a/components/signin/core/browser/signin_manager_base.cc b/components/signin/core/browser/signin_manager_base.cc
index f18f009..a84f5ef 100644
--- a/components/signin/core/browser/signin_manager_base.cc
+++ b/components/signin/core/browser/signin_manager_base.cc
@@ -57,6 +57,7 @@
   registry->RegisterBooleanPref(prefs::kReverseAutologinEnabled, true);
   registry->RegisterListPref(prefs::kReverseAutologinRejectedEmailList,
                              new base::ListValue);
+  registry->RegisterBooleanPref(prefs::kSigninAllowed, true);
   registry->RegisterInt64Pref(prefs::kSignedInTime,
                               base::Time().ToInternalValue());
 
diff --git a/components/signin/ios/browser/account_consistency_service.mm b/components/signin/ios/browser/account_consistency_service.mm
index 7e6e1a1..22a09265 100644
--- a/components/signin/ios/browser/account_consistency_service.mm
+++ b/components/signin/ios/browser/account_consistency_service.mm
@@ -100,10 +100,12 @@
       [delegate_ onGoIncognito:continue_url];
       break;
     }
-    case signin::GAIA_SERVICE_TYPE_SIGNOUT:
-    case signin::GAIA_SERVICE_TYPE_ADDSESSION:
-    case signin::GAIA_SERVICE_TYPE_REAUTH:
     case signin::GAIA_SERVICE_TYPE_SIGNUP:
+    case signin::GAIA_SERVICE_TYPE_ADDSESSION:
+      [delegate_ onAddAccount];
+      break;
+    case signin::GAIA_SERVICE_TYPE_SIGNOUT:
+    case signin::GAIA_SERVICE_TYPE_REAUTH:
     case signin::GAIA_SERVICE_TYPE_DEFAULT:
       [delegate_ onManageAccounts];
       break;
diff --git a/components/signin/ios/browser/manage_accounts_delegate.h b/components/signin/ios/browser/manage_accounts_delegate.h
index c117c7c..64b7066 100644
--- a/components/signin/ios/browser/manage_accounts_delegate.h
+++ b/components/signin/ios/browser/manage_accounts_delegate.h
@@ -13,6 +13,9 @@
 // property.
 - (void)onManageAccounts;
 
+// Called when the user taps on an add account button in a Google web property.
+- (void)onAddAccount;
+
 // Called when the user taps on go incognito button in a Google web property.
 // |url| is the continuation URL received from the server. If it is valid,
 // then this delegate should open an incognito tab and navigate to |url|.
diff --git a/components/startup_metric_utils/browser/startup_metric_utils.cc b/components/startup_metric_utils/browser/startup_metric_utils.cc
index 9fd7d91..c916e50 100644
--- a/components/startup_metric_utils/browser/startup_metric_utils.cc
+++ b/components/startup_metric_utils/browser/startup_metric_utils.cc
@@ -16,6 +16,7 @@
 
 #if defined(OS_WIN)
 #include <winternl.h>
+#include "base/win/win_util.h"
 #include "base/win/windows_version.h"
 #endif
 
@@ -146,7 +147,7 @@
     DCHECK_LE(index + sizeof(SYSTEM_PROCESS_INFORMATION_EX), buffer.size());
     SYSTEM_PROCESS_INFORMATION_EX* proc_info =
         reinterpret_cast<SYSTEM_PROCESS_INFORMATION_EX*>(buffer.data() + index);
-    if (reinterpret_cast<DWORD>(proc_info->UniqueProcessId) == proc_id) {
+    if (base::win::HandleToUint32(proc_info->UniqueProcessId) == proc_id) {
       *hard_fault_count = proc_info->HardFaultCount;
       return true;
     }
diff --git a/components/storage_monitor/storage_monitor_linux.cc b/components/storage_monitor/storage_monitor_linux.cc
index 061ffdf..a97b92e5 100644
--- a/components/storage_monitor/storage_monitor_linux.cc
+++ b/components/storage_monitor/storage_monitor_linux.cc
@@ -7,11 +7,12 @@
 #include "components/storage_monitor/storage_monitor_linux.h"
 
 #include <mntent.h>
+#include <stdint.h>
 #include <stdio.h>
 
+#include <limits>
 #include <list>
 
-#include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/metrics/histogram.h"
 #include "base/process/kill.h"
@@ -97,8 +98,8 @@
 
 // Returns the storage partition size of the device specified by |device_path|.
 // If the requested information is unavailable, returns 0.
-uint64 GetDeviceStorageSize(const base::FilePath& device_path,
-                            struct udev_device* device) {
+uint64_t GetDeviceStorageSize(const base::FilePath& device_path,
+                              struct udev_device* device) {
   // sysfs provides the device size in units of 512-byte blocks.
   const std::string partition_size =
       device::UdevDeviceGetSysattrValue(device, kSizeSysAttr);
@@ -109,11 +110,12 @@
       "RemovableDeviceNotificationsLinux.device_partition_size_available",
       !partition_size.empty());
 
-  uint64 total_size_in_bytes = 0;
+  uint64_t total_size_in_bytes = 0;
   if (!base::StringToUint64(partition_size, &total_size_in_bytes))
     return 0;
-  return (total_size_in_bytes <= kuint64max / 512) ?
-      total_size_in_bytes * 512 : 0;
+  return (total_size_in_bytes <= std::numeric_limits<uint64_t>::max() / 512)
+             ? total_size_in_bytes * 512
+             : 0;
 }
 
 // Gets the device information using udev library.
diff --git a/components/storage_monitor/storage_monitor_linux.h b/components/storage_monitor/storage_monitor_linux.h
index c8ff79a..5a01230 100644
--- a/components/storage_monitor/storage_monitor_linux.h
+++ b/components/storage_monitor/storage_monitor_linux.h
@@ -18,10 +18,10 @@
 #include <map>
 #include <string>
 
-#include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/files/file_path_watcher.h"
+#include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "components/storage_monitor/mtab_watcher_linux.h"
diff --git a/components/sync_driver/BUILD.gn b/components/sync_driver/BUILD.gn
index 38b89a8..b64b46e 100644
--- a/components/sync_driver/BUILD.gn
+++ b/components/sync_driver/BUILD.gn
@@ -208,6 +208,7 @@
   testonly = true
   sources = [
     "about_sync_util_unittest.cc",
+    "backend_migrator_unittest.cc",
     "backup_rollback_controller_unittest.cc",
     "data_type_manager_impl_unittest.cc",
     "device_info_data_type_controller_unittest.cc",
@@ -223,7 +224,9 @@
     "non_blocking_data_type_controller_unittest.cc",
     "non_frontend_data_type_controller_unittest.cc",
     "non_ui_data_type_controller_unittest.cc",
+    "profile_sync_auth_provider_unittest.cc",
     "shared_change_processor_unittest.cc",
+    "startup_controller_unittest.cc",
     "sync_prefs_unittest.cc",
     "sync_stopped_reporter_unittest.cc",
     "sync_util_unittest.cc",
@@ -237,6 +240,9 @@
     "//base/test:test_support",
     "//components/os_crypt",
     "//components/pref_registry:test_support",
+    "//components/signin/core/browser:test_support",
+    "//components/syncable_prefs",
+    "//components/syncable_prefs:test_support",
     "//components/version_info",
     "//net:test_support",
     "//sync:test_support_sync_api",
diff --git a/components/sync_driver/DEPS b/components/sync_driver/DEPS
index 6728eca4..7703b9e 100644
--- a/components/sync_driver/DEPS
+++ b/components/sync_driver/DEPS
@@ -7,6 +7,7 @@
   "+components/policy",
   "+components/pref_registry",
   "+components/signin/core/browser",
+  "+components/syncable_prefs",
   "+components/version_info",
   "+google",
   "+google_apis",
diff --git a/chrome/browser/sync/backend_migrator_unittest.cc b/components/sync_driver/backend_migrator_unittest.cc
similarity index 94%
rename from chrome/browser/sync/backend_migrator_unittest.cc
rename to components/sync_driver/backend_migrator_unittest.cc
index f700c10..4170ab26 100644
--- a/chrome/browser/sync/backend_migrator_unittest.cc
+++ b/components/sync_driver/backend_migrator_unittest.cc
@@ -7,10 +7,8 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/tracked_objects.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/sync/profile_sync_service_mock.h"
 #include "components/sync_driver/data_type_manager_mock.h"
-#include "content/public/test/test_browser_thread_bundle.h"
+#include "components/sync_driver/fake_sync_service.h"
 #include "sync/internal_api/public/base/model_type_test_util.h"
 #include "sync/internal_api/public/test/test_user_share.h"
 #include "sync/internal_api/public/write_transaction.h"
@@ -33,20 +31,16 @@
 
 class SyncBackendMigratorTest : public testing::Test {
  public:
-  SyncBackendMigratorTest() : service_(&profile_) { }
+  SyncBackendMigratorTest() { }
   virtual ~SyncBackendMigratorTest() { }
 
   virtual void SetUp() {
     test_user_share_.SetUp();
     Mock::VerifyAndClear(manager());
-    Mock::VerifyAndClear(&service_);
     preferred_types_.Put(syncer::BOOKMARKS);
     preferred_types_.Put(syncer::PREFERENCES);
     preferred_types_.Put(syncer::AUTOFILL);
 
-    ON_CALL(service_, GetPreferredDataTypes()).
-        WillByDefault(Return(preferred_types_));
-
     migrator_.reset(
         new BackendMigrator(
             "Profile0", test_user_share_.user_share(), service(), manager(),
@@ -90,22 +84,18 @@
     run_loop.RunUntilIdle();
   }
 
-  ProfileSyncService* service() { return &service_; }
+  sync_driver::SyncService* service() { return &service_; }
   DataTypeManagerMock* manager() { return &manager_; }
   syncer::ModelTypeSet preferred_types() { return preferred_types_; }
   BackendMigrator* migrator() { return migrator_.get(); }
   void RemovePreferredType(syncer::ModelType type) {
     preferred_types_.Remove(type);
-    Mock::VerifyAndClear(&service_);
-    ON_CALL(service_, GetPreferredDataTypes()).
-        WillByDefault(Return(preferred_types_));
   }
 
  private:
-  content::TestBrowserThreadBundle thread_bundle_;
+  base::MessageLoop message_loop_;
   syncer::ModelTypeSet preferred_types_;
-  TestingProfile profile_;
-  NiceMock<ProfileSyncServiceMock> service_;
+  sync_driver::FakeSyncService service_;
   NiceMock<DataTypeManagerMock> manager_;
   syncer::TestUserShare test_user_share_;
   scoped_ptr<BackendMigrator> migrator_;
diff --git a/chrome/browser/sync/profile_sync_auth_provider_unittest.cc b/components/sync_driver/profile_sync_auth_provider_unittest.cc
similarity index 66%
rename from chrome/browser/sync/profile_sync_auth_provider_unittest.cc
rename to components/sync_driver/profile_sync_auth_provider_unittest.cc
index 7a06d79..cb9ea96 100644
--- a/chrome/browser/sync/profile_sync_auth_provider_unittest.cc
+++ b/components/sync_driver/profile_sync_auth_provider_unittest.cc
@@ -3,18 +3,10 @@
 // found in the LICENSE file.
 
 #include "base/run_loop.h"
-#include "chrome/browser/signin/account_fetcher_service_factory.h"
-#include "chrome/browser/signin/chrome_signin_client_factory.h"
-#include "chrome/browser/signin/fake_account_fetcher_service_builder.h"
-#include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "chrome/browser/signin/test_signin_client_builder.h"
-#include "chrome/test/base/testing_profile.h"
 #include "components/signin/core/browser/fake_account_fetcher_service.h"
 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/sync_driver/profile_sync_auth_provider.h"
-#include "content/public/test/test_browser_thread_bundle.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -28,23 +20,13 @@
   ~ProfileSyncAuthProviderTest() override {}
 
   void SetUp() override {
-    TestingProfile::Builder builder;
-    builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
-                              &BuildAutoIssuingFakeProfileOAuth2TokenService);
-    builder.AddTestingFactory(AccountFetcherServiceFactory::GetInstance(),
-                              FakeAccountFetcherServiceBuilder::BuildForTests);
-    builder.AddTestingFactory(ChromeSigninClientFactory::GetInstance(),
-                              signin::BuildTestSigninClient);
-
-    profile_ = builder.Build();
-
-    FakeProfileOAuth2TokenService* token_service =
-        (FakeProfileOAuth2TokenService*)
-        ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get());
-    token_service->UpdateCredentials(kAccountId, "fake_refresh_token");
+    token_service_.reset(new FakeProfileOAuth2TokenService());
+    token_service_->set_auto_post_fetch_response_on_message_loop(true);
+    token_service_->UpdateCredentials(kAccountId, "fake_refresh_token");
 
     auth_provider_frontend_.reset(new ProfileSyncAuthProvider(
-        token_service, kAccountId, GaiaConstants::kChromeSyncOAuth2Scope));
+        token_service_.get(), kAccountId,
+        GaiaConstants::kChromeSyncOAuth2Scope));
     auth_provider_backend_ =
         auth_provider_frontend_->CreateProviderForSyncThread().Pass();
   }
@@ -56,9 +38,9 @@
   }
 
  protected:
-  content::TestBrowserThreadBundle thread_bundle_;
-  scoped_ptr<Profile> profile_;
+  base::MessageLoop message_loop_;
 
+  scoped_ptr<FakeProfileOAuth2TokenService> token_service_;
   scoped_ptr<ProfileSyncAuthProvider> auth_provider_frontend_;
   scoped_ptr<syncer::SyncAuthProvider> auth_provider_backend_;
 
diff --git a/chrome/browser/sync/startup_controller_unittest.cc b/components/sync_driver/startup_controller_unittest.cc
similarity index 86%
rename from chrome/browser/sync/startup_controller_unittest.cc
rename to components/sync_driver/startup_controller_unittest.cc
index 5934976..0999a96 100644
--- a/chrome/browser/sync/startup_controller_unittest.cc
+++ b/components/sync_driver/startup_controller_unittest.cc
@@ -8,15 +8,11 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/time/time.h"
-#include "chrome/browser/defaults.h"
-#include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "chrome/browser/sync/supervised_user_signin_manager_wrapper.h"
-#include "chrome/test/base/testing_profile.h"
 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
+#include "components/sync_driver/signin_manager_wrapper.h"
 #include "components/sync_driver/sync_driver_switches.h"
 #include "components/sync_driver/sync_prefs.h"
-#include "content/public/test/test_browser_thread_bundle.h"
+#include "components/syncable_prefs/testing_pref_service_syncable.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace browser_sync {
@@ -50,22 +46,12 @@
   StartupControllerTest() : started_(false) {}
 
   void SetUp() override {
-    profile_.reset(new TestingProfile());
-    sync_prefs_.reset(new sync_driver::SyncPrefs(profile_->GetPrefs()));
-    token_service_.reset(static_cast<FakeProfileOAuth2TokenService*>(
-        BuildFakeProfileOAuth2TokenService(profile_.get()).release()));
+    sync_driver::SyncPrefs::RegisterProfilePrefs(pref_service_.registry());
+    sync_prefs_.reset(new sync_driver::SyncPrefs(&pref_service_));
+    token_service_.reset(new FakeProfileOAuth2TokenService());
     signin_.reset(new FakeSigninManagerWrapper());
 
-    ProfileSyncServiceStartBehavior behavior =
-        browser_defaults::kSyncAutoStarts ? AUTO_START : MANUAL_START;
-    base::Closure fake_start_backend = base::Bind(
-        &StartupControllerTest::FakeStartBackend, base::Unretained(this));
-    controller_.reset(new StartupController(behavior, token_service(),
-                                            sync_prefs_.get(), signin_.get(),
-                                            fake_start_backend));
-    controller_->Reset(syncer::UserTypes());
-    controller_->OverrideFallbackTimeoutForTest(
-        base::TimeDelta::FromSeconds(0));
+    SetUpController(AUTO_START);
   }
 
   void TearDown() override {
@@ -77,6 +63,18 @@
     started_ = false;
   }
 
+  void SetUpController(ProfileSyncServiceStartBehavior start_behavior) {
+    started_ = false;
+    base::Closure fake_start_backend = base::Bind(
+        &StartupControllerTest::FakeStartBackend, base::Unretained(this));
+    controller_.reset(new StartupController(start_behavior, token_service(),
+                                            sync_prefs_.get(), signin_.get(),
+                                            fake_start_backend));
+    controller_->Reset(syncer::UserTypes());
+    controller_->OverrideFallbackTimeoutForTest(
+        base::TimeDelta::FromSeconds(0));
+  }
+
   void FakeStartBackend() {
     started_ = true;
   }
@@ -89,16 +87,15 @@
     return token_service_.get();
   }
   sync_driver::SyncPrefs* sync_prefs() { return sync_prefs_.get(); }
-  Profile* profile() { return profile_.get(); }
 
  private:
   bool started_;
-  content::TestBrowserThreadBundle thread_bundle_;
+  base::MessageLoop message_loop_;
+  syncable_prefs::TestingPrefServiceSyncable pref_service_;
   scoped_ptr<StartupController> controller_;
   scoped_ptr<FakeSigninManagerWrapper> signin_;
   scoped_ptr<FakeProfileOAuth2TokenService> token_service_;
   scoped_ptr<sync_driver::SyncPrefs> sync_prefs_;
-  scoped_ptr<TestingProfile> profile_;
 };
 
 // Test that sync doesn't start until all conditions are met.
@@ -208,20 +205,26 @@
   EXPECT_FALSE(started());
 }
 
-// Test that sync starts when the user first asks to setup sync (which
-// may be implicit due to the platform).
-TEST_F(StartupControllerTest, FirstSetup) {
+// Test that sync starts without the user having to explicitly ask for
+// setup when AUTO_START is the startup behavior requested.
+TEST_F(StartupControllerTest, FirstSetupWithAutoStart) {
   signin()->set_account(kTestUser);
   token_service()->UpdateCredentials(kTestUser, kTestToken);
   controller()->TryStart();
+  EXPECT_TRUE(started());
+}
 
-  if (browser_defaults::kSyncAutoStarts) {
-    EXPECT_TRUE(started());
-  } else {
-    controller()->set_setup_in_progress(true);
-    controller()->TryStart();
-    EXPECT_TRUE(started());
-  }
+// Test that sync starts only after user explicitly asks for setup when
+// MANUAL_START is the startup behavior requested.
+TEST_F(StartupControllerTest, FirstSetupWithManualStart) {
+  signin()->set_account(kTestUser);
+  token_service()->UpdateCredentials(kTestUser, kTestToken);
+  SetUpController(MANUAL_START);
+  controller()->TryStart();
+  EXPECT_FALSE(started());
+  controller()->set_setup_in_progress(true);
+  controller()->TryStart();
+  EXPECT_TRUE(started());
 }
 
 TEST_F(StartupControllerTest, Reset) {
diff --git a/components/translate/core/browser/options_menu_model.cc b/components/translate/core/browser/options_menu_model.cc
index 4bb07c2d..f5eeb1b 100644
--- a/components/translate/core/browser/options_menu_model.cc
+++ b/components/translate/core/browser/options_menu_model.cc
@@ -29,14 +29,13 @@
   // |translate_delegate| must already be owned.
   DCHECK(translate_infobar_delegate_->GetTranslateDriver());
 
-  base::string16 original_language = translate_delegate->language_name_at(
-      translate_delegate->original_language_index());
-  base::string16 target_language = translate_delegate->language_name_at(
-      translate_delegate->target_language_index());
+  base::string16 original_language =
+      translate_delegate->original_language_name();
+  base::string16 target_language = translate_delegate->target_language_name();
 
   bool autodetermined_source_language =
-      translate_delegate->original_language_index() ==
-      TranslateInfoBarDelegate::kNoIndex;
+      (translate_delegate->original_language_code() ==
+       translate::kUnknownLanguageCode);
 
   // Populate the menu.
   // Incognito mode does not get any preferences related items.
diff --git a/components/translate/core/browser/translate_infobar_delegate.cc b/components/translate/core/browser/translate_infobar_delegate.cc
index 1332ae0..605bf49b 100644
--- a/components/translate/core/browser/translate_infobar_delegate.cc
+++ b/components/translate/core/browser/translate_infobar_delegate.cc
@@ -109,14 +109,14 @@
     infobar_manager->AddInfoBar(infobar.Pass());
 }
 
-void TranslateInfoBarDelegate::UpdateOriginalLanguageIndex(
-    size_t language_index) {
-  ui_delegate_.UpdateOriginalLanguageIndex(language_index);
+void TranslateInfoBarDelegate::UpdateOriginalLanguage(
+    const std::string& language_code) {
+  ui_delegate_.UpdateOriginalLanguage(language_code);
 }
 
-void TranslateInfoBarDelegate::UpdateTargetLanguageIndex(
-    size_t language_index) {
-  ui_delegate_.UpdateTargetLanguageIndex(language_index);
+void TranslateInfoBarDelegate::UpdateTargetLanguage(
+    const std::string& language_code) {
+  ui_delegate_.UpdateTargetLanguage(language_code);
 }
 
 void TranslateInfoBarDelegate::Translate() {
@@ -190,10 +190,8 @@
 
 base::string16 TranslateInfoBarDelegate::GetMessageInfoBarText() {
   if (step_ == translate::TRANSLATE_STEP_TRANSLATING) {
-    base::string16 target_language_name =
-        language_name_at(target_language_index());
     return l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_TRANSLATING_TO,
-                                      target_language_name);
+                                      target_language_name());
   }
 
   DCHECK_EQ(translate::TRANSLATE_STEP_TRANSLATE_ERROR, step_);
@@ -215,11 +213,10 @@
     case TranslateErrors::UNSUPPORTED_LANGUAGE:
       return l10n_util::GetStringFUTF16(
           IDS_TRANSLATE_INFOBAR_UNSUPPORTED_PAGE_LANGUAGE,
-          language_name_at(target_language_index()));
+          target_language_name());
     case TranslateErrors::IDENTICAL_LANGUAGES:
       return l10n_util::GetStringFUTF16(
-          IDS_TRANSLATE_INFOBAR_ERROR_SAME_LANGUAGE,
-          language_name_at(target_language_index()));
+          IDS_TRANSLATE_INFOBAR_ERROR_SAME_LANGUAGE, target_language_name());
     default:
       NOTREACHED();
       return base::string16();
diff --git a/components/translate/core/browser/translate_infobar_delegate.h b/components/translate/core/browser/translate_infobar_delegate.h
index 83d69815..671ed5c0d 100644
--- a/components/translate/core/browser/translate_infobar_delegate.h
+++ b/components/translate/core/browser/translate_infobar_delegate.h
@@ -83,24 +83,26 @@
 
   TranslateErrors::Type error_type() const { return error_type_; }
 
-  size_t original_language_index() const {
-    return ui_delegate_.GetOriginalLanguageIndex();
-  }
-  void UpdateOriginalLanguageIndex(size_t language_index);
-
-  size_t target_language_index() const {
-    return ui_delegate_.GetTargetLanguageIndex();
-  }
-  void UpdateTargetLanguageIndex(size_t language_index);
-
-  // Convenience methods.
   std::string original_language_code() const {
     return ui_delegate_.GetOriginalLanguageCode();
   }
+
+  base::string16 original_language_name() const {
+    return language_name_at(ui_delegate_.GetOriginalLanguageIndex());
+  }
+
+  void UpdateOriginalLanguage(const std::string& language_code);
+
   std::string target_language_code() const {
     return ui_delegate_.GetTargetLanguageCode();
   }
 
+  base::string16 target_language_name() const {
+    return language_name_at(ui_delegate_.GetTargetLanguageIndex());
+  }
+
+  void UpdateTargetLanguage(const std::string& language_code);
+
   // Returns true if the current infobar indicates an error (in which case it
   // should get a yellow background instead of a blue one).
   bool is_error() const {
diff --git a/components/translate/core/browser/translate_ui_delegate.cc b/components/translate/core/browser/translate_ui_delegate.cc
index d1912dc..3896565 100644
--- a/components/translate/core/browser/translate_ui_delegate.cc
+++ b/components/translate/core/browser/translate_ui_delegate.cc
@@ -144,6 +144,16 @@
   original_language_index_ = language_index;
 }
 
+void TranslateUIDelegate::UpdateOriginalLanguage(
+    const std::string& language_code) {
+  for (size_t i = 0; i < languages_.size(); ++i) {
+    if (languages_[i].first.compare(language_code) == 0) {
+      UpdateOriginalLanguageIndex(i);
+      return;
+    }
+  }
+}
+
 size_t TranslateUIDelegate::GetTargetLanguageIndex() const {
   return target_language_index_;
 }
@@ -157,6 +167,16 @@
   target_language_index_ = language_index;
 }
 
+void TranslateUIDelegate::UpdateTargetLanguage(
+    const std::string& language_code) {
+  for (size_t i = 0; i < languages_.size(); ++i) {
+    if (languages_[i].first.compare(language_code) == 0) {
+      UpdateTargetLanguageIndex(i);
+      return;
+    }
+  }
+}
+
 std::string TranslateUIDelegate::GetLanguageCodeAt(size_t index) const {
   DCHECK_LT(index, GetNumberOfLanguages());
   return languages_[index].first;
@@ -176,7 +196,9 @@
 }
 
 std::string TranslateUIDelegate::GetTargetLanguageCode() const {
-  return GetLanguageCodeAt(GetTargetLanguageIndex());
+  return (GetTargetLanguageIndex() == kNoIndex)
+             ? translate::kUnknownLanguageCode
+             : GetLanguageCodeAt(GetTargetLanguageIndex());
 }
 
 void TranslateUIDelegate::Translate() {
diff --git a/components/translate/core/browser/translate_ui_delegate.h b/components/translate/core/browser/translate_ui_delegate.h
index cf8a9a2..04f457ca 100644
--- a/components/translate/core/browser/translate_ui_delegate.h
+++ b/components/translate/core/browser/translate_ui_delegate.h
@@ -24,6 +24,14 @@
 
 // The TranslateUIDelegate is a generic delegate for UI which offers Translate
 // feature to the user.
+
+// Note that the API offers a way to read/set language values through array
+// indices. Such indices are only valid as long as the visual representation
+// (infobar, bubble...) is in sync with the underlying language list which
+// can actually change at run time (see translate_language_list.h).
+// It is recommended that languages are only updated by language code to
+// avoid bugs like crbug.com/555124
+
 class TranslateUIDelegate {
  public:
   static const size_t kNoIndex = static_cast<size_t>(-1);
@@ -45,27 +53,31 @@
   // Returns the original language index.
   size_t GetOriginalLanguageIndex() const;
 
+  // Returns the original language code.
+  std::string GetOriginalLanguageCode() const;
+
   // Updates the original language index.
   void UpdateOriginalLanguageIndex(size_t language_index);
 
+  void UpdateOriginalLanguage(const std::string& language_code);
+
   // Returns the target language index.
   size_t GetTargetLanguageIndex() const;
 
+  // Returns the target language code.
+  std::string GetTargetLanguageCode() const;
+
   // Updates the target language index.
   void UpdateTargetLanguageIndex(size_t language_index);
 
+  void UpdateTargetLanguage(const std::string& language_code);
+
   // Returns the ISO code for the language at |index|.
   std::string GetLanguageCodeAt(size_t index) const;
 
   // Returns the displayable name for the language at |index|.
   base::string16 GetLanguageNameAt(size_t index) const;
 
-  // The original language for Translate.
-  std::string GetOriginalLanguageCode() const;
-
-  // The target language for Translate.
-  std::string GetTargetLanguageCode() const;
-
   // Starts translating the current page.
   void Translate();
 
@@ -103,11 +115,10 @@
   TranslateDriver* translate_driver_;
   base::WeakPtr<TranslateManager> translate_manager_;
 
+  // ISO code (en, fr...) -> displayable name in the current locale
   typedef std::pair<std::string, base::string16> LanguageNamePair;
 
   // The list supported languages for translation.
-  // The pair first string is the language ISO code (ex: en, fr...), the second
-  // string is the displayable name on the current locale.
   // The languages are sorted alphabetically based on the displayable name.
   std::vector<LanguageNamePair> languages_;
 
diff --git a/components/web_view/frame.cc b/components/web_view/frame.cc
index de267a3..090a52a 100644
--- a/components/web_view/frame.cc
+++ b/components/web_view/frame.cc
@@ -194,8 +194,7 @@
                        mus::mojom::WindowTreeClientPtr window_tree_client,
                        mojo::InterfaceRequest<mojom::Frame> frame_request,
                        base::TimeTicks navigation_start_time) {
-  if (client_type == ClientType::EXISTING_FRAME_NEW_APP &&
-      window_tree_client.get()) {
+  if (client_type == ClientType::EXISTING_FRAME_NEW_APP && window_tree_client) {
     embedded_connection_id_ = kInvalidConnectionId;
     embed_weak_ptr_factory_.InvalidateWeakPtrs();
     window_->Embed(
@@ -258,7 +257,7 @@
   while (!children_.empty())
     delete children_[0];
 
-  ClientType client_type = window_tree_client.get() == nullptr
+  ClientType client_type = !window_tree_client
                                ? ClientType::EXISTING_FRAME_SAME_APP
                                : ClientType::EXISTING_FRAME_NEW_APP;
   scoped_ptr<FrameUserDataAndBinding> data_and_binding;
diff --git a/content/app/BUILD.gn b/content/app/BUILD.gn
index 7d3e5ee..e8575cc 100644
--- a/content/app/BUILD.gn
+++ b/content/app/BUILD.gn
@@ -73,6 +73,7 @@
 content_app_extra_configs = [
   "//build/config/compiler:wexit_time_destructors",
   "//content:content_implementation",
+  "//content/public/common:mojo_shell_client",
   "//v8:external_startup_data",
 ]
 
diff --git a/content/app/mojo/mojo_init.cc b/content/app/mojo/mojo_init.cc
index b214fe3..2aee5b4b 100644
--- a/content/app/mojo/mojo_init.cc
+++ b/content/app/mojo/mojo_init.cc
@@ -11,6 +11,10 @@
 #include "ipc/ipc_channel.h"
 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
 
+#if defined(MOJO_SHELL_CLIENT)
+#include "content/common/mojo/mojo_shell_connection_impl.h"
+#endif
+
 namespace content {
 
 namespace {
@@ -21,9 +25,14 @@
     const base::CommandLine& command_line =
         *base::CommandLine::ForCurrentProcess();
     if (command_line.HasSwitch("use-new-edk")) {
-      std::string process_type =
-          command_line.GetSwitchValueASCII(switches::kProcessType);
-      if (process_type.empty()) {
+      bool initialize_as_parent =
+          command_line.GetSwitchValueASCII(switches::kProcessType).empty();
+#if defined(MOJO_SHELL_CLIENT)
+      if (IsRunningInMojoShell()) {
+        initialize_as_parent = false;
+      }
+#endif
+      if (initialize_as_parent) {
         mojo::embedder::PreInitializeParentProcess();
       } else {
         mojo::embedder::PreInitializeChildProcess();
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index ff1b66d..624eb3b 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -430,6 +430,7 @@
       "//ui/aura",
       "//ui/aura_extra",
       "//ui/strings",
+      "//ui/views/mus:for_component",
       "//ui/wm",
     ]
     sources += [
@@ -441,13 +442,14 @@
       "web_contents/web_contents_view_mus.h",
     ]
     if (toolkit_views) {
-      deps += [ "//ui/views/mus:for_component" ]
       defines += [ "MOJO_RUNNER_CLIENT" ]
     }
   } else {  # Not aura.
     sources -= [
       "media/capture/cursor_renderer_aura.cc",
       "media/capture/cursor_renderer_aura.h",
+      "media/capture/window_activity_tracker_aura.cc",
+      "media/capture/window_activity_tracker_aura.h",
       "renderer_host/compositor_resize_lock_aura.cc",
       "renderer_host/compositor_resize_lock_aura.h",
       "renderer_host/input/synthetic_gesture_target_aura.cc",
@@ -518,8 +520,6 @@
     sources += [
       "media/cdm/browser_cdm_manager.cc",
       "media/cdm/browser_cdm_manager.h",
-      "media/media_web_contents_observer.cc",
-      "media/media_web_contents_observer.h",
     ]
   }
 
diff --git a/content/browser/DEPS b/content/browser/DEPS
index 42ad828..be561672 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -87,6 +87,7 @@
   "+third_party/WebKit/public/web/WebPopupType.h",
   "+third_party/WebKit/public/web/WebSandboxFlags.h",
   "+third_party/WebKit/public/web/WebSerializedScriptValueVersion.h",
+  "+third_party/WebKit/public/web/WebSharedWorkerCreationContextType.h",
   "+third_party/WebKit/public/web/WebSharedWorkerCreationErrors.h",
   "+third_party/WebKit/public/web/WebTextDirection.h",
   "+third_party/WebKit/public/web/WebTextInputType.h",
diff --git a/content/browser/accessibility/accessibility_tree_formatter_win.cc b/content/browser/accessibility/accessibility_tree_formatter_win.cc
index c7ef471..6277f430 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_win.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_win.cc
@@ -298,8 +298,7 @@
   dict.GetString("role", &role_value);
   WriteAttribute(true, base::UTF16ToUTF8(role_value), &line);
 
-  for (int i = 0; i < arraysize(ALL_ATTRIBUTES); i++) {
-    const char* attribute_name = ALL_ATTRIBUTES[i];
+  for (const char* attribute_name : ALL_ATTRIBUTES) {
     const base::Value* value;
     if (!dict.Get(attribute_name, &value))
       continue;
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc
index 373ef0ed..a28a06b4 100644
--- a/content/browser/accessibility/accessibility_win_browsertest.cc
+++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -126,7 +126,7 @@
   base::win::ScopedComPtr<IAccessible> document(GetRendererAccessible());
   std::vector<base::win::ScopedVariant> document_children =
       GetAllAccessibleChildren(document.get());
-  ASSERT_EQ(1, document_children.size());
+  ASSERT_EQ(1u, document_children.size());
 
   base::win::ScopedComPtr<IAccessible2> form;
   HRESULT hr = QueryIAccessible2(GetAccessibleFromVariant(
@@ -134,7 +134,7 @@
   ASSERT_EQ(S_OK, hr);
   std::vector<base::win::ScopedVariant> form_children =
       GetAllAccessibleChildren(form.get());
-  ASSERT_EQ(2, form_children.size());
+  ASSERT_EQ(2u, form_children.size());
 
   // Find the input text field.
   base::win::ScopedComPtr<IAccessible2> input;
@@ -178,7 +178,7 @@
   base::win::ScopedComPtr<IAccessible> document(GetRendererAccessible());
   std::vector<base::win::ScopedVariant> document_children =
       GetAllAccessibleChildren(document.get());
-  ASSERT_EQ(1, document_children.size());
+  ASSERT_EQ(1u, document_children.size());
 
   base::win::ScopedComPtr<IAccessible2> section;
   HRESULT hr = QueryIAccessible2(GetAccessibleFromVariant(
@@ -186,7 +186,7 @@
   ASSERT_EQ(S_OK, hr);
   std::vector<base::win::ScopedVariant> section_children =
       GetAllAccessibleChildren(section.get());
-  ASSERT_EQ(1, section_children.size());
+  ASSERT_EQ(1u, section_children.size());
 
   // Find the textarea text field.
   base::win::ScopedComPtr<IAccessible2> textarea;
@@ -905,7 +905,7 @@
       &unique_id, &node_type);
   ASSERT_EQ(S_OK, hr);
   EXPECT_EQ(NODETYPE_DOCUMENT, node_type);
-  EXPECT_EQ(1, num_children);
+  EXPECT_EQ(1u, num_children);
   node_name.Reset();
   node_value.Reset();
 
@@ -919,7 +919,7 @@
   ASSERT_EQ(S_OK, hr);
   EXPECT_EQ(L"body", std::wstring(node_name, node_name.Length()));
   EXPECT_EQ(NODETYPE_ELEMENT, node_type);
-  EXPECT_EQ(1, num_children);
+  EXPECT_EQ(1u, num_children);
   node_name.Reset();
   node_value.Reset();
 
@@ -933,7 +933,7 @@
   ASSERT_EQ(S_OK, hr);
   EXPECT_EQ(L"input", std::wstring(node_name, node_name.Length()));
   EXPECT_EQ(NODETYPE_ELEMENT, node_type);
-  EXPECT_EQ(0, num_children);
+  EXPECT_EQ(0u, num_children);
 }
 
 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, TestRoleGroup) {
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index a057213d..003e805 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -119,11 +119,11 @@
 }
 
 bool BrowserAccessibility::PlatformIsChildOfLeaf() const {
-  BrowserAccessibility* ancestor = GetParent();
+  BrowserAccessibility* ancestor = InternalGetParent();
   while (ancestor) {
     if (ancestor->PlatformIsLeaf())
       return true;
-    ancestor = ancestor->GetParent();
+    ancestor = ancestor->InternalGetParent();
   }
 
   return false;
@@ -197,6 +197,16 @@
   return manager_->GetParentNodeFromParentTree();
 }
 
+BrowserAccessibility* BrowserAccessibility::InternalGetParent() const {
+  if (!node_ || !manager_)
+    return nullptr;
+  ui::AXNode* parent = node_->parent();
+  if (parent)
+    return manager_->GetFromAXNode(parent);
+
+  return nullptr;
+}
+
 int32 BrowserAccessibility::GetIndexInParent() const {
   return node_ ? node_->index_in_parent() : -1;
 }
@@ -256,7 +266,7 @@
     gfx::Rect bounds;
     for (size_t i = 0; i < InternalChildCount(); ++i) {
       BrowserAccessibility* child = InternalGetChild(i);
-      int child_len = child->GetStaticTextLenRecursive();
+      int child_len = child->GetInnerTextLength();
       if (start < child_len && start + len > 0) {
         gfx::Rect child_rect = child->GetLocalBoundsForRange(start, len);
         bounds.Union(child_rect);
@@ -359,11 +369,18 @@
   return bounds;
 }
 
+base::string16 BrowserAccessibility::GetValue() const {
+  base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE);
+  if (value.empty() && IsSimpleTextControl())
+    value = GetInnerText();
+  return value;
+}
+
 int BrowserAccessibility::GetWordStartBoundary(
     int start, ui::TextBoundaryDirection direction) const {
   DCHECK_GE(start, -1);
   // Special offset that indicates that a word boundary has not been found.
-  int word_start_not_found = GetStaticTextLenRecursive();
+  int word_start_not_found = GetInnerTextLength();
   int word_start = word_start_not_found;
 
   switch (GetRole()) {
@@ -436,7 +453,7 @@
       int child_start = 0;
       for (size_t i = 0; i < InternalChildCount(); ++i) {
         BrowserAccessibility* child = InternalGetChild(i);
-        int child_len = child->GetStaticTextLenRecursive();
+        int child_len = child->GetInnerTextLength();
         int child_word_start = child->GetWordStartBoundary(start, direction);
         if (child_word_start < child_len) {
           // We have found a possible word boundary.
@@ -763,16 +780,18 @@
   return name;
 }
 
-int BrowserAccessibility::GetStaticTextLenRecursive() const {
-  if (GetRole() == ui::AX_ROLE_STATIC_TEXT ||
-      GetRole() == ui::AX_ROLE_LINE_BREAK) {
-    return static_cast<int>(GetStringAttribute(ui::AX_ATTR_NAME).size());
-  }
+base::string16 BrowserAccessibility::GetInnerText() const {
+  if (IsTextOnlyObject())
+    return GetString16Attribute(ui::AX_ATTR_NAME);
 
-  int len = 0;
+  base::string16 text;
   for (size_t i = 0; i < InternalChildCount(); ++i)
-    len += InternalGetChild(i)->GetStaticTextLenRecursive();
-  return len;
+    text += InternalGetChild(i)->GetInnerText();
+  return text;
+}
+
+int BrowserAccessibility::GetInnerTextLength() const {
+  return static_cast<int>(GetInnerText().size());
 }
 
 void BrowserAccessibility::FixEmptyBounds(gfx::Rect* bounds) const
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index e5e5927..d24c7d3 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -138,6 +138,10 @@
   // the role is WebAXRoleStaticText.
   gfx::Rect GetGlobalBoundsForRange(int start, int len) const;
 
+  // This is to handle the cases such as ARIA textbox, where the value should
+  // be calculated from the object's inner text.
+  base::string16 GetValue() const;
+
   // Searches in the given text and from the given offset until the start of
   // the next or previous word is found and returns its position.
   // In case there is no word boundary before or after the given offset, it
@@ -186,6 +190,7 @@
   // accessibility APIs.
   uint32 InternalChildCount() const;
   BrowserAccessibility* InternalGetChild(uint32 child_index) const;
+  BrowserAccessibility* InternalGetParent() const;
 
   BrowserAccessibility* GetParent() const;
   int32 GetIndexInParent() const;
@@ -314,9 +319,8 @@
   ui::AXNode* node_;
 
  private:
-  // Return the sum of the lengths of all static text descendants,
-  // including this object if it's static text.
-  int GetStaticTextLenRecursive() const;
+  base::string16 GetInnerText() const;
+  int GetInnerTextLength() const;
 
   // If a bounding rectangle is empty, compute it based on the union of its
   // children, since most accessibility APIs don't like elements with no
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc
index 96411cb..08fe609 100644
--- a/content/browser/accessibility/browser_accessibility_android.cc
+++ b/content/browser/accessibility/browser_accessibility_android.cc
@@ -320,7 +320,7 @@
 
   // First, always return the |value| attribute if this is an
   // input field.
-  base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE);
+  base::string16 value = GetValue();
   if (!value.empty()) {
     if (HasState(ui::AX_STATE_EDITABLE))
       return value;
@@ -646,7 +646,7 @@
 }
 
 int BrowserAccessibilityAndroid::GetEditableTextLength() const {
-  base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE);
+  base::string16 value = GetValue();
   return value.length();
 }
 
@@ -915,7 +915,7 @@
   BrowserAccessibility::OnDataChanged();
 
   if (IsEditableText()) {
-    base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE);
+    base::string16 value = GetValue();
     if (value != new_value_) {
       old_value_ = new_value_;
       new_value_ = value;
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 20a3621..a5176c3 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -605,8 +605,7 @@
 
   // If it's focusable but didn't have any other name or value, compute a name
   // from its descendants.
-  std::string value = browserAccessibility_->GetStringAttribute(
-      ui::AX_ATTR_VALUE);
+  base::string16 value = browserAccessibility_->GetValue();
   if (browserAccessibility_->HasState(ui::AX_STATE_FOCUSABLE) &&
       !browserAccessibility_->IsControl() &&
       value.empty() &&
@@ -841,8 +840,7 @@
 }
 
 - (NSNumber*)numberOfCharacters {
-  std::string value = browserAccessibility_->GetStringAttribute(
-      ui::AX_ATTR_VALUE);
+  base::string16 value = browserAccessibility_->GetValue();
   return [NSNumber numberWithInt:value.size()];
 }
 
@@ -1360,18 +1358,17 @@
                 red / 255., green / 255., blue / 255.];
   }
 
-  return NSStringForStringAttribute(
-      browserAccessibility_, ui::AX_ATTR_VALUE);
+  return base::SysUTF16ToNSString(browserAccessibility_->GetValue());
 }
 
 - (NSString*)valueDescription {
-  return NSStringForStringAttribute(
-      browserAccessibility_, ui::AX_ATTR_VALUE);
+  if (browserAccessibility_)
+    return base::SysUTF16ToNSString(browserAccessibility_->GetValue());
+  return nil;
 }
 
 - (NSValue*)visibleCharacterRange {
-  std::string value = browserAccessibility_->GetStringAttribute(
-      ui::AX_ATTR_VALUE);
+  base::string16 value = browserAccessibility_->GetValue();
   return [NSValue valueWithRange:NSMakeRange(0, value.size())];
 }
 
@@ -1441,8 +1438,7 @@
   if (!browserAccessibility_)
     return nil;
 
-  base::string16 value =
-      browserAccessibility_->GetString16Attribute(ui::AX_ATTR_VALUE);
+  base::string16 value = browserAccessibility_->GetValue();
   if (NSMaxRange(range) > value.size())
     return nil;
 
@@ -1481,8 +1477,7 @@
       return [NSNumber numberWithInt:static_cast<int>(line_breaks.size())];
     }
     if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) {
-      base::string16 value = browserAccessibility_->GetString16Attribute(
-          ui::AX_ATTR_VALUE);
+      base::string16 value = browserAccessibility_->GetValue();
       return base::SysUTF16ToNSString(value.substr(selStart, selLength));
     }
     if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
@@ -1502,8 +1497,7 @@
   const std::vector<int32>& line_breaks =
       browserAccessibility_->GetIntListAttribute(
           ui::AX_ATTR_LINE_BREAKS);
-  std::string value = browserAccessibility_->GetStringAttribute(
-      ui::AX_ATTR_VALUE);
+  base::string16 value = browserAccessibility_->GetValue();
   int len = static_cast<int>(value.size());
 
   if ([attribute isEqualToString:
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
index 0c61d914..7679237 100644
--- a/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -49,7 +49,10 @@
     const ui::AXNodeData& node6 /* = ui::AXNodeData() */,
     const ui::AXNodeData& node7 /* = ui::AXNodeData() */,
     const ui::AXNodeData& node8 /* = ui::AXNodeData() */,
-    const ui::AXNodeData& node9 /* = ui::AXNodeData() */) {
+    const ui::AXNodeData& node9 /* = ui::AXNodeData() */,
+    const ui::AXNodeData& node10 /* = ui::AXNodeData() */,
+    const ui::AXNodeData& node11 /* = ui::AXNodeData() */,
+    const ui::AXNodeData& node12 /* = ui::AXNodeData() */) {
   CR_DEFINE_STATIC_LOCAL(ui::AXNodeData, empty_data, ());
   int32 no_id = empty_data.id;
 
@@ -71,6 +74,12 @@
     update.nodes.push_back(node8);
   if (node9.id != no_id)
     update.nodes.push_back(node9);
+  if (node10.id != no_id)
+    update.nodes.push_back(node10);
+  if (node11.id != no_id)
+    update.nodes.push_back(node11);
+  if (node12.id != no_id)
+    update.nodes.push_back(node12);
   return update;
 }
 
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h
index 168d577..872efad 100644
--- a/content/browser/accessibility/browser_accessibility_manager.h
+++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -42,7 +42,10 @@
     const ui::AXNodeData& node6 = ui::AXNodeData(),
     const ui::AXNodeData& node7 = ui::AXNodeData(),
     const ui::AXNodeData& node8 = ui::AXNodeData(),
-    const ui::AXNodeData& node9 = ui::AXNodeData());
+    const ui::AXNodeData& node9 = ui::AXNodeData(),
+    const ui::AXNodeData& node10 = ui::AXNodeData(),
+    const ui::AXNodeData& node11 = ui::AXNodeData(),
+    const ui::AXNodeData& node12 = ui::AXNodeData());
 
 // Class that can perform actions on behalf of the BrowserAccessibilityManager.
 // Note: BrowserAccessibilityManager should never cache any of the return
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.cc b/content/browser/accessibility/browser_accessibility_manager_win.cc
index f05055e..e74b32f 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -17,6 +17,10 @@
 
 namespace content {
 
+// Map from unique_id_win to BrowserAccessibility
+using UniqueIDWinMap = base::hash_map<LONG, BrowserAccessibility*>;
+base::LazyInstance<UniqueIDWinMap> g_unique_id_map = LAZY_INSTANCE_INITIALIZER;
+
 // static
 BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
     const ui::AXTreeUpdate& initial_tree,
@@ -66,15 +70,17 @@
 }
 
 HWND BrowserAccessibilityManagerWin::GetParentHWND() {
-  if (!delegate_)
+  BrowserAccessibilityDelegate* delegate = GetDelegateFromRootManager();
+  if (!delegate)
     return NULL;
-  return delegate_->AccessibilityGetAcceleratedWidget();
+  return delegate->AccessibilityGetAcceleratedWidget();
 }
 
 IAccessible* BrowserAccessibilityManagerWin::GetParentIAccessible() {
-  if (!delegate_)
+  BrowserAccessibilityDelegate* delegate = GetDelegateFromRootManager();
+  if (!delegate)
     return NULL;
-  return delegate_->AccessibilityGetNativeViewAccessible();
+  return delegate->AccessibilityGetNativeViewAccessible();
 }
 
 void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(
@@ -304,8 +310,7 @@
   if (!obj->IsNative())
     return;
   LONG unique_id_win = obj->ToBrowserAccessibilityWin()->unique_id_win();
-  unique_id_to_ax_id_map_[unique_id_win] = obj->GetId();
-  unique_id_to_ax_tree_id_map_[unique_id_win] = ax_tree_id_;
+  g_unique_id_map.Get()[unique_id_win] = obj;
 }
 
 void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXTree* tree,
@@ -317,9 +322,7 @@
     return;
   if (!obj->IsNative())
     return;
-  unique_id_to_ax_id_map_.erase(
-      obj->ToBrowserAccessibilityWin()->unique_id_win());
-  unique_id_to_ax_tree_id_map_.erase(
+  g_unique_id_map.Get().erase(
       obj->ToBrowserAccessibilityWin()->unique_id_win());
   if (obj == tracked_scroll_object_) {
     tracked_scroll_object_->Release();
@@ -392,31 +395,11 @@
 
 BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFromUniqueIdWin(
     LONG unique_id_win) {
-  auto tree_iter = unique_id_to_ax_tree_id_map_.find(unique_id_win);
-  if (tree_iter == unique_id_to_ax_tree_id_map_.end())
+  auto iter = g_unique_id_map.Get().find(unique_id_win);
+  if (iter == g_unique_id_map.Get().end())
     return nullptr;
 
-  int tree_id = tree_iter->second;
-  if (tree_id != ax_tree_id_) {
-    BrowserAccessibilityManagerWin* manager =
-        BrowserAccessibilityManager::FromID(tree_id)
-            ->ToBrowserAccessibilityManagerWin();
-    if (!manager)
-      return nullptr;
-    if (manager != this)
-      return manager->GetFromUniqueIdWin(unique_id_win);
-    return nullptr;
-  }
-
-  auto iter = unique_id_to_ax_id_map_.find(unique_id_win);
-  if (iter == unique_id_to_ax_id_map_.end())
-    return nullptr;
-
-  BrowserAccessibility* result = GetFromID(iter->second);
-  if (result && result->IsNative())
-    return result->ToBrowserAccessibilityWin();
-
-  return nullptr;
+  return iter->second->ToBrowserAccessibilityWin();
 }
 
 }  // namespace content
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.h b/content/browser/accessibility/browser_accessibility_manager_win.h
index b64595ec..1f9434f 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.h
+++ b/content/browser/accessibility/browser_accessibility_manager_win.h
@@ -72,14 +72,6 @@
   // TODO(dmazzoni): remove once http://crbug.com/113483 is fixed.
   BrowserAccessibilityWin* tracked_scroll_object_;
 
-  // A mapping from the Windows-specific unique IDs (unique within the
-  // browser process) to accessibility ids within this page.
-  base::hash_map<long, int32> unique_id_to_ax_id_map_;
-
-  // A mapping from the Windows-specific unique IDs (unique within the
-  // browser process) to the AXTreeID that contains this unique ID.
-  base::hash_map<long, AXTreeIDRegistry::AXTreeID> unique_id_to_ax_tree_id_map_;
-
   // Set to true if we need to fire a focus event on the root as soon as
   // possible.
   bool focus_event_on_root_needed_;
diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc
index 3009bfa..e44e912 100644
--- a/content/browser/accessibility/browser_accessibility_win.cc
+++ b/content/browser/accessibility/browser_accessibility_win.cc
@@ -3094,7 +3094,10 @@
     // Special Mozilla extension: return the accessible for the root document.
     // Screen readers use this to distinguish between a document loaded event
     // on the root document vs on an iframe.
-    return manager()->GetRoot()->ToBrowserAccessibilityWin()->QueryInterface(
+    BrowserAccessibility* node = this;
+    while (node->GetParent())
+      node = node->GetParent()->manager()->GetRoot();
+    return node->ToBrowserAccessibilityWin()->QueryInterface(
         IID_IAccessible2, object);
   }
 
@@ -3384,7 +3387,7 @@
   win_attributes_->name = GetString16Attribute(ui::AX_ATTR_NAME);
   win_attributes_->description = GetString16Attribute(ui::AX_ATTR_DESCRIPTION);
 
-  base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE);
+  base::string16 value = GetValue();
 
   // On Windows, the value of a document should be its url.
   if (GetRole() == ui::AX_ROLE_ROOT_WEB_AREA ||
@@ -3898,19 +3901,6 @@
     ++(*largest_offset);
 }
 
-base::string16 BrowserAccessibilityWin::GetNameRecursive() const {
-  if (!name().empty()) {
-    return name();
-  }
-
-  base::string16 result;
-  for (uint32 i = 0; i < PlatformChildCount(); ++i) {
-    result += PlatformGetChild(i)->ToBrowserAccessibilityWin()->
-        GetNameRecursive();
-  }
-  return result;
-}
-
 base::string16 BrowserAccessibilityWin::GetValueText() {
   float fval;
   base::string16 value = this->value();
diff --git a/content/browser/accessibility/browser_accessibility_win.h b/content/browser/accessibility/browser_accessibility_win.h
index 8004cbd..c51d1d448 100644
--- a/content/browser/accessibility/browser_accessibility_win.h
+++ b/content/browser/accessibility/browser_accessibility_win.h
@@ -820,9 +820,6 @@
   // selection.)
   void GetSelectionOffsets(int* selection_start, int* selection_end) const;
 
-  // Append the accessible name from this node and its children.
-  base::string16 GetNameRecursive() const;
-
   // Get the value text, which might come from the floating-point
   // value for some roles.
   base::string16 GetValueText();
diff --git a/content/browser/accessibility/browser_accessibility_win_unittest.cc b/content/browser/accessibility/browser_accessibility_win_unittest.cc
index 29886bc1..89cdd54c 100644
--- a/content/browser/accessibility/browser_accessibility_win_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_win_unittest.cc
@@ -484,7 +484,7 @@
 TEST_F(BrowserAccessibilityTest, TestSimpleHypertext) {
   const std::string text1_name = "One two three.";
   const std::string text2_name = " Four five six.";
-  const size_t text_name_len = text1_name.length() + text2_name.length();
+  const long text_name_len = text1_name.length() + text2_name.length();
 
   ui::AXNodeData text1;
   text1.id = 11;
@@ -567,7 +567,7 @@
   const base::string16 embed(1, BrowserAccessibilityWin::kEmbeddedCharacter);
   const base::string16 root_hypertext =
       text1_name + embed + text2_name + embed + embed + embed;
-  const size_t root_hypertext_len = root_hypertext.length();
+  const long root_hypertext_len = root_hypertext.length();
 
   ui::AXNodeData text1;
   text1.id = 11;
@@ -882,10 +882,144 @@
   ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
 }
 
-/**
- * Ensures that ui::AX_ATTR_TEXT_SEL_START/END attributes are correctly used to
- * determine caret position and text selection in simple form fields.
- */
+TEST_F(BrowserAccessibilityTest, TestValueAttributeInTextControls) {
+  ui::AXNodeData root;
+  root.id = 1;
+  root.role = ui::AX_ROLE_ROOT_WEB_AREA;
+  root.state = (1 << ui::AX_STATE_READ_ONLY) | (1 << ui::AX_STATE_FOCUSABLE);
+
+  ui::AXNodeData combo_box, combo_box_text;
+  combo_box.id = 2;
+  combo_box_text.id = 3;
+  combo_box.SetName("Combo box:");
+  combo_box_text.SetName("Combo box text");
+  combo_box.role = ui::AX_ROLE_COMBO_BOX;
+  combo_box_text.role = ui::AX_ROLE_STATIC_TEXT;
+  combo_box.state = (1 << ui::AX_STATE_EDITABLE) |
+                    (1 << ui::AX_STATE_FOCUSABLE) | (1 << ui::AX_STATE_FOCUSED);
+  combo_box_text.state = 1 << ui::AX_STATE_EDITABLE;
+  combo_box.child_ids.push_back(combo_box_text.id);
+
+  ui::AXNodeData search_box, search_box_text, new_line;
+  search_box.id = 4;
+  search_box_text.id = 5;
+  new_line.id = 6;
+  search_box.SetName("Search for:");
+  search_box_text.SetName("Search box text");
+  new_line.SetName("\n");
+  search_box.role = ui::AX_ROLE_SEARCH_BOX;
+  search_box_text.role = ui::AX_ROLE_STATIC_TEXT;
+  new_line.role = ui::AX_ROLE_LINE_BREAK;
+  search_box.state = (1 << ui::AX_STATE_EDITABLE) |
+                     (1 << ui::AX_STATE_FOCUSABLE) |
+                     (1 << ui::AX_STATE_FOCUSED);
+  search_box_text.state = new_line.state = 1 << ui::AX_STATE_EDITABLE;
+  search_box.child_ids.push_back(search_box_text.id);
+  search_box.child_ids.push_back(new_line.id);
+
+  ui::AXNodeData text_field;
+  text_field.id = 7;
+  text_field.role = ui::AX_ROLE_TEXT_FIELD;
+  text_field.state =
+      (1 << ui::AX_STATE_EDITABLE) | (1 << ui::AX_STATE_FOCUSABLE);
+  text_field.SetValue("Text field text");
+
+  ui::AXNodeData link, link_text;
+  link.id = 8;
+  link_text.id = 9;
+  link_text.SetName("Link text");
+  link.role = ui::AX_ROLE_LINK;
+  link_text.role = ui::AX_ROLE_STATIC_TEXT;
+  link.state = link_text.state = 1 << ui::AX_STATE_READ_ONLY;
+  link.child_ids.push_back(link_text.id);
+
+  ui::AXNodeData slider, slider_text;
+  slider.id = 10;
+  slider_text.id = 11;
+  slider.AddFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, 5.0F);
+  slider_text.SetName("Slider text");
+  slider.role = ui::AX_ROLE_SLIDER;
+  slider_text.role = ui::AX_ROLE_STATIC_TEXT;
+  slider_text.state = 1 << ui::AX_STATE_READ_ONLY;
+  slider.child_ids.push_back(slider_text.id);
+
+  root.child_ids.push_back(2);   // Combo box.
+  root.child_ids.push_back(4);   // Search box.
+  root.child_ids.push_back(7);   // Text field.
+  root.child_ids.push_back(8);   // Link.
+  root.child_ids.push_back(10);  // Slider.
+
+  CountedBrowserAccessibility::reset();
+  scoped_ptr<BrowserAccessibilityManager> manager(
+      BrowserAccessibilityManager::Create(
+          MakeAXTreeUpdate(root, combo_box, combo_box_text, search_box,
+                           search_box_text, new_line, text_field, link,
+                           link_text, slider, slider_text),
+          nullptr, new CountedBrowserAccessibilityFactory()));
+  ASSERT_EQ(11, CountedBrowserAccessibility::num_instances());
+
+  ASSERT_NE(nullptr, manager->GetRoot());
+  BrowserAccessibilityWin* root_accessible =
+      manager->GetRoot()->ToBrowserAccessibilityWin();
+  ASSERT_NE(nullptr, root_accessible);
+  ASSERT_EQ(5U, root_accessible->PlatformChildCount());
+
+  BrowserAccessibilityWin* combo_box_accessible =
+      root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+  ASSERT_NE(nullptr, combo_box_accessible);
+  manager->SetFocus(combo_box_accessible, false /* notify */);
+  ASSERT_EQ(combo_box_accessible,
+            manager->GetFocus(root_accessible)->ToBrowserAccessibilityWin());
+  BrowserAccessibilityWin* search_box_accessible =
+      root_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin();
+  ASSERT_NE(nullptr, search_box_accessible);
+  BrowserAccessibilityWin* text_field_accessible =
+      root_accessible->PlatformGetChild(2)->ToBrowserAccessibilityWin();
+  ASSERT_NE(nullptr, text_field_accessible);
+  BrowserAccessibilityWin* link_accessible =
+      root_accessible->PlatformGetChild(3)->ToBrowserAccessibilityWin();
+  ASSERT_NE(nullptr, link_accessible);
+  BrowserAccessibilityWin* slider_accessible =
+      root_accessible->PlatformGetChild(4)->ToBrowserAccessibilityWin();
+  ASSERT_NE(nullptr, slider_accessible);
+
+  base::win::ScopedVariant childid_self(CHILDID_SELF);
+  base::win::ScopedVariant childid_slider(5);
+  base::win::ScopedBstr value;
+
+  HRESULT hr =
+      combo_box_accessible->get_accValue(childid_self, value.Receive());
+  EXPECT_EQ(S_OK, hr);
+  EXPECT_STREQ(L"Combo box text", value);
+  value.Reset();
+  hr = search_box_accessible->get_accValue(childid_self, value.Receive());
+  EXPECT_EQ(S_OK, hr);
+  EXPECT_STREQ(L"Search box text\n", value);
+  value.Reset();
+  hr = text_field_accessible->get_accValue(childid_self, value.Receive());
+  EXPECT_EQ(S_OK, hr);
+  EXPECT_STREQ(L"Text field text", value);
+  value.Reset();
+
+  // Other controls, such as links, should not use their inner text as their
+  // value. Only text entry controls.
+  hr = link_accessible->get_accValue(childid_self, value.Receive());
+  EXPECT_EQ(S_OK, hr);
+  EXPECT_EQ(0, value.Length());
+  value.Reset();
+
+  // Sliders and other range controls should expose their current value and not
+  // their inner text.
+  // Also, try accessing the slider via its child number instead of directly.
+  hr = root_accessible->get_accValue(childid_slider, value.Receive());
+  EXPECT_EQ(S_OK, hr);
+  EXPECT_STREQ(L"5", value);
+  value.Reset();
+
+  manager.reset();
+  ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
+}
+
 TEST_F(BrowserAccessibilityTest, TestCaretAndSelectionInSimpleFields) {
   ui::AXNodeData root;
   root.id = 1;
diff --git a/content/browser/android/in_process/synchronous_compositor_impl.cc b/content/browser/android/in_process/synchronous_compositor_impl.cc
index ae4fb61..7b9b151 100644
--- a/content/browser/android/in_process/synchronous_compositor_impl.cc
+++ b/content/browser/android/in_process/synchronous_compositor_impl.cc
@@ -298,13 +298,11 @@
 }
 
 void SynchronousCompositorImpl::DeliverMessages() {
-  ScopedVector<IPC::Message> messages;
+  std::vector<scoped_ptr<IPC::Message>> messages;
   output_surface_->GetMessagesToDeliver(&messages);
   RenderProcessHost* rph = rwhva_->GetRenderWidgetHost()->GetProcess();
-  for (ScopedVector<IPC::Message>::const_iterator i = messages.begin();
-       i != messages.end();
-       ++i) {
-    rph->OnMessageReceived(**i);
+  for (const auto& msg : messages) {
+    rph->OnMessageReceived(*msg);
   }
 }
 
diff --git a/content/browser/android/url_request_content_job_unittest.cc b/content/browser/android/url_request_content_job_unittest.cc
index 028a864..288914a5 100644
--- a/content/browser/android/url_request_content_job_unittest.cc
+++ b/content/browser/android/url_request_content_job_unittest.cc
@@ -26,7 +26,8 @@
  public:
   class JobObserver {
    public:
-    virtual void OnJobCreated(URLRequestContentJob* job) = 0;
+    virtual ~JobObserver() {}
+    virtual void OnJobCreated() = 0;
   };
 
   CallbacksJobFactory(const base::FilePath& path, JobObserver* observer)
@@ -45,7 +46,7 @@
             network_delegate,
             path_,
             const_cast<base::MessageLoop*>(&message_loop_)->task_runner());
-    observer_->OnJobCreated(job);
+    observer_->OnJobCreated();
     return job;
   }
 
@@ -82,16 +83,15 @@
 
 class JobObserverImpl : public CallbacksJobFactory::JobObserver {
  public:
-  void OnJobCreated(URLRequestContentJob* job) override {
-    jobs_.push_back(job);
-  }
+  JobObserverImpl() : num_jobs_created_(0) {}
+  ~JobObserverImpl() override {}
 
-  typedef std::vector<scoped_refptr<URLRequestContentJob> > JobList;
+  void OnJobCreated() override { ++num_jobs_created_; }
 
-  const JobList& jobs() { return jobs_; }
+  int num_jobs_created() const { return num_jobs_created_; }
 
- protected:
-  JobList jobs_;
+ private:
+  int num_jobs_created_;
 };
 
 // A simple holder for start/end used in http range requests.
@@ -158,11 +158,12 @@
         base::StringPrintf("bytes=%d-%d", range->start, range->end);
     request->SetExtraRequestHeaderByName(
         net::HttpRequestHeaders::kRange, range_value, true /*overwrite*/);
-    if (range->start <= file_size)
-      expected_length =
-          std::min(range->end, (int) (file_size - 1)) - range->start + 1;
-    else
+    if (range->start <= file_size) {
+      expected_length = std::min(range->end, static_cast<int>(file_size - 1)) -
+                        range->start + 1;
+    } else {
       expected_length = 0;
+    }
   }
   request->Start();
 
@@ -170,8 +171,8 @@
   loop.Run();
 
   EXPECT_FALSE(delegate_.request_failed());
-  ASSERT_EQ(observer_.jobs().size(), 1u);
-  EXPECT_EQ(delegate_.bytes_received(), expected_length);
+  ASSERT_EQ(1, observer_.num_jobs_created());
+  EXPECT_EQ(expected_length, delegate_.bytes_received());
 }
 
 TEST_F(URLRequestContentJobTest, ContentURIWithoutRange) {
diff --git a/content/browser/appcache/appcache_database.cc b/content/browser/appcache/appcache_database.cc
index 8298bfb..aaa2ed2b 100644
--- a/content/browser/appcache/appcache_database.cc
+++ b/content/browser/appcache/appcache_database.cc
@@ -218,12 +218,12 @@
   ResetConnectionAndTables();
 }
 
-int64 AppCacheDatabase::GetOriginUsage(const GURL& origin) {
+int64_t AppCacheDatabase::GetOriginUsage(const GURL& origin) {
   std::vector<CacheRecord> records;
   if (!FindCachesForOrigin(origin, &records))
     return 0;
 
-  int64 origin_usage = 0;
+  int64_t origin_usage = 0;
   std::vector<CacheRecord>::const_iterator iter = records.begin();
   while (iter != records.end()) {
     origin_usage += iter->cache_size;
@@ -232,7 +232,7 @@
   return origin_usage;
 }
 
-bool AppCacheDatabase::GetAllOriginUsage(std::map<GURL, int64>* usage_map) {
+bool AppCacheDatabase::GetAllOriginUsage(std::map<GURL, int64_t>* usage_map) {
   std::set<GURL> origins;
   if (!FindOriginsWithGroups(&origins))
     return false;
@@ -260,8 +260,10 @@
 }
 
 bool AppCacheDatabase::FindLastStorageIds(
-    int64* last_group_id, int64* last_cache_id, int64* last_response_id,
-    int64* last_deletable_response_rowid) {
+    int64_t* last_group_id,
+    int64_t* last_cache_id,
+    int64_t* last_response_id,
+    int64_t* last_deletable_response_rowid) {
   DCHECK(last_group_id && last_cache_id && last_response_id &&
          last_deletable_response_rowid);
 
@@ -281,11 +283,11 @@
       "SELECT MAX(response_id) FROM DeletableResponseIds";
   const char* kMaxDeletableResponseRowIdSql =
       "SELECT MAX(rowid) FROM DeletableResponseIds";
-  int64 max_group_id;
-  int64 max_cache_id;
-  int64 max_response_id_from_entries;
-  int64 max_response_id_from_deletables;
-  int64 max_deletable_response_rowid;
+  int64_t max_group_id;
+  int64_t max_cache_id;
+  int64_t max_response_id_from_entries;
+  int64_t max_response_id_from_deletables;
+  int64_t max_deletable_response_rowid;
   if (!RunUniqueStatementWithInt64Result(kMaxGroupIdSql, &max_group_id) ||
       !RunUniqueStatementWithInt64Result(kMaxCacheIdSql, &max_cache_id) ||
       !RunUniqueStatementWithInt64Result(kMaxResponseIdFromEntriesSql,
@@ -305,7 +307,7 @@
   return true;
 }
 
-bool AppCacheDatabase::FindGroup(int64 group_id, GroupRecord* record) {
+bool AppCacheDatabase::FindGroup(int64_t group_id, GroupRecord* record) {
   DCHECK(record);
   if (!LazyOpen(kDontCreate))
     return false;
@@ -377,7 +379,8 @@
   return statement.Succeeded();
 }
 
-bool AppCacheDatabase::FindGroupForCache(int64 cache_id, GroupRecord* record) {
+bool AppCacheDatabase::FindGroupForCache(int64_t cache_id,
+                                         GroupRecord* record) {
   DCHECK(record);
   if (!LazyOpen(kDontCreate))
     return false;
@@ -420,7 +423,7 @@
   return statement.Run();
 }
 
-bool AppCacheDatabase::DeleteGroup(int64 group_id) {
+bool AppCacheDatabase::DeleteGroup(int64_t group_id) {
   if (!LazyOpen(kDontCreate))
     return false;
 
@@ -431,15 +434,14 @@
   return statement.Run();
 }
 
-bool AppCacheDatabase::UpdateLastAccessTime(
-    int64 group_id, base::Time time) {
+bool AppCacheDatabase::UpdateLastAccessTime(int64_t group_id, base::Time time) {
   if (!LazyUpdateLastAccessTime(group_id, time))
     return false;
   return CommitLazyLastAccessTimes();
 }
 
-bool AppCacheDatabase::LazyUpdateLastAccessTime(
-    int64 group_id, base::Time time) {
+bool AppCacheDatabase::LazyUpdateLastAccessTime(int64_t group_id,
+                                                base::Time time) {
   if (!LazyOpen(kCreateIfNeeded))
     return false;
   lazy_last_access_times_[group_id] = time;
@@ -468,7 +470,7 @@
 }
 
 bool AppCacheDatabase::UpdateEvictionTimes(
-    int64 group_id,
+    int64_t group_id,
     base::Time last_full_update_check_time,
     base::Time first_evictable_error_time) {
   if (!LazyOpen(kCreateIfNeeded))
@@ -485,7 +487,7 @@
   return statement.Run();  // Will succeed even if group_id is invalid.
 }
 
-bool AppCacheDatabase::FindCache(int64 cache_id, CacheRecord* record) {
+bool AppCacheDatabase::FindCache(int64_t cache_id, CacheRecord* record) {
   DCHECK(record);
   if (!LazyOpen(kDontCreate))
     return false;
@@ -504,7 +506,8 @@
   return true;
 }
 
-bool AppCacheDatabase::FindCacheForGroup(int64 group_id, CacheRecord* record) {
+bool AppCacheDatabase::FindCacheForGroup(int64_t group_id,
+                                         CacheRecord* record) {
   DCHECK(record);
   if (!LazyOpen(kDontCreate))
     return false;
@@ -559,7 +562,7 @@
   return statement.Run();
 }
 
-bool AppCacheDatabase::DeleteCache(int64 cache_id) {
+bool AppCacheDatabase::DeleteCache(int64_t cache_id) {
   if (!LazyOpen(kDontCreate))
     return false;
 
@@ -572,8 +575,8 @@
   return statement.Run();
 }
 
-bool AppCacheDatabase::FindEntriesForCache(
-    int64 cache_id, std::vector<EntryRecord>* records) {
+bool AppCacheDatabase::FindEntriesForCache(int64_t cache_id,
+                                           std::vector<EntryRecord>* records) {
   DCHECK(records && records->empty());
   if (!LazyOpen(kDontCreate))
     return false;
@@ -616,8 +619,9 @@
   return statement.Succeeded();
 }
 
-bool AppCacheDatabase::FindEntry(
-    int64 cache_id, const GURL& url, EntryRecord* record) {
+bool AppCacheDatabase::FindEntry(int64_t cache_id,
+                                 const GURL& url,
+                                 EntryRecord* record) {
   DCHECK(record);
   if (!LazyOpen(kDontCreate))
     return false;
@@ -673,7 +677,7 @@
   return transaction.Commit();
 }
 
-bool AppCacheDatabase::DeleteEntriesForCache(int64 cache_id) {
+bool AppCacheDatabase::DeleteEntriesForCache(int64_t cache_id) {
   if (!LazyOpen(kDontCreate))
     return false;
 
@@ -686,8 +690,9 @@
   return statement.Run();
 }
 
-bool AppCacheDatabase::AddEntryFlags(
-    const GURL& entry_url, int64 cache_id, int additional_flags) {
+bool AppCacheDatabase::AddEntryFlags(const GURL& entry_url,
+                                     int64_t cache_id,
+                                     int additional_flags) {
   if (!LazyOpen(kDontCreate))
     return false;
 
@@ -724,7 +729,7 @@
 }
 
 bool AppCacheDatabase::FindNamespacesForCache(
-    int64 cache_id,
+    int64_t cache_id,
     std::vector<NamespaceRecord>* intercepts,
     std::vector<NamespaceRecord>* fallbacks) {
   DCHECK(intercepts && intercepts->empty());
@@ -789,7 +794,7 @@
   return transaction.Commit();
 }
 
-bool AppCacheDatabase::DeleteNamespacesForCache(int64 cache_id) {
+bool AppCacheDatabase::DeleteNamespacesForCache(int64_t cache_id) {
   if (!LazyOpen(kDontCreate))
     return false;
 
@@ -803,7 +808,8 @@
 }
 
 bool AppCacheDatabase::FindOnlineWhiteListForCache(
-    int64 cache_id, std::vector<OnlineWhiteListRecord>* records) {
+    int64_t cache_id,
+    std::vector<OnlineWhiteListRecord>* records) {
   DCHECK(records && records->empty());
   if (!LazyOpen(kDontCreate))
     return false;
@@ -856,7 +862,7 @@
   return transaction.Commit();
 }
 
-bool AppCacheDatabase::DeleteOnlineWhiteListForCache(int64 cache_id) {
+bool AppCacheDatabase::DeleteOnlineWhiteListForCache(int64_t cache_id) {
   if (!LazyOpen(kDontCreate))
     return false;
 
@@ -870,7 +876,9 @@
 }
 
 bool AppCacheDatabase::GetDeletableResponseIds(
-    std::vector<int64>* response_ids, int64 max_rowid, int limit) {
+    std::vector<int64_t>* response_ids,
+    int64_t max_rowid,
+    int limit) {
   if (!LazyOpen(kDontCreate))
     return false;
 
@@ -889,22 +897,23 @@
 }
 
 bool AppCacheDatabase::InsertDeletableResponseIds(
-    const std::vector<int64>& response_ids) {
+    const std::vector<int64_t>& response_ids) {
   const char kSql[] =
       "INSERT INTO DeletableResponseIds (response_id) VALUES (?)";
   return RunCachedStatementWithIds(SQL_FROM_HERE, kSql, response_ids);
 }
 
 bool AppCacheDatabase::DeleteDeletableResponseIds(
-    const std::vector<int64>& response_ids) {
+    const std::vector<int64_t>& response_ids) {
   const char kSql[] =
       "DELETE FROM DeletableResponseIds WHERE response_id = ?";
   return RunCachedStatementWithIds(SQL_FROM_HERE, kSql, response_ids);
 }
 
 bool AppCacheDatabase::RunCachedStatementWithIds(
-    const sql::StatementID& statement_id, const char* sql,
-    const std::vector<int64>& ids) {
+    const sql::StatementID& statement_id,
+    const char* sql,
+    const std::vector<int64_t>& ids) {
   DCHECK(sql);
   if (!LazyOpen(kCreateIfNeeded))
     return false;
@@ -915,7 +924,7 @@
 
   sql::Statement statement(db_->GetCachedStatement(statement_id, sql));
 
-  std::vector<int64>::const_iterator iter = ids.begin();
+  std::vector<int64_t>::const_iterator iter = ids.begin();
   while (iter != ids.end()) {
     statement.BindInt64(0, *iter);
     if (!statement.Run())
@@ -927,8 +936,8 @@
   return transaction.Commit();
 }
 
-bool AppCacheDatabase::RunUniqueStatementWithInt64Result(
-    const char* sql, int64* result) {
+bool AppCacheDatabase::RunUniqueStatementWithInt64Result(const char* sql,
+                                                         int64_t* result) {
   DCHECK(sql);
   sql::Statement statement(db_->GetUniqueStatement(sql));
   if (!statement.Step()) {
@@ -939,8 +948,9 @@
 }
 
 bool AppCacheDatabase::FindResponseIdsForCacheHelper(
-    int64 cache_id, std::vector<int64>* ids_vector,
-    std::set<int64>* ids_set) {
+    int64_t cache_id,
+    std::vector<int64_t>* ids_vector,
+    std::set<int64_t>* ids_set) {
   DCHECK(ids_vector || ids_set);
   DCHECK(!(ids_vector && ids_set));
   if (!LazyOpen(kDontCreate))
@@ -953,7 +963,7 @@
 
   statement.BindInt64(0, cache_id);
   while (statement.Step()) {
-    int64 id = statement.ColumnInt64(0);
+    int64_t id = statement.ColumnInt64(0);
     if (ids_set)
       ids_set->insert(id);
     else
diff --git a/content/browser/appcache/appcache_database.h b/content/browser/appcache/appcache_database.h
index 6addf90..2b628a3 100644
--- a/content/browser/appcache/appcache_database.h
+++ b/content/browser/appcache/appcache_database.h
@@ -5,11 +5,12 @@
 #ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_DATABASE_H_
 #define CONTENT_BROWSER_APPCACHE_APPCACHE_DATABASE_H_
 
+#include <stdint.h>
+
 #include <map>
 #include <set>
 #include <vector>
 
-#include "base/basictypes.h"
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
@@ -51,7 +52,7 @@
     GroupRecord();
     ~GroupRecord();
 
-    int64 group_id;
+    int64_t group_id;
     GURL origin;
     GURL manifest_url;
     base::Time creation_time;
@@ -64,28 +65,28 @@
     CacheRecord()
         : cache_id(0), group_id(0), online_wildcard(false), cache_size(0) {}
 
-    int64 cache_id;
-    int64 group_id;
+    int64_t cache_id;
+    int64_t group_id;
     bool online_wildcard;
     base::Time update_time;
-    int64 cache_size;  // the sum of all response sizes in this cache
+    int64_t cache_size;  // the sum of all response sizes in this cache
   };
 
   struct EntryRecord {
     EntryRecord() : cache_id(0), flags(0), response_id(0), response_size(0) {}
 
-    int64 cache_id;
+    int64_t cache_id;
     GURL url;
     int flags;
-    int64 response_id;
-    int64 response_size;
+    int64_t response_id;
+    int64_t response_size;
   };
 
   struct CONTENT_EXPORT NamespaceRecord {
     NamespaceRecord();
     ~NamespaceRecord();
 
-    int64 cache_id;
+    int64_t cache_id;
     GURL origin;
     AppCacheNamespace namespace_;
   };
@@ -95,7 +96,7 @@
   struct OnlineWhiteListRecord {
     OnlineWhiteListRecord() : cache_id(0), is_pattern(false) {}
 
-    int64 cache_id;
+    int64_t cache_id;
     GURL namespace_url;
     bool is_pattern;
   };
@@ -107,58 +108,57 @@
   bool is_disabled() const { return is_disabled_; }
   bool was_corruption_detected() const { return was_corruption_detected_; }
 
-  int64 GetOriginUsage(const GURL& origin);
-  bool GetAllOriginUsage(std::map<GURL, int64>* usage_map);
+  int64_t GetOriginUsage(const GURL& origin);
+  bool GetAllOriginUsage(std::map<GURL, int64_t>* usage_map);
 
   bool FindOriginsWithGroups(std::set<GURL>* origins);
-  bool FindLastStorageIds(
-      int64* last_group_id, int64* last_cache_id, int64* last_response_id,
-      int64* last_deletable_response_rowid);
+  bool FindLastStorageIds(int64_t* last_group_id,
+                          int64_t* last_cache_id,
+                          int64_t* last_response_id,
+                          int64_t* last_deletable_response_rowid);
 
-  bool FindGroup(int64 group_id, GroupRecord* record);
+  bool FindGroup(int64_t group_id, GroupRecord* record);
   bool FindGroupForManifestUrl(const GURL& manifest_url, GroupRecord* record);
   bool FindGroupsForOrigin(
       const GURL& origin, std::vector<GroupRecord>* records);
-  bool FindGroupForCache(int64 cache_id, GroupRecord* record);
+  bool FindGroupForCache(int64_t cache_id, GroupRecord* record);
   bool InsertGroup(const GroupRecord* record);
-  bool DeleteGroup(int64 group_id);
+  bool DeleteGroup(int64_t group_id);
 
   // The access and eviction time update methods do not fail when
   // given invalid group_ids. The return value only indicates whether
   // the database is functioning.
-  bool UpdateLastAccessTime(int64 group_id,
-                            base::Time last_access_time);
-  bool LazyUpdateLastAccessTime(int64 group_id,
-                                base::Time last_access_time);
-  bool UpdateEvictionTimes(int64 group_id,
+  bool UpdateLastAccessTime(int64_t group_id, base::Time last_access_time);
+  bool LazyUpdateLastAccessTime(int64_t group_id, base::Time last_access_time);
+  bool UpdateEvictionTimes(int64_t group_id,
                            base::Time last_full_update_check_time,
                            base::Time first_evictable_error_time);
   bool CommitLazyLastAccessTimes();  // The destructor calls this too.
 
-  bool FindCache(int64 cache_id, CacheRecord* record);
-  bool FindCacheForGroup(int64 group_id, CacheRecord* record);
+  bool FindCache(int64_t cache_id, CacheRecord* record);
+  bool FindCacheForGroup(int64_t group_id, CacheRecord* record);
   bool FindCachesForOrigin(
       const GURL& origin, std::vector<CacheRecord>* records);
   bool InsertCache(const CacheRecord* record);
-  bool DeleteCache(int64 cache_id);
+  bool DeleteCache(int64_t cache_id);
 
-  bool FindEntriesForCache(
-      int64 cache_id, std::vector<EntryRecord>* records);
+  bool FindEntriesForCache(int64_t cache_id, std::vector<EntryRecord>* records);
   bool FindEntriesForUrl(
       const GURL& url, std::vector<EntryRecord>* records);
-  bool FindEntry(int64 cache_id, const GURL& url, EntryRecord* record);
+  bool FindEntry(int64_t cache_id, const GURL& url, EntryRecord* record);
   bool InsertEntry(const EntryRecord* record);
   bool InsertEntryRecords(
       const std::vector<EntryRecord>& records);
-  bool DeleteEntriesForCache(int64 cache_id);
-  bool AddEntryFlags(const GURL& entry_url, int64 cache_id,
+  bool DeleteEntriesForCache(int64_t cache_id);
+  bool AddEntryFlags(const GURL& entry_url,
+                     int64_t cache_id,
                      int additional_flags);
-  bool FindResponseIdsForCacheAsVector(
-      int64 cache_id, std::vector<int64>* response_ids) {
+  bool FindResponseIdsForCacheAsVector(int64_t cache_id,
+                                       std::vector<int64_t>* response_ids) {
     return FindResponseIdsForCacheHelper(cache_id, response_ids, NULL);
   }
-  bool FindResponseIdsForCacheAsSet(
-      int64 cache_id, std::set<int64>* response_ids) {
+  bool FindResponseIdsForCacheAsSet(int64_t cache_id,
+                                    std::set<int64_t>* response_ids) {
     return FindResponseIdsForCacheHelper(cache_id, NULL, response_ids);
   }
 
@@ -166,26 +166,26 @@
       const GURL& origin,
       NamespaceRecordVector* intercepts,
       NamespaceRecordVector* fallbacks);
-  bool FindNamespacesForCache(
-      int64 cache_id,
-      NamespaceRecordVector* intercepts,
-      std::vector<NamespaceRecord>* fallbacks);
+  bool FindNamespacesForCache(int64_t cache_id,
+                              NamespaceRecordVector* intercepts,
+                              std::vector<NamespaceRecord>* fallbacks);
   bool InsertNamespaceRecords(
       const NamespaceRecordVector& records);
   bool InsertNamespace(const NamespaceRecord* record);
-  bool DeleteNamespacesForCache(int64 cache_id);
+  bool DeleteNamespacesForCache(int64_t cache_id);
 
-  bool FindOnlineWhiteListForCache(
-      int64 cache_id, std::vector<OnlineWhiteListRecord>* records);
+  bool FindOnlineWhiteListForCache(int64_t cache_id,
+                                   std::vector<OnlineWhiteListRecord>* records);
   bool InsertOnlineWhiteList(const OnlineWhiteListRecord* record);
   bool InsertOnlineWhiteListRecords(
       const std::vector<OnlineWhiteListRecord>& records);
-  bool DeleteOnlineWhiteListForCache(int64 cache_id);
+  bool DeleteOnlineWhiteListForCache(int64_t cache_id);
 
-  bool GetDeletableResponseIds(std::vector<int64>* response_ids,
-                               int64 max_rowid, int limit);
-  bool InsertDeletableResponseIds(const std::vector<int64>& response_ids);
-  bool DeleteDeletableResponseIds(const std::vector<int64>& response_ids);
+  bool GetDeletableResponseIds(std::vector<int64_t>* response_ids,
+                               int64_t max_rowid,
+                               int limit);
+  bool InsertDeletableResponseIds(const std::vector<int64_t>& response_ids);
+  bool DeleteDeletableResponseIds(const std::vector<int64_t>& response_ids);
 
   // So our callers can wrap operations in transactions.
   sql::Connection* db_connection() {
@@ -194,14 +194,14 @@
   }
 
  private:
-  bool RunCachedStatementWithIds(
-      const sql::StatementID& statement_id, const char* sql,
-      const std::vector<int64>& ids);
-  bool RunUniqueStatementWithInt64Result(const char* sql, int64* result);
+  bool RunCachedStatementWithIds(const sql::StatementID& statement_id,
+                                 const char* sql,
+                                 const std::vector<int64_t>& ids);
+  bool RunUniqueStatementWithInt64Result(const char* sql, int64_t* result);
 
-  bool FindResponseIdsForCacheHelper(
-      int64 cache_id, std::vector<int64>* ids_vector,
-      std::set<int64>* ids_set);
+  bool FindResponseIdsForCacheHelper(int64_t cache_id,
+                                     std::vector<int64_t>* ids_vector,
+                                     std::set<int64_t>* ids_set);
 
   // Record retrieval helpers
   void ReadGroupRecord(const sql::Statement& statement, GroupRecord* record);
@@ -234,7 +234,7 @@
   base::FilePath db_file_path_;
   scoped_ptr<sql::Connection> db_;
   scoped_ptr<sql::MetaTable> meta_table_;
-  std::map<int64, base::Time> lazy_last_access_times_;
+  std::map<int64_t, base::Time> lazy_last_access_times_;
   bool is_disabled_;
   bool is_recreating_;
   bool was_corruption_detected_;
diff --git a/content/browser/appcache/appcache_database_unittest.cc b/content/browser/appcache/appcache_database_unittest.cc
index f786df6..2f09a02 100644
--- a/content/browser/appcache/appcache_database_unittest.cc
+++ b/content/browser/appcache/appcache_database_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <limits>
+
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
@@ -35,7 +37,7 @@
   EXPECT_FALSE(db.LazyOpen(false));
   EXPECT_TRUE(db.LazyOpen(true));
 
-  int64 group_id, cache_id, response_id, deleteable_response_rowid;
+  int64_t group_id, cache_id, response_id, deleteable_response_rowid;
   group_id = cache_id = response_id = deleteable_response_rowid = 0;
   EXPECT_TRUE(db.FindLastStorageIds(&group_id, &cache_id, &response_id,
                                     &deleteable_response_rowid));
@@ -135,7 +137,7 @@
   {
     sql::ScopedErrorIgnorer ignore_errors;
     ignore_errors.IgnoreError(SQLITE_CORRUPT);
-    std::map<GURL, int64> usage_map;
+    std::map<GURL, int64_t> usage_map;
     EXPECT_FALSE(db.GetAllOriginUsage(&usage_map));
     EXPECT_TRUE(db.was_corruption_detected());
     EXPECT_TRUE(base::PathExists(kDbFile));
@@ -680,20 +682,22 @@
   // TODO(shess): See EntryRecords test.
   ignore_errors.IgnoreError(SQLITE_CONSTRAINT);
 
-  std::vector<int64> ids;
+  std::vector<int64_t> ids;
 
-  EXPECT_TRUE(db.GetDeletableResponseIds(&ids, kint64max, 100));
+  EXPECT_TRUE(db.GetDeletableResponseIds(
+      &ids, std::numeric_limits<int64_t>::max(), 100));
   EXPECT_TRUE(ids.empty());
   ids.push_back(0);
   EXPECT_TRUE(db.DeleteDeletableResponseIds(ids));
   EXPECT_TRUE(db.InsertDeletableResponseIds(ids));
 
   ids.clear();
-  EXPECT_TRUE(db.GetDeletableResponseIds(&ids, kint64max, 100));
+  EXPECT_TRUE(db.GetDeletableResponseIds(
+      &ids, std::numeric_limits<int64_t>::max(), 100));
   EXPECT_EQ(1U, ids.size());
   EXPECT_EQ(0, ids[0]);
 
-  int64 unused, deleteable_response_rowid;
+  int64_t unused, deleteable_response_rowid;
   unused = deleteable_response_rowid = 0;
   EXPECT_TRUE(db.FindLastStorageIds(&unused, &unused, &unused,
                                     &deleteable_response_rowid));
@@ -715,14 +719,16 @@
   EXPECT_EQ(10, deleteable_response_rowid);
 
   ids.clear();
-  EXPECT_TRUE(db.GetDeletableResponseIds(&ids, kint64max, 100));
+  EXPECT_TRUE(db.GetDeletableResponseIds(
+      &ids, std::numeric_limits<int64_t>::max(), 100));
   EXPECT_EQ(10U, ids.size());
   for (int i = 0; i < 10; ++i)
     EXPECT_EQ(i, ids[i]);
 
   // Ensure the limit is respected.
   ids.clear();
-  EXPECT_TRUE(db.GetDeletableResponseIds(&ids, kint64max, 5));
+  EXPECT_TRUE(
+      db.GetDeletableResponseIds(&ids, std::numeric_limits<int64_t>::max(), 5));
   EXPECT_EQ(5U, ids.size());
   for (int i = 0; i < static_cast<int>(ids.size()); ++i)
     EXPECT_EQ(i, ids[i]);
@@ -737,7 +743,8 @@
   // Ensure that we can delete from the table.
   EXPECT_TRUE(db.DeleteDeletableResponseIds(ids));
   ids.clear();
-  EXPECT_TRUE(db.GetDeletableResponseIds(&ids, kint64max, 100));
+  EXPECT_TRUE(db.GetDeletableResponseIds(
+      &ids, std::numeric_limits<int64_t>::max(), 100));
   EXPECT_EQ(5U, ids.size());
   for (int i = 0; i < static_cast<int>(ids.size()); ++i)
     EXPECT_EQ(i + 5, ids[i]);
@@ -808,7 +815,7 @@
   EXPECT_TRUE(db.FindCachesForOrigin(kOtherOrigin, &cache_records));
   EXPECT_EQ(1U, cache_records.size());
 
-  std::map<GURL, int64> usage_map;
+  std::map<GURL, int64_t> usage_map;
   EXPECT_TRUE(db.GetAllOriginUsage(&usage_map));
   EXPECT_EQ(2U, usage_map.size());
   EXPECT_EQ(1100, usage_map[kOrigin]);
diff --git a/content/browser/appcache/appcache_request_handler.cc b/content/browser/appcache/appcache_request_handler.cc
index 485c794..450b43165 100644
--- a/content/browser/appcache/appcache_request_handler.cc
+++ b/content/browser/appcache/appcache_request_handler.cc
@@ -76,7 +76,7 @@
   found_manifest_url_ = GURL();
   found_network_namespace_ = false;
 
-  AppCacheURLRequestJob* job;
+  scoped_ptr<AppCacheURLRequestJob> job;
   if (is_main_resource())
     job = MaybeLoadMainResource(request, network_delegate);
   else
@@ -87,15 +87,10 @@
   // have been started yet.
   if (job && job->is_delivering_network_response()) {
     DCHECK(!job->has_been_started());
-    // Create and destroy job.
-    // TODO(mmenke): Once URLRequestJobs are no longer reference counted, it
-    // should be passed around as a scoped_ptr, and this will just be a Reset()
-    // call on the scoped_ptr returned by a method called above.
-    scoped_refptr<AppCacheURLRequestJob> job_owner(job);
-    job = nullptr;
+    job.reset();
   }
 
-  return job;
+  return job.release();
 }
 
 AppCacheURLRequestJob* AppCacheRequestHandler::MaybeLoadFallbackForRedirect(
@@ -116,7 +111,7 @@
 
   DCHECK(!job_.get());  // our jobs never generate redirects
 
-  AppCacheURLRequestJob* job = nullptr;
+  scoped_ptr<AppCacheURLRequestJob> job;
   if (found_fallback_entry_.has_response_id()) {
     // 6.9.6, step 4: If this results in a redirect to another origin,
     // get the resource of the fallback entry.
@@ -132,7 +127,7 @@
     // 6.9.6 step 3 and 5: Fetch the resource normally.
   }
 
-  return job;
+  return job.release();
 }
 
 AppCacheURLRequestJob* AppCacheRequestHandler::MaybeLoadFallbackForResponse(
@@ -173,11 +168,11 @@
 
   // 6.9.6, step 4: If this results in a 4xx or 5xx status code
   // or there were network errors, get the resource of the fallback entry.
-  AppCacheURLRequestJob* job = CreateJob(request, network_delegate);
+  scoped_ptr<AppCacheURLRequestJob> job = CreateJob(request, network_delegate);
   DeliverAppCachedResponse(
       found_fallback_entry_, found_cache_id_, found_group_id_,
       found_manifest_url_, true, found_namespace_entry_url_);
-  return job;
+  return job.release();
 }
 
 void AppCacheRequestHandler::GetExtraResponseInfo(
@@ -274,20 +269,20 @@
   job_.reset();
 }
 
-AppCacheURLRequestJob* AppCacheRequestHandler::CreateJob(
+scoped_ptr<AppCacheURLRequestJob> AppCacheRequestHandler::CreateJob(
     net::URLRequest* request,
     net::NetworkDelegate* network_delegate) {
-  AppCacheURLRequestJob* job = new AppCacheURLRequestJob(
+  scoped_ptr<AppCacheURLRequestJob> job(new AppCacheURLRequestJob(
       request, network_delegate, storage(), host_, is_main_resource(),
       base::Bind(&AppCacheRequestHandler::OnPrepareToRestart,
-                 base::Unretained(this)));
+                 base::Unretained(this))));
   job_ = job->GetWeakPtr();
   return job;
 }
 
 // Main-resource handling ----------------------------------------------
 
-AppCacheURLRequestJob* AppCacheRequestHandler::MaybeLoadMainResource(
+scoped_ptr<AppCacheURLRequestJob> AppCacheRequestHandler::MaybeLoadMainResource(
     net::URLRequest* request,
     net::NetworkDelegate* network_delegate) {
   DCHECK(!job_.get());
@@ -311,7 +306,7 @@
 
   // We may have to wait for our storage query to complete, but
   // this query can also complete syncrhonously.
-  AppCacheURLRequestJob* job = CreateJob(request, network_delegate);
+  scoped_ptr<AppCacheURLRequestJob> job = CreateJob(request, network_delegate);
   storage()->FindResponseForMainRequest(
       request->url(), preferred_manifest_url, this);
   return job;
@@ -385,7 +380,7 @@
 
 // Sub-resource handling ----------------------------------------------
 
-AppCacheURLRequestJob* AppCacheRequestHandler::MaybeLoadSubResource(
+scoped_ptr<AppCacheURLRequestJob> AppCacheRequestHandler::MaybeLoadSubResource(
     net::URLRequest* request,
     net::NetworkDelegate* network_delegate) {
   DCHECK(!job_.get());
@@ -403,7 +398,7 @@
     return nullptr;
   }
 
-  AppCacheURLRequestJob* job = CreateJob(request, network_delegate);
+  scoped_ptr<AppCacheURLRequestJob> job = CreateJob(request, network_delegate);
   ContinueMaybeLoadSubResource();
   return job;
 }
diff --git a/content/browser/appcache/appcache_request_handler.h b/content/browser/appcache/appcache_request_handler.h
index e3c6602..b801602 100644
--- a/content/browser/appcache/appcache_request_handler.h
+++ b/content/browser/appcache/appcache_request_handler.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_APPCACHE_APPCACHE_REQUEST_HANDLER_H_
 
 #include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/supports_user_data.h"
 #include "content/browser/appcache/appcache_entry.h"
@@ -84,8 +85,9 @@
 
   // Helper method to create an AppCacheURLRequestJob and populate job_.
   // Caller takes ownership of returned value.
-  AppCacheURLRequestJob* CreateJob(net::URLRequest* request,
-                                   net::NetworkDelegate* network_delegate);
+  scoped_ptr<AppCacheURLRequestJob> CreateJob(
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate);
 
   // Helper to retrieve a pointer to the storage object.
   AppCacheStorage* storage() const;
@@ -97,7 +99,7 @@
   // Main-resource loading -------------------------------------
   // Frame and SharedWorker main resources are handled here.
 
-  AppCacheURLRequestJob* MaybeLoadMainResource(
+  scoped_ptr<AppCacheURLRequestJob> MaybeLoadMainResource(
       net::URLRequest* request,
       net::NetworkDelegate* network_delegate);
 
@@ -113,7 +115,7 @@
   // Sub-resource loading -------------------------------------
   // Dedicated worker and all manner of sub-resources are handled here.
 
-  AppCacheURLRequestJob* MaybeLoadSubResource(
+  scoped_ptr<AppCacheURLRequestJob> MaybeLoadSubResource(
       net::URLRequest* request,
       net::NetworkDelegate* network_delegate);
   void ContinueMaybeLoadSubResource();
diff --git a/content/browser/appcache/appcache_request_handler_unittest.cc b/content/browser/appcache/appcache_request_handler_unittest.cc
index 5aa3ca1..2d08cc3 100644
--- a/content/browser/appcache/appcache_request_handler_unittest.cc
+++ b/content/browser/appcache/appcache_request_handler_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/location.h"
+#include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/thread_task_runner_handle.h"
@@ -92,8 +93,9 @@
           has_response_info_(true),
           response_info_(info) {}
 
-   protected:
     ~MockURLRequestJob() override {}
+
+   protected:
     void Start() override { NotifyHeadersComplete(); }
     int GetResponseCode() const override { return response_code_; }
     void GetResponseInfo(net::HttpResponseInfo* info) override {
@@ -110,30 +112,23 @@
 
   class MockURLRequestJobFactory : public net::URLRequestJobFactory {
    public:
-    MockURLRequestJobFactory() : job_(NULL) {
-    }
+    MockURLRequestJobFactory() {}
 
     ~MockURLRequestJobFactory() override { DCHECK(!job_); }
 
-    void SetJob(net::URLRequestJob* job) {
-      job_ = job;
-    }
+    void SetJob(scoped_ptr<net::URLRequestJob> job) { job_ = job.Pass(); }
 
     net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
         const std::string& scheme,
         net::URLRequest* request,
         net::NetworkDelegate* network_delegate) const override {
-      if (job_) {
-        net::URLRequestJob* temp = job_;
-        job_ = NULL;
-        return temp;
-      } else {
-        // Some of these tests trigger UpdateJobs which start URLRequests.
-        // We short circuit those be returning error jobs.
-        return new net::URLRequestErrorJob(request,
-                                           network_delegate,
-                                           net::ERR_INTERNET_DISCONNECTED);
-      }
+      if (job_)
+        return job_.release();
+
+      // Some of these tests trigger UpdateJobs which start URLRequests.
+      // We short circuit those be returning error jobs.
+      return new net::URLRequestErrorJob(request, network_delegate,
+                                         net::ERR_INTERNET_DISCONNECTED);
     }
 
     net::URLRequestJob* MaybeInterceptRedirect(
@@ -162,7 +157,7 @@
     }
 
    private:
-    mutable net::URLRequestJob* job_;
+    mutable scoped_ptr<net::URLRequestJob> job_;
   };
 
   static void SetUpTestCase() {
@@ -261,8 +256,8 @@
                                                false));
     EXPECT_TRUE(handler_.get());
 
-    job_ = handler_->MaybeLoadResource(request_.get(),
-                                       request_->context()->network_delegate());
+    job_.reset(handler_->MaybeLoadResource(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_TRUE(job_.get());
     EXPECT_TRUE(job_->is_waiting());
 
@@ -281,14 +276,13 @@
     EXPECT_EQ(GURL(), manifest_url);
     EXPECT_EQ(0, handler_->found_group_id_);
 
-    AppCacheURLRequestJob* fallback_job;
-    fallback_job = handler_->MaybeLoadFallbackForRedirect(
-        request_.get(),
-        request_->context()->network_delegate(),
-        GURL("http://blah/redirect"));
+    scoped_ptr<AppCacheURLRequestJob> fallback_job(
+        handler_->MaybeLoadFallbackForRedirect(
+            request_.get(), request_->context()->network_delegate(),
+            GURL("http://blah/redirect")));
     EXPECT_FALSE(fallback_job);
-    fallback_job = handler_->MaybeLoadFallbackForResponse(
-        request_.get(), request_->context()->network_delegate());
+    fallback_job.reset(handler_->MaybeLoadFallbackForResponse(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_FALSE(fallback_job);
 
     EXPECT_TRUE(host_->preferred_manifest_url().is_empty());
@@ -315,8 +309,8 @@
         GURL(), AppCacheEntry(),
         1, 2, GURL("http://blah/manifest/"));
 
-    job_ = handler_->MaybeLoadResource(request_.get(),
-                                       request_->context()->network_delegate());
+    job_.reset(handler_->MaybeLoadResource(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_TRUE(job_.get());
     EXPECT_TRUE(job_->is_waiting());
 
@@ -335,9 +329,9 @@
     EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url);
     EXPECT_EQ(2, handler_->found_group_id_);
 
-    AppCacheURLRequestJob* fallback_job;
-    fallback_job = handler_->MaybeLoadFallbackForResponse(
-        request_.get(), request_->context()->network_delegate());
+    scoped_ptr<AppCacheURLRequestJob> fallback_job(
+        handler_->MaybeLoadFallbackForResponse(
+            request_.get(), request_->context()->network_delegate()));
     EXPECT_FALSE(fallback_job);
 
     EXPECT_EQ(GURL("http://blah/manifest/"),
@@ -366,8 +360,8 @@
         AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
         1, 2, GURL("http://blah/manifest/"));
 
-    job_ = handler_->MaybeLoadResource(request_.get(),
-                                       request_->context()->network_delegate());
+    job_.reset(handler_->MaybeLoadResource(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_TRUE(job_.get());
     EXPECT_TRUE(job_->is_waiting());
 
@@ -376,11 +370,9 @@
   }
 
   void SimulateResponseCode(int response_code) {
-    job_factory_->SetJob(
-        new MockURLRequestJob(
-            request_.get(),
-            request_->context()->network_delegate(),
-            response_code));
+    job_factory_->SetJob(make_scoped_ptr(new MockURLRequestJob(
+        request_.get(), request_->context()->network_delegate(),
+        response_code)));
     request_->Start();
     // All our simulation needs  to satisfy are the following two DCHECKs
     DCHECK(request_->status().is_success());
@@ -388,10 +380,8 @@
   }
 
   void SimulateResponseInfo(const net::HttpResponseInfo& info) {
-    job_factory_->SetJob(
-        new MockURLRequestJob(
-            request_.get(),
-            request_->context()->network_delegate(), info));
+    job_factory_->SetJob(make_scoped_ptr(new MockURLRequestJob(
+        request_.get(), request_->context()->network_delegate(), info)));
     request_->Start();
   }
 
@@ -406,15 +396,15 @@
     // When the request is restarted, the existing job is dropped so a
     // real network job gets created. We expect NULL here which will cause
     // the net library to create a real job.
-    job_ = handler_->MaybeLoadResource(request_.get(),
-                                       request_->context()->network_delegate());
+    job_.reset(handler_->MaybeLoadResource(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_FALSE(job_.get());
 
     // Simulate an http error of the real network job.
     SimulateResponseCode(500);
 
-    job_ = handler_->MaybeLoadFallbackForResponse(
-        request_.get(), request_->context()->network_delegate());
+    job_.reset(handler_->MaybeLoadFallbackForResponse(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_TRUE(job_.get());
     EXPECT_TRUE(job_->is_delivering_appcache_response());
 
@@ -453,8 +443,8 @@
         AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
         1, 2, GURL("http://blah/manifest/"));
 
-    job_ = handler_->MaybeLoadResource(request_.get(),
-                                       request_->context()->network_delegate());
+    job_.reset(handler_->MaybeLoadResource(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_TRUE(job_.get());
     EXPECT_TRUE(job_->is_waiting());
 
@@ -473,8 +463,8 @@
     // When the request is restarted, the existing job is dropped so a
     // real network job gets created. We expect NULL here which will cause
     // the net library to create a real job.
-    job_ = handler_->MaybeLoadResource(request_.get(),
-                                       request_->context()->network_delegate());
+    job_.reset(handler_->MaybeLoadResource(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_FALSE(job_.get());
 
     // Simulate an http error of the real network job, but with custom
@@ -488,8 +478,8 @@
         std::string(kOverrideHeaders, arraysize(kOverrideHeaders)));
     SimulateResponseInfo(info);
 
-    job_ = handler_->MaybeLoadFallbackForResponse(
-        request_.get(), request_->context()->network_delegate());
+    job_.reset(handler_->MaybeLoadFallbackForResponse(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_FALSE(job_.get());
 
     // GetExtraResponseInfo should return no information.
@@ -532,19 +522,18 @@
                                                false));
     EXPECT_TRUE(handler_.get());
 
-    job_ = handler_->MaybeLoadResource(request_.get(),
-                                       request_->context()->network_delegate());
+    job_.reset(handler_->MaybeLoadResource(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_TRUE(job_.get());
     EXPECT_TRUE(job_->is_delivering_error_response());
 
-    AppCacheURLRequestJob* fallback_job;
-    fallback_job = handler_->MaybeLoadFallbackForRedirect(
-        request_.get(),
-        request_->context()->network_delegate(),
-        GURL("http://blah/redirect"));
+    scoped_ptr<AppCacheURLRequestJob> fallback_job(
+        handler_->MaybeLoadFallbackForRedirect(
+            request_.get(), request_->context()->network_delegate(),
+            GURL("http://blah/redirect")));
     EXPECT_FALSE(fallback_job);
-    fallback_job = handler_->MaybeLoadFallbackForResponse(
-        request_.get(), request_->context()->network_delegate());
+    fallback_job.reset(handler_->MaybeLoadFallbackForResponse(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_FALSE(fallback_job);
 
     TestFinished();
@@ -564,8 +553,8 @@
                                                RESOURCE_TYPE_SUB_RESOURCE,
                                                false));
     EXPECT_TRUE(handler_.get());
-    job_ = handler_->MaybeLoadResource(request_.get(),
-                                       request_->context()->network_delegate());
+    job_.reset(handler_->MaybeLoadResource(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_TRUE(job_.get());
     EXPECT_TRUE(job_->is_waiting());
 
@@ -573,14 +562,13 @@
     EXPECT_FALSE(job_->is_waiting());
     EXPECT_TRUE(job_->is_delivering_error_response());
 
-    AppCacheURLRequestJob* fallback_job;
-    fallback_job = handler_->MaybeLoadFallbackForRedirect(
-        request_.get(),
-        request_->context()->network_delegate(),
-        GURL("http://blah/redirect"));
+    scoped_ptr<AppCacheURLRequestJob> fallback_job(
+        handler_->MaybeLoadFallbackForRedirect(
+            request_.get(), request_->context()->network_delegate(),
+            GURL("http://blah/redirect")));
     EXPECT_FALSE(fallback_job);
-    fallback_job = handler_->MaybeLoadFallbackForResponse(
-        request_.get(), request_->context()->network_delegate());
+    fallback_job.reset(handler_->MaybeLoadFallbackForResponse(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_FALSE(fallback_job);
 
     TestFinished();
@@ -600,19 +588,18 @@
                                                RESOURCE_TYPE_SUB_RESOURCE,
                                                false));
     EXPECT_TRUE(handler_.get());
-    job_ = handler_->MaybeLoadResource(request_.get(),
-                                       request_->context()->network_delegate());
+    job_.reset(handler_->MaybeLoadResource(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_TRUE(job_.get());
     EXPECT_TRUE(job_->is_delivering_appcache_response());
 
-    AppCacheURLRequestJob* fallback_job;
-    fallback_job = handler_->MaybeLoadFallbackForRedirect(
-        request_.get(),
-        request_->context()->network_delegate(),
-        GURL("http://blah/redirect"));
+    scoped_ptr<AppCacheURLRequestJob> fallback_job(
+        handler_->MaybeLoadFallbackForRedirect(
+            request_.get(), request_->context()->network_delegate(),
+            GURL("http://blah/redirect")));
     EXPECT_FALSE(fallback_job);
-    fallback_job = handler_->MaybeLoadFallbackForResponse(
-        request_.get(), request_->context()->network_delegate());
+    fallback_job.reset(handler_->MaybeLoadFallbackForResponse(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_FALSE(fallback_job);
 
     TestFinished();
@@ -634,20 +621,19 @@
                                                RESOURCE_TYPE_SUB_RESOURCE,
                                                false));
     EXPECT_TRUE(handler_.get());
-    job_ = handler_->MaybeLoadResource(request_.get(),
-                                       request_->context()->network_delegate());
+    job_.reset(handler_->MaybeLoadResource(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_FALSE(job_.get());
 
-    job_ = handler_->MaybeLoadFallbackForRedirect(
-        request_.get(),
-        request_->context()->network_delegate(),
-        GURL("http://not_blah/redirect"));
+    job_.reset(handler_->MaybeLoadFallbackForRedirect(
+        request_.get(), request_->context()->network_delegate(),
+        GURL("http://not_blah/redirect")));
     EXPECT_TRUE(job_.get());
     EXPECT_TRUE(job_->is_delivering_appcache_response());
 
-    AppCacheURLRequestJob* fallback_job;
-    fallback_job = handler_->MaybeLoadFallbackForResponse(
-        request_.get(), request_->context()->network_delegate());
+    scoped_ptr<AppCacheURLRequestJob> fallback_job(
+        handler_->MaybeLoadFallbackForResponse(
+            request_.get(), request_->context()->network_delegate()));
     EXPECT_FALSE(fallback_job);
 
     TestFinished();
@@ -669,20 +655,19 @@
                                                RESOURCE_TYPE_SUB_RESOURCE,
                                                false));
     EXPECT_TRUE(handler_.get());
-    job_ = handler_->MaybeLoadResource(request_.get(),
-                                       request_->context()->network_delegate());
+    job_.reset(handler_->MaybeLoadResource(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_FALSE(job_.get());
 
-    AppCacheURLRequestJob* fallback_job;
-    fallback_job = handler_->MaybeLoadFallbackForRedirect(
-        request_.get(),
-        request_->context()->network_delegate(),
-        GURL("http://blah/redirect"));
+    scoped_ptr<AppCacheURLRequestJob> fallback_job(
+        handler_->MaybeLoadFallbackForRedirect(
+            request_.get(), request_->context()->network_delegate(),
+            GURL("http://blah/redirect")));
     EXPECT_FALSE(fallback_job);
 
     SimulateResponseCode(200);
-    fallback_job = handler_->MaybeLoadFallbackForResponse(
-        request_.get(), request_->context()->network_delegate());
+    fallback_job.reset(handler_->MaybeLoadFallbackForResponse(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_FALSE(fallback_job);
 
     TestFinished();
@@ -705,18 +690,17 @@
                                                RESOURCE_TYPE_SUB_RESOURCE,
                                                false));
     EXPECT_TRUE(handler_.get());
-    job_ = handler_->MaybeLoadResource(request_.get(),
-                                       request_->context()->network_delegate());
+    job_.reset(handler_->MaybeLoadResource(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_FALSE(job_.get());
 
-    AppCacheURLRequestJob* fallback_job;
-    fallback_job = handler_->MaybeLoadFallbackForRedirect(
-        request_.get(),
-        request_->context()->network_delegate(),
-        GURL("http://blah/redirect"));
+    scoped_ptr<AppCacheURLRequestJob> fallback_job(
+        handler_->MaybeLoadFallbackForRedirect(
+            request_.get(), request_->context()->network_delegate(),
+            GURL("http://blah/redirect")));
     EXPECT_FALSE(fallback_job);
-    fallback_job = handler_->MaybeLoadFallbackForResponse(
-        request_.get(), request_->context()->network_delegate());
+    fallback_job.reset(handler_->MaybeLoadFallbackForResponse(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_FALSE(fallback_job);
 
     TestFinished();
@@ -765,8 +749,8 @@
                                                false));
     EXPECT_TRUE(handler_.get());
 
-    job_ = handler_->MaybeLoadResource(request_.get(),
-                                       request_->context()->network_delegate());
+    job_.reset(handler_->MaybeLoadResource(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_TRUE(job_.get());
     EXPECT_TRUE(job_->is_waiting());
 
@@ -821,18 +805,21 @@
                                                false));
     EXPECT_TRUE(handler_.get());
 
-    job_ = handler_->MaybeLoadResource(request_.get(),
-                                       request_->context()->network_delegate());
+    job_.reset(handler_->MaybeLoadResource(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_TRUE(job_.get());
     EXPECT_TRUE(job_->is_waiting());
     EXPECT_FALSE(job_->has_been_started());
 
-    job_factory_->SetJob(job_.get());
+    base::WeakPtr<AppCacheURLRequestJob> weak_job = job_->GetWeakPtr();
+
+    job_factory_->SetJob(job_.Pass());
     request_->Start();
-    EXPECT_TRUE(job_->has_been_started());
+    ASSERT_TRUE(weak_job);
+    EXPECT_TRUE(weak_job->has_been_started());
 
     request_->Cancel();
-    EXPECT_TRUE(job_->has_been_killed());
+    ASSERT_FALSE(weak_job);
 
     EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
         request_.get(), request_->context()->network_delegate()));
@@ -903,8 +890,8 @@
         GURL(), AppCacheEntry(),
         1, 2, GURL("http://blah/manifest/"));
 
-    job_ = handler_->MaybeLoadResource(request_.get(),
-                                       request_->context()->network_delegate());
+    job_.reset(handler_->MaybeLoadResource(
+        request_.get(), request_->context()->network_delegate()));
     EXPECT_TRUE(job_.get());
     EXPECT_TRUE(job_->is_waiting());
 
@@ -957,7 +944,7 @@
   MockURLRequestDelegate delegate_;
   scoped_ptr<net::URLRequest> request_;
   scoped_ptr<AppCacheRequestHandler> handler_;
-  scoped_refptr<AppCacheURLRequestJob> job_;
+  scoped_ptr<AppCacheURLRequestJob> job_;
 
   static scoped_ptr<base::Thread> io_thread_;
 };
diff --git a/content/browser/appcache/appcache_storage.cc b/content/browser/appcache/appcache_storage.cc
index 0770006..7b94bf4 100644
--- a/content/browser/appcache/appcache_storage.cc
+++ b/content/browser/appcache/appcache_storage.cc
@@ -15,7 +15,7 @@
 namespace content {
 
 // static
-const int64 AppCacheStorage::kUnitializedId = -1;
+const int64_t AppCacheStorage::kUnitializedId = -1;
 
 AppCacheStorage::AppCacheStorage(AppCacheServiceImpl* service)
     : last_cache_id_(kUnitializedId), last_group_id_(kUnitializedId),
@@ -41,8 +41,8 @@
 
 AppCacheStorage::ResponseInfoLoadTask::ResponseInfoLoadTask(
     const GURL& manifest_url,
-    int64 group_id,
-    int64 response_id,
+    int64_t group_id,
+    int64_t response_id,
     AppCacheStorage* storage)
     : storage_(storage),
       manifest_url_(manifest_url),
@@ -79,8 +79,10 @@
   delete this;
 }
 
-void AppCacheStorage::LoadResponseInfo(
-    const GURL& manifest_url, int64 group_id, int64 id, Delegate* delegate) {
+void AppCacheStorage::LoadResponseInfo(const GURL& manifest_url,
+                                       int64_t group_id,
+                                       int64_t id,
+                                       Delegate* delegate) {
   AppCacheResponseInfo* info = working_set_.GetResponseInfo(id);
   if (info) {
     delegate->OnResponseInfoLoaded(info, id);
@@ -95,10 +97,10 @@
   info_load->StartIfNeeded();
 }
 
-void AppCacheStorage::UpdateUsageMapAndNotify(
-    const GURL& origin, int64 new_usage) {
+void AppCacheStorage::UpdateUsageMapAndNotify(const GURL& origin,
+                                              int64_t new_usage) {
   DCHECK_GE(new_usage, 0);
-  int64 old_usage = usage_map_[origin];
+  int64_t old_usage = usage_map_[origin];
   if (new_usage > 0)
     usage_map_[origin] = new_usage;
   else
diff --git a/content/browser/appcache/appcache_storage.h b/content/browser/appcache/appcache_storage.h
index 41668cb..d10a8931 100644
--- a/content/browser/appcache/appcache_storage.h
+++ b/content/browser/appcache/appcache_storage.h
@@ -8,9 +8,9 @@
 #include <map>
 #include <vector>
 
-#include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
+#include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "content/browser/appcache/appcache_working_set.h"
@@ -37,7 +37,7 @@
 
 class CONTENT_EXPORT AppCacheStorage {
  public:
-  typedef std::map<GURL, int64> UsageMap;
+  typedef std::map<GURL, int64_t> UsageMap;
 
   class CONTENT_EXPORT Delegate {
    public:
@@ -45,7 +45,7 @@
     virtual void OnAllInfo(AppCacheInfoCollection* collection) {}
 
     // If a load fails the 'cache' will be NULL.
-    virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) {}
+    virtual void OnCacheLoaded(AppCache* cache, int64_t cache_id) {}
 
     // If a load fails the 'group' will be NULL.
     virtual void OnGroupLoaded(
@@ -62,8 +62,8 @@
                                      int response_code) {}
 
     // If a load fails the 'response_info' will be NULL.
-    virtual void OnResponseInfoLoaded(
-        AppCacheResponseInfo* response_info, int64 response_id) {}
+    virtual void OnResponseInfoLoaded(AppCacheResponseInfo* response_info,
+                                      int64_t response_id) {}
 
     // If no response is found, entry.response_id() and
     // fallback_entry.response_id() will be kAppCacheNoResponseId.
@@ -71,10 +71,13 @@
     // namespace, the url of the namespece entry is returned.
     // If a response is found, the cache id and manifest url of the
     // containing cache and group are also returned.
-    virtual void OnMainResponseFound(
-        const GURL& url, const AppCacheEntry& entry,
-        const GURL& namespace_entry_url, const AppCacheEntry& fallback_entry,
-        int64 cache_id, int64 group_id, const GURL& mainfest_url) {}
+    virtual void OnMainResponseFound(const GURL& url,
+                                     const AppCacheEntry& entry,
+                                     const GURL& namespace_entry_url,
+                                     const AppCacheEntry& fallback_entry,
+                                     int64_t cache_id,
+                                     int64_t group_id,
+                                     const GURL& mainfest_url) {}
 
    protected:
     virtual ~Delegate() {}
@@ -93,7 +96,7 @@
   // memory, the delegate will be called back immediately without returning
   // to the message loop. If the load fails, the delegate will be called
   // back with a NULL cache pointer.
-  virtual void LoadCache(int64 id, Delegate* delegate) = 0;
+  virtual void LoadCache(int64_t id, Delegate* delegate) = 0;
 
   // Schedules a group and its newest cache, if any, to be loaded from storage.
   // Upon load completion the delegate will be called back. If the group
@@ -108,9 +111,10 @@
   // already resides in memory, the delegate will be called back
   // immediately without returning to the message loop. If the load fails,
   // the delegate will be called back with a NULL pointer.
-  virtual void LoadResponseInfo(
-      const GURL& manifest_url, int64 group_id, int64 response_id,
-      Delegate* delegate);
+  virtual void LoadResponseInfo(const GURL& manifest_url,
+                                int64_t group_id,
+                                int64_t response_id,
+                                Delegate* delegate);
 
   // Schedules a group and its newest complete cache to be initially stored or
   // incrementally updated with new changes. Upon completion the delegate
@@ -142,7 +146,7 @@
   // and schedules a task to update persistent storage. If the cache is
   // already scheduled to be loaded, upon loading completion the entry
   // will be marked. There is no delegate completion callback.
-  virtual void MarkEntryAsForeign(const GURL& entry_url, int64 cache_id) = 0;
+  virtual void MarkEntryAsForeign(const GURL& entry_url, int64_t cache_id) = 0;
 
   // Schedules a task to update persistent storage and doom the group and all
   // related caches and responses for deletion. Upon completion the in-memory
@@ -166,37 +170,34 @@
   }
 
   // Creates a reader to read a response from storage.
-  virtual AppCacheResponseReader* CreateResponseReader(
-      const GURL& manifest_url, int64 group_id, int64 response_id) = 0;
+  virtual AppCacheResponseReader* CreateResponseReader(const GURL& manifest_url,
+                                                       int64_t group_id,
+                                                       int64_t response_id) = 0;
 
   // Creates a writer to write a new response to storage. This call
   // establishes a new response id.
-  virtual AppCacheResponseWriter* CreateResponseWriter(
-      const GURL& manifest_url, int64 group_id) = 0;
+  virtual AppCacheResponseWriter* CreateResponseWriter(const GURL& manifest_url,
+                                                       int64_t group_id) = 0;
 
   // Creates a metadata writer to write metadata of response to storage.
   virtual AppCacheResponseMetadataWriter* CreateResponseMetadataWriter(
-      int64 group_id,
-      int64 response_id) = 0;
+      int64_t group_id,
+      int64_t response_id) = 0;
 
   // Schedules the lazy deletion of responses and saves the ids
   // persistently such that the responses will be deleted upon restart
   // if they aren't deleted prior to shutdown.
-  virtual void DoomResponses(
-      const GURL& manifest_url, const std::vector<int64>& response_ids) = 0;
+  virtual void DoomResponses(const GURL& manifest_url,
+                             const std::vector<int64_t>& response_ids) = 0;
 
   // Schedules the lazy deletion of responses without persistently saving
   // the response ids.
-  virtual void DeleteResponses(
-      const GURL& manifest_url, const std::vector<int64>& response_ids) = 0;
+  virtual void DeleteResponses(const GURL& manifest_url,
+                               const std::vector<int64_t>& response_ids) = 0;
 
   // Generates unique storage ids for different object types.
-  int64 NewCacheId() {
-    return ++last_cache_id_;
-  }
-  int64 NewGroupId() {
-    return ++last_group_id_;
-  }
+  int64_t NewCacheId() { return ++last_cache_id_; }
+  int64_t NewGroupId() { return ++last_group_id_; }
 
   // The working set of object instances currently in memory.
   AppCacheWorkingSet* working_set() { return &working_set_; }
@@ -250,13 +251,15 @@
   // multiple callers.
   class ResponseInfoLoadTask {
    public:
-    ResponseInfoLoadTask(const GURL& manifest_url, int64 group_id,
-                         int64 response_id, AppCacheStorage* storage);
+    ResponseInfoLoadTask(const GURL& manifest_url,
+                         int64_t group_id,
+                         int64_t response_id,
+                         AppCacheStorage* storage);
     ~ResponseInfoLoadTask();
 
-    int64 response_id() const { return response_id_; }
+    int64_t response_id() const { return response_id_; }
     const GURL& manifest_url() const { return manifest_url_; }
-    int64 group_id() const { return group_id_; }
+    int64_t group_id() const { return group_id_; }
 
     void AddDelegate(DelegateReference* delegate_reference) {
       delegates_.push_back(delegate_reference);
@@ -269,14 +272,14 @@
 
     AppCacheStorage* storage_;
     GURL manifest_url_;
-    int64 group_id_;
-    int64 response_id_;
+    int64_t group_id_;
+    int64_t response_id_;
     scoped_ptr<AppCacheResponseReader> reader_;
     DelegateReferenceVector delegates_;
     scoped_refptr<HttpResponseInfoIOBuffer> info_buffer_;
   };
 
-  typedef std::map<int64, ResponseInfoLoadTask*> PendingResponseInfoLoads;
+  typedef std::map<int64_t, ResponseInfoLoadTask*> PendingResponseInfoLoads;
 
   DelegateReference* GetDelegateReference(Delegate* delegate) {
     DelegateReferenceMap::iterator iter =
@@ -294,7 +297,9 @@
   }
 
   ResponseInfoLoadTask* GetOrCreateResponseInfoLoadTask(
-      const GURL& manifest_url, int64 group_id, int64 response_id) {
+      const GURL& manifest_url,
+      int64_t group_id,
+      int64_t response_id) {
     PendingResponseInfoLoads::iterator iter =
         pending_info_loads_.find(response_id);
     if (iter != pending_info_loads_.end())
@@ -303,19 +308,17 @@
   }
 
   // Should only be called when creating a new response writer.
-  int64 NewResponseId() {
-    return ++last_response_id_;
-  }
+  int64_t NewResponseId() { return ++last_response_id_; }
 
   // Helpers to query and notify the QuotaManager.
-  void UpdateUsageMapAndNotify(const GURL& origin, int64 new_usage);
+  void UpdateUsageMapAndNotify(const GURL& origin, int64_t new_usage);
   void ClearUsageMapAndNotify();
   void NotifyStorageAccessed(const GURL& origin);
 
   // The last storage id used for different object types.
-  int64 last_cache_id_;
-  int64 last_group_id_;
-  int64 last_response_id_;
+  int64_t last_cache_id_;
+  int64_t last_group_id_;
+  int64_t last_response_id_;
 
   UsageMap usage_map_;  // maps origin to usage
   AppCacheWorkingSet working_set_;
@@ -324,7 +327,7 @@
   PendingResponseInfoLoads pending_info_loads_;
 
   // The set of last ids must be retrieved from storage prior to being used.
-  static const int64 kUnitializedId;
+  static const int64_t kUnitializedId;
 
   FRIEND_TEST_ALL_PREFIXES(content::AppCacheStorageTest, DelegateReferences);
   FRIEND_TEST_ALL_PREFIXES(content::AppCacheStorageTest, UsageMap);
diff --git a/content/browser/appcache/appcache_storage_impl.cc b/content/browser/appcache/appcache_storage_impl.cc
index 067d19ac..8c9ded3 100644
--- a/content/browser/appcache/appcache_storage_impl.cc
+++ b/content/browser/appcache/appcache_storage_impl.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 #include <functional>
+#include <limits>
 #include <set>
 #include <vector>
 
@@ -50,9 +51,10 @@
 namespace {
 
 // Helpers for clearing data from the AppCacheDatabase.
-bool DeleteGroupAndRelatedRecords(AppCacheDatabase* database,
-                                  int64 group_id,
-                                  std::vector<int64>* deletable_response_ids) {
+bool DeleteGroupAndRelatedRecords(
+    AppCacheDatabase* database,
+    int64_t group_id,
+    std::vector<int64_t>* deletable_response_ids) {
   AppCacheDatabase::CacheRecord cache_record;
   bool success = false;
   if (database->FindCacheForGroup(group_id, &cache_record)) {
@@ -120,7 +122,7 @@
         NOTREACHED() << "Failed to start transaction";
         return;
       }
-      std::vector<int64> deletable_response_ids;
+      std::vector<int64_t> deletable_response_ids;
       bool success = DeleteGroupAndRelatedRecords(database,
                                                   group->group_id,
                                                   &deletable_response_ids);
@@ -281,11 +283,11 @@
  private:
   base::FilePath db_file_path_;
   base::FilePath disk_cache_directory_;
-  int64 last_group_id_;
-  int64 last_cache_id_;
-  int64 last_response_id_;
-  int64 last_deletable_response_rowid_;
-  std::map<GURL, int64> usage_map_;
+  int64_t last_group_id_;
+  int64_t last_cache_id_;
+  int64_t last_response_id_;
+  int64_t last_deletable_response_rowid_;
+  std::map<GURL, int64_t> usage_map_;
 };
 
 void AppCacheStorageImpl::InitTask::Run() {
@@ -403,7 +405,7 @@
       : DatabaseTask(storage) {}
   ~StoreOrLoadTask() override {}
 
-  bool FindRelatedCacheRecords(int64 cache_id);
+  bool FindRelatedCacheRecords(int64_t cache_id);
   void CreateCacheAndGroupFromRecords(
       scoped_refptr<AppCache>* cache, scoped_refptr<AppCacheGroup>* group);
 
@@ -419,7 +421,7 @@
 };
 
 bool AppCacheStorageImpl::StoreOrLoadTask::FindRelatedCacheRecords(
-    int64 cache_id) {
+    int64_t cache_id) {
   return database_->FindEntriesForCache(cache_id, &entry_records_) &&
          database_->FindNamespacesForCache(
              cache_id, &intercept_namespace_records_,
@@ -505,9 +507,8 @@
 
 class AppCacheStorageImpl::CacheLoadTask : public StoreOrLoadTask {
  public:
-  CacheLoadTask(int64 cache_id, AppCacheStorageImpl* storage)
-      : StoreOrLoadTask(storage), cache_id_(cache_id),
-        success_(false) {}
+  CacheLoadTask(int64_t cache_id, AppCacheStorageImpl* storage)
+      : StoreOrLoadTask(storage), cache_id_(cache_id), success_(false) {}
 
   // DatabaseTask:
   void Run() override;
@@ -517,7 +518,7 @@
   ~CacheLoadTask() override {}
 
  private:
-  int64 cache_id_;
+  int64_t cache_id_;
   bool success_;
 };
 
@@ -608,8 +609,8 @@
 
   void GetQuotaThenSchedule();
   void OnQuotaCallback(storage::QuotaStatusCode status,
-                       int64 usage,
-                       int64 quota);
+                       int64_t usage,
+                       int64_t quota);
 
   // DatabaseTask:
   void Run() override;
@@ -624,9 +625,9 @@
   scoped_refptr<AppCache> cache_;
   bool success_;
   bool would_exceed_quota_;
-  int64 space_available_;
-  int64 new_origin_usage_;
-  std::vector<int64> newly_deletable_response_ids_;
+  int64_t space_available_;
+  int64_t new_origin_usage_;
+  std::vector<int64_t> newly_deletable_response_ids_;
 };
 
 AppCacheStorageImpl::StoreGroupAndCacheTask::StoreGroupAndCacheTask(
@@ -660,7 +661,7 @@
     if (storage_->service()->special_storage_policy() &&
         storage_->service()->special_storage_policy()->IsStorageUnlimited(
             group_record_.origin))
-      space_available_ = kint64max;
+      space_available_ = std::numeric_limits<int64_t>::max();
     Schedule();
     return;
   }
@@ -680,11 +681,11 @@
 
 void AppCacheStorageImpl::StoreGroupAndCacheTask::OnQuotaCallback(
     storage::QuotaStatusCode status,
-    int64 usage,
-    int64 quota) {
+    int64_t usage,
+    int64_t quota) {
   if (storage_) {
     if (status == storage::kQuotaStatusOk)
-      space_available_ = std::max(static_cast<int64>(0), quota - usage);
+      space_available_ = std::max(static_cast<int64_t>(0), quota - usage);
     else
       space_available_ = 0;
     storage_->pending_quota_queries_.erase(this);
@@ -702,7 +703,7 @@
   if (!transaction.Begin())
     return;
 
-  int64 old_origin_usage = database_->GetOriginUsage(group_record_.origin);
+  int64_t old_origin_usage = database_->GetOriginUsage(group_record_.origin);
 
   AppCacheDatabase::GroupRecord existing_group;
   success_ = database_->FindGroup(group_record_.group_id, &existing_group);
@@ -726,7 +727,7 @@
     AppCacheDatabase::CacheRecord cache;
     if (database_->FindCacheForGroup(group_record_.group_id, &cache)) {
       // Get the set of response ids in the old cache.
-      std::set<int64> existing_response_ids;
+      std::set<int64_t> existing_response_ids;
       database_->FindResponseIdsForCacheAsSet(cache.cache_id,
                                               &existing_response_ids);
 
@@ -739,7 +740,7 @@
       }
 
       // The rest are deletable.
-      std::set<int64>::const_iterator id_iter = existing_response_ids.begin();
+      std::set<int64_t>::const_iterator id_iter = existing_response_ids.begin();
       while (id_iter != existing_response_ids.end()) {
         newly_deletable_response_ids_.push_back(*id_iter);
         ++id_iter;
@@ -789,7 +790,7 @@
 
   // Check limits based on the space availbable given to us via the
   // quota system.
-  int64 delta = new_origin_usage_ - old_origin_usage;
+  int64_t delta = new_origin_usage_ - old_origin_usage;
   if (delta > space_available_) {
     would_exceed_quota_ = true;
     success_ = false;
@@ -840,9 +841,9 @@
         AppCacheDatabase::EntryRecord,
         bool> {
  public:
-  SortByCachePreference(int64 preferred_id, const std::set<int64>& in_use_ids)
-      : preferred_id_(preferred_id), in_use_ids_(in_use_ids) {
-  }
+  SortByCachePreference(int64_t preferred_id,
+                        const std::set<int64_t>& in_use_ids)
+      : preferred_id_(preferred_id), in_use_ids_(in_use_ids) {}
   bool operator()(
       const AppCacheDatabase::EntryRecord& lhs,
       const AppCacheDatabase::EntryRecord& rhs) {
@@ -856,8 +857,8 @@
       return 50;
     return 0;
   }
-  int64 preferred_id_;
-  const std::set<int64>& in_use_ids_;
+  int64_t preferred_id_;
+  const std::set<int64_t>& in_use_ids_;
 };
 
 bool SortByLength(
@@ -873,7 +874,7 @@
       : database_(database) {
   }
 
-  bool IsInNetworkNamespace(const GURL& url, int64 cache_id) {
+  bool IsInNetworkNamespace(const GURL& url, int64_t cache_id) {
     typedef std::pair<WhiteListMap::iterator, bool> InsertResult;
     InsertResult result = namespaces_map_.insert(
         WhiteListMap::value_type(cache_id, AppCacheNamespaceVector()));
@@ -883,8 +884,8 @@
   }
 
  private:
-  void GetOnlineWhiteListForCache(
-      int64 cache_id, AppCacheNamespaceVector* namespaces) {
+  void GetOnlineWhiteListForCache(int64_t cache_id,
+                                  AppCacheNamespaceVector* namespaces) {
     DCHECK(namespaces && namespaces->empty());
     typedef std::vector<AppCacheDatabase::OnlineWhiteListRecord>
         WhiteListVector;
@@ -901,7 +902,7 @@
   }
 
   // Key is cache id
-  typedef std::map<int64, AppCacheNamespaceVector> WhiteListMap;
+  typedef std::map<int64_t, AppCacheNamespaceVector> WhiteListMap;
   WhiteListMap namespaces_map_;
   AppCacheDatabase* database_;
 };
@@ -941,22 +942,21 @@
   typedef std::vector<AppCacheDatabase::NamespaceRecord*>
       NamespaceRecordPtrVector;
 
-  bool FindExactMatch(int64 preferred_id);
-  bool FindNamespaceMatch(int64 preferred_id);
-  bool FindNamespaceHelper(
-      int64 preferred_cache_id,
-      AppCacheDatabase::NamespaceRecordVector* namespaces,
-      NetworkNamespaceHelper* network_namespace_helper);
+  bool FindExactMatch(int64_t preferred_id);
+  bool FindNamespaceMatch(int64_t preferred_id);
+  bool FindNamespaceHelper(int64_t preferred_cache_id,
+                           AppCacheDatabase::NamespaceRecordVector* namespaces,
+                           NetworkNamespaceHelper* network_namespace_helper);
   bool FindFirstValidNamespace(const NamespaceRecordPtrVector& namespaces);
 
   GURL url_;
   GURL preferred_manifest_url_;
-  std::set<int64> cache_ids_in_use_;
+  std::set<int64_t> cache_ids_in_use_;
   AppCacheEntry entry_;
   AppCacheEntry fallback_entry_;
   GURL namespace_entry_url_;
-  int64 cache_id_;
-  int64 group_id_;
+  int64_t cache_id_;
+  int64_t group_id_;
   GURL manifest_url_;
 };
 
@@ -976,7 +976,7 @@
   // TODO(michaeln): come up with a 'preferred_manifest_url' in more cases
   // - when navigating a frame whose current contents are from an appcache
   // - when clicking an href in a frame that is appcached
-  int64 preferred_cache_id = kAppCacheNoCacheId;
+  int64_t preferred_cache_id = kAppCacheNoCacheId;
   if (!preferred_manifest_url_.is_empty()) {
     AppCacheDatabase::GroupRecord preferred_group;
     AppCacheDatabase::CacheRecord preferred_cache;
@@ -1001,8 +1001,8 @@
          group_id_ == 0);
 }
 
-bool AppCacheStorageImpl::
-FindMainResponseTask::FindExactMatch(int64 preferred_cache_id) {
+bool AppCacheStorageImpl::FindMainResponseTask::FindExactMatch(
+    int64_t preferred_cache_id) {
   std::vector<AppCacheDatabase::EntryRecord> entries;
   if (database_->FindEntriesForUrl(url_, &entries) && !entries.empty()) {
     // Sort them in order of preference, from the preferred_cache first,
@@ -1028,8 +1028,8 @@
   return false;
 }
 
-bool AppCacheStorageImpl::
-FindMainResponseTask::FindNamespaceMatch(int64 preferred_cache_id) {
+bool AppCacheStorageImpl::FindMainResponseTask::FindNamespaceMatch(
+    int64_t preferred_cache_id) {
   AppCacheDatabase::NamespaceRecordVector all_intercepts;
   AppCacheDatabase::NamespaceRecordVector all_fallbacks;
   if (!database_->FindNamespacesForOrigin(
@@ -1050,9 +1050,8 @@
   return false;
 }
 
-bool AppCacheStorageImpl::
-FindMainResponseTask::FindNamespaceHelper(
-    int64 preferred_cache_id,
+bool AppCacheStorageImpl::FindMainResponseTask::FindNamespaceHelper(
+    int64_t preferred_cache_id,
     AppCacheDatabase::NamespaceRecordVector* namespaces,
     NetworkNamespaceHelper* network_namespace_helper) {
   // Sort them by length, longer matches within the same cache/bucket take
@@ -1130,8 +1129,9 @@
 
 class AppCacheStorageImpl::MarkEntryAsForeignTask : public DatabaseTask {
  public:
-  MarkEntryAsForeignTask(
-      AppCacheStorageImpl* storage, const GURL& url, int64 cache_id)
+  MarkEntryAsForeignTask(AppCacheStorageImpl* storage,
+                         const GURL& url,
+                         int64_t cache_id)
       : DatabaseTask(storage), cache_id_(cache_id), entry_url_(url) {}
 
   // DatabaseTask:
@@ -1142,7 +1142,7 @@
   ~MarkEntryAsForeignTask() override {}
 
  private:
-  int64 cache_id_;
+  int64_t cache_id_;
   GURL entry_url_;
 };
 
@@ -1174,12 +1174,12 @@
 
  private:
   scoped_refptr<AppCacheGroup> group_;
-  int64 group_id_;
+  int64_t group_id_;
   GURL origin_;
   bool success_;
   int response_code_;
-  int64 new_origin_usage_;
-  std::vector<int64> newly_deletable_response_ids_;
+  int64_t new_origin_usage_;
+  std::vector<int64_t> newly_deletable_response_ids_;
 };
 
 AppCacheStorageImpl::MakeGroupObsoleteTask::MakeGroupObsoleteTask(
@@ -1250,7 +1250,7 @@
 
 class AppCacheStorageImpl::GetDeletableResponseIdsTask : public DatabaseTask {
  public:
-  GetDeletableResponseIdsTask(AppCacheStorageImpl* storage, int64 max_rowid)
+  GetDeletableResponseIdsTask(AppCacheStorageImpl* storage, int64_t max_rowid)
       : DatabaseTask(storage), max_rowid_(max_rowid) {}
 
   // DatabaseTask:
@@ -1261,8 +1261,8 @@
   ~GetDeletableResponseIdsTask() override {}
 
  private:
-  int64 max_rowid_;
-  std::vector<int64> response_ids_;
+  int64_t max_rowid_;
+  std::vector<int64_t> response_ids_;
 };
 
 void AppCacheStorageImpl::GetDeletableResponseIdsTask::Run() {
@@ -1287,7 +1287,7 @@
   // DatabaseTask:
   void Run() override;
 
-  std::vector<int64> response_ids_;
+  std::vector<int64_t> response_ids_;
 
  protected:
   ~InsertDeletableResponseIdsTask() override {}
@@ -1309,7 +1309,7 @@
   // DatabaseTask:
   void Run() override;
 
-  std::vector<int64> response_ids_;
+  std::vector<int64_t> response_ids_;
 
  protected:
   ~DeleteDeletableResponseIdsTask() override {}
@@ -1339,7 +1339,7 @@
   ~LazyUpdateLastAccessTimeTask() override {}
 
  private:
-  int64 group_id_;
+  int64_t group_id_;
   base::Time last_access_time_;
 };
 
@@ -1393,7 +1393,7 @@
   ~UpdateEvictionTimesTask() override {}
 
  private:
-  int64 group_id_;
+  int64_t group_id_;
   base::Time last_full_update_check_time_;
   base::Time first_evictable_error_time_;
 };
@@ -1481,7 +1481,7 @@
   task->Schedule();
 }
 
-void AppCacheStorageImpl::LoadCache(int64 id, Delegate* delegate) {
+void AppCacheStorageImpl::LoadCache(int64_t id, Delegate* delegate) {
   DCHECK(delegate);
   if (is_disabled_) {
     delegate->OnCacheLoaded(NULL, id);
@@ -1667,9 +1667,13 @@
 
 void AppCacheStorageImpl::CallOnMainResponseFound(
     DelegateReferenceVector* delegates,
-    const GURL& url, const AppCacheEntry& entry,
-    const GURL& namespace_entry_url, const AppCacheEntry& fallback_entry,
-    int64 cache_id, int64 group_id, const GURL& manifest_url) {
+    const GURL& url,
+    const AppCacheEntry& entry,
+    const GURL& namespace_entry_url,
+    const AppCacheEntry& fallback_entry,
+    int64_t cache_id,
+    int64_t group_id,
+    const GURL& manifest_url) {
   FOR_EACH_DELEGATE(
       (*delegates),
       OnMainResponseFound(url, entry,
@@ -1701,8 +1705,8 @@
       found_network_namespace);
 }
 
-void AppCacheStorageImpl::MarkEntryAsForeign(
-    const GURL& entry_url, int64 cache_id) {
+void AppCacheStorageImpl::MarkEntryAsForeign(const GURL& entry_url,
+                                             int64_t cache_id) {
   AppCache* cache = working_set_.GetCache(cache_id);
   if (cache) {
     AppCacheEntry* entry = cache->GetEntry(entry_url);
@@ -1733,24 +1737,28 @@
 }
 
 AppCacheResponseReader* AppCacheStorageImpl::CreateResponseReader(
-    const GURL& manifest_url, int64 group_id, int64 response_id) {
+    const GURL& manifest_url,
+    int64_t group_id,
+    int64_t response_id) {
   return new AppCacheResponseReader(response_id, group_id, disk_cache());
 }
 
 AppCacheResponseWriter* AppCacheStorageImpl::CreateResponseWriter(
-    const GURL& manifest_url, int64 group_id) {
+    const GURL& manifest_url,
+    int64_t group_id) {
   return new AppCacheResponseWriter(NewResponseId(), group_id, disk_cache());
 }
 
 AppCacheResponseMetadataWriter*
-AppCacheStorageImpl::CreateResponseMetadataWriter(int64 group_id,
-                                                  int64 response_id) {
+AppCacheStorageImpl::CreateResponseMetadataWriter(int64_t group_id,
+                                                  int64_t response_id) {
   return new AppCacheResponseMetadataWriter(response_id, group_id,
                                             disk_cache());
 }
 
 void AppCacheStorageImpl::DoomResponses(
-    const GURL& manifest_url, const std::vector<int64>& response_ids) {
+    const GURL& manifest_url,
+    const std::vector<int64_t>& response_ids) {
   if (response_ids.empty())
     return;
 
@@ -1769,7 +1777,8 @@
 }
 
 void AppCacheStorageImpl::DeleteResponses(
-    const GURL& manifest_url, const std::vector<int64>& response_ids) {
+    const GURL& manifest_url,
+    const std::vector<int64_t>& response_ids) {
   if (response_ids.empty())
     return;
   StartDeletingResponses(response_ids);
@@ -1785,7 +1794,7 @@
 }
 
 void AppCacheStorageImpl::StartDeletingResponses(
-    const std::vector<int64>& response_ids) {
+    const std::vector<int64_t>& response_ids) {
   DCHECK(!response_ids.empty());
   did_start_deleting_responses_ = true;
   deletable_response_ids_.insert(
@@ -1818,7 +1827,7 @@
   }
 
   // TODO(michaeln): add group_id to DoomEntry args
-  int64 id = deletable_response_ids_.front();
+  int64_t id = deletable_response_ids_.front();
   int rv = disk_cache_->DoomEntry(
       id, base::Bind(&AppCacheStorageImpl::OnDeletedOneResponse,
                      base::Unretained(this)));
@@ -1831,7 +1840,7 @@
   if (is_disabled_)
     return;
 
-  int64 id = deletable_response_ids_.front();
+  int64_t id = deletable_response_ids_.front();
   deletable_response_ids_.pop_front();
   if (rv != net::ERR_ABORTED)
     deleted_response_ids_.push_back(id);
@@ -1856,7 +1865,7 @@
 }
 
 AppCacheStorageImpl::CacheLoadTask*
-AppCacheStorageImpl::GetPendingCacheLoadTask(int64 cache_id) {
+AppCacheStorageImpl::GetPendingCacheLoadTask(int64_t cache_id) {
   PendingCacheLoads::iterator found = pending_cache_loads_.find(cache_id);
   if (found != pending_cache_loads_.end())
     return found->second;
@@ -1872,7 +1881,8 @@
 }
 
 void AppCacheStorageImpl::GetPendingForeignMarkingsForCache(
-    int64 cache_id, std::vector<GURL>* urls) {
+    int64_t cache_id,
+    std::vector<GURL>* urls) {
   PendingForeignMarkings::iterator iter = pending_foreign_markings_.begin();
   while (iter != pending_foreign_markings_.end()) {
     if (iter->second == cache_id)
diff --git a/content/browser/appcache/appcache_storage_impl.h b/content/browser/appcache/appcache_storage_impl.h
index 2d1162ec..c1e65f6 100644
--- a/content/browser/appcache/appcache_storage_impl.h
+++ b/content/browser/appcache/appcache_storage_impl.h
@@ -43,7 +43,7 @@
 
   // AppCacheStorage methods, see the base class for doc comments.
   void GetAllInfo(Delegate* delegate) override;
-  void LoadCache(int64 id, Delegate* delegate) override;
+  void LoadCache(int64_t id, Delegate* delegate) override;
   void LoadOrCreateGroup(const GURL& manifest_url, Delegate* delegate) override;
   void StoreGroupAndNewestCache(AppCacheGroup* group,
                                 AppCache* newest_cache,
@@ -56,23 +56,23 @@
                                  AppCacheEntry* found_entry,
                                  AppCacheEntry* found_fallback_entry,
                                  bool* found_network_namespace) override;
-  void MarkEntryAsForeign(const GURL& entry_url, int64 cache_id) override;
+  void MarkEntryAsForeign(const GURL& entry_url, int64_t cache_id) override;
   void MakeGroupObsolete(AppCacheGroup* group,
                          Delegate* delegate,
                          int response_code) override;
   void StoreEvictionTimes(AppCacheGroup* group) override;
   AppCacheResponseReader* CreateResponseReader(const GURL& manifest_url,
-                                               int64 group_id,
-                                               int64 response_id) override;
+                                               int64_t group_id,
+                                               int64_t response_id) override;
   AppCacheResponseWriter* CreateResponseWriter(const GURL& manifest_url,
-                                               int64 group_id) override;
+                                               int64_t group_id) override;
   AppCacheResponseMetadataWriter* CreateResponseMetadataWriter(
-      int64 group_id,
-      int64 response_id) override;
+      int64_t group_id,
+      int64_t response_id) override;
   void DoomResponses(const GURL& manifest_url,
-                     const std::vector<int64>& response_ids) override;
+                     const std::vector<int64_t>& response_ids) override;
   void DeleteResponses(const GURL& manifest_url,
-                       const std::vector<int64>& response_ids) override;
+                       const std::vector<int64_t>& response_ids) override;
 
  private:
   // The AppCacheStorageImpl class methods and datamembers may only be
@@ -97,25 +97,25 @@
   class UpdateEvictionTimesTask;
 
   typedef std::deque<DatabaseTask*> DatabaseTaskQueue;
-  typedef std::map<int64, CacheLoadTask*> PendingCacheLoads;
+  typedef std::map<int64_t, CacheLoadTask*> PendingCacheLoads;
   typedef std::map<GURL, GroupLoadTask*> PendingGroupLoads;
-  typedef std::deque<std::pair<GURL, int64> > PendingForeignMarkings;
+  typedef std::deque<std::pair<GURL, int64_t>> PendingForeignMarkings;
   typedef std::set<StoreGroupAndCacheTask*> PendingQuotaQueries;
 
   bool IsInitTaskComplete() {
     return last_cache_id_ != AppCacheStorage::kUnitializedId;
   }
 
-  CacheLoadTask* GetPendingCacheLoadTask(int64 cache_id);
+  CacheLoadTask* GetPendingCacheLoadTask(int64_t cache_id);
   GroupLoadTask* GetPendingGroupLoadTask(const GURL& manifest_url);
-  void GetPendingForeignMarkingsForCache(
-      int64 cache_id, std::vector<GURL>* urls);
+  void GetPendingForeignMarkingsForCache(int64_t cache_id,
+                                         std::vector<GURL>* urls);
 
   void ScheduleSimpleTask(const base::Closure& task);
   void RunOnePendingSimpleTask();
 
   void DelayedStartDeletingUnusedResponses();
-  void StartDeletingResponses(const std::vector<int64>& response_ids);
+  void StartDeletingResponses(const std::vector<int64_t>& response_ids);
   void ScheduleDeleteOneResponse();
   void DeleteOneResponse();
   void OnDeletedOneResponse(int rv);
@@ -136,11 +136,14 @@
       scoped_refptr<AppCache> newest_cache,
       scoped_refptr<DelegateReference> delegate_ref);
 
-  void CallOnMainResponseFound(
-      DelegateReferenceVector* delegates,
-      const GURL& url, const AppCacheEntry& entry,
-      const GURL& namespace_entry_url, const AppCacheEntry& fallback_entry,
-      int64 cache_id, int64 group_id, const GURL& manifest_url);
+  void CallOnMainResponseFound(DelegateReferenceVector* delegates,
+                               const GURL& url,
+                               const AppCacheEntry& entry,
+                               const GURL& namespace_entry_url,
+                               const AppCacheEntry& fallback_entry,
+                               int64_t cache_id,
+                               int64_t group_id,
+                               const GURL& manifest_url);
 
   CONTENT_EXPORT AppCacheDiskCache* disk_cache();
 
@@ -162,11 +165,11 @@
   PendingQuotaQueries pending_quota_queries_;
 
   // Structures to keep track of lazy response deletion.
-  std::deque<int64> deletable_response_ids_;
-  std::vector<int64> deleted_response_ids_;
+  std::deque<int64_t> deletable_response_ids_;
+  std::vector<int64_t> deleted_response_ids_;
   bool is_response_deletion_scheduled_;
   bool did_start_deleting_responses_;
-  int64 last_deletable_response_rowid_;
+  int64_t last_deletable_response_rowid_;
 
   // Created on the IO thread, but only used on the DB thread.
   AppCacheDatabase* database_;
diff --git a/content/browser/appcache/appcache_storage_impl_unittest.cc b/content/browser/appcache/appcache_storage_impl_unittest.cc
index 59bc7d4..d673053 100644
--- a/content/browser/appcache/appcache_storage_impl_unittest.cc
+++ b/content/browser/appcache/appcache_storage_impl_unittest.cc
@@ -195,7 +195,7 @@
           found_cache_id_(kAppCacheNoCacheId), test_(test) {
     }
 
-    void OnCacheLoaded(AppCache* cache, int64 cache_id) override {
+    void OnCacheLoaded(AppCache* cache, int64_t cache_id) override {
       loaded_cache_ = cache;
       loaded_cache_id_ = cache_id;
       test_->ScheduleNextTask();
@@ -232,8 +232,8 @@
                              const AppCacheEntry& entry,
                              const GURL& namespace_entry_url,
                              const AppCacheEntry& fallback_entry,
-                             int64 cache_id,
-                             int64 group_id,
+                             int64_t cache_id,
+                             int64_t group_id,
                              const GURL& manifest_url) override {
       found_url_ = url;
       found_entry_ = entry;
@@ -246,7 +246,7 @@
     }
 
     scoped_refptr<AppCache> loaded_cache_;
-    int64 loaded_cache_id_;
+    int64_t loaded_cache_id_;
     scoped_refptr<AppCacheGroup> loaded_group_;
     GURL loaded_manifest_url_;
     scoped_refptr<AppCache> loaded_groups_newest_cache_;
@@ -259,8 +259,8 @@
     AppCacheEntry found_entry_;
     GURL found_namespace_entry_url_;
     AppCacheEntry found_fallback_entry_;
-    int64 found_cache_id_;
-    int64 found_group_id_;
+    int64_t found_cache_id_;
+    int64_t found_group_id_;
     GURL found_manifest_url_;
     AppCacheStorageImplTest* test_;
   };
@@ -321,7 +321,7 @@
     void NotifyStorageModified(storage::QuotaClient::ID client_id,
                                const GURL& origin,
                                storage::StorageType type,
-                               int64 delta) override {
+                               int64_t delta) override {
       EXPECT_EQ(storage::QuotaClient::kAppcache, client_id);
       EXPECT_EQ(storage::kStorageTypeTemporary, type);
       ++notify_storage_modified_count_;
@@ -493,7 +493,7 @@
 
     // Setup some preconditions. Make an 'unstored' cache for
     // us to load. The ctor should put it in the working set.
-    int64 cache_id = storage()->NewCacheId();
+    int64_t cache_id = storage()->NewCacheId();
     scoped_refptr<AppCache> cache(new AppCache(storage(), cache_id));
 
     // Conduct the test.
@@ -764,7 +764,7 @@
 
     // Setup some preconditions. Create a group and newest cache that
     // appear to be "unstored" and big enough to exceed the 5M limit.
-    const int64 kTooBig = 10 * 1024 * 1024;  // 10M
+    const int64_t kTooBig = 10 * 1024 * 1024;  // 10M
     group_ = new AppCacheGroup(
         storage(), kManifestUrl, storage()->NewGroupId());
     cache_ = new AppCache(storage(), storage()->NewCacheId());
@@ -1837,9 +1837,10 @@
     return delegate_.get();
   }
 
-  void MakeCacheAndGroup(
-      const GURL& manifest_url, int64 group_id, int64 cache_id,
-      bool add_to_database) {
+  void MakeCacheAndGroup(const GURL& manifest_url,
+                         int64_t group_id,
+                         int64_t cache_id,
+                         bool add_to_database) {
     AppCacheEntry default_entry(
         AppCacheEntry::EXPLICIT, cache_id + kDefaultEntryIdOffset,
         kDefaultEntrySize);
diff --git a/content/browser/appcache/appcache_url_request_job.cc b/content/browser/appcache/appcache_url_request_job.cc
index de924a1..7612da44 100644
--- a/content/browser/appcache/appcache_url_request_job.cc
+++ b/content/browser/appcache/appcache_url_request_job.cc
@@ -51,6 +51,11 @@
   DCHECK(storage_);
 }
 
+AppCacheURLRequestJob::~AppCacheURLRequestJob() {
+  if (storage_)
+    storage_->CancelDelegateCallbacks(this);
+}
+
 void AppCacheURLRequestJob::DeliverAppCachedResponse(
     const GURL& manifest_url, int64 group_id, int64 cache_id,
     const AppCacheEntry& entry, bool is_fallback) {
@@ -270,11 +275,6 @@
   BeginDelivery();
 }
 
-AppCacheURLRequestJob::~AppCacheURLRequestJob() {
-  if (storage_)
-    storage_->CancelDelegateCallbacks(this);
-}
-
 void AppCacheURLRequestJob::OnResponseInfoLoaded(
       AppCacheResponseInfo* response_info, int64 response_id) {
   DCHECK(is_delivering_appcache_response());
diff --git a/content/browser/appcache/appcache_url_request_job.h b/content/browser/appcache/appcache_url_request_job.h
index 8f51e7b..d3dfcf47 100644
--- a/content/browser/appcache/appcache_url_request_job.h
+++ b/content/browser/appcache/appcache_url_request_job.h
@@ -44,6 +44,8 @@
                         bool is_main_resource,
                         const OnPrepareToRestartCallback& restart_callback_);
 
+  ~AppCacheURLRequestJob() override;
+
   // Informs the job of what response it should deliver. Only one of these
   // methods should be called, and only once per job. A job will sit idle and
   // wait indefinitely until one of the deliver methods is called.
@@ -96,9 +98,6 @@
     return cache_entry_not_found_;
   }
 
- protected:
-  ~AppCacheURLRequestJob() override;
-
  private:
   friend class AppCacheRequestHandlerTest;
   friend class AppCacheURLRequestJobTest;
diff --git a/content/browser/appcache/appcache_url_request_job_unittest.cc b/content/browser/appcache/appcache_url_request_job_unittest.cc
index 231b7ea..4483f9c 100644
--- a/content/browser/appcache/appcache_url_request_job_unittest.cc
+++ b/content/browser/appcache/appcache_url_request_job_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/pickle.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
@@ -61,18 +62,13 @@
 
 class MockURLRequestJobFactory : public net::URLRequestJobFactory {
  public:
-  MockURLRequestJobFactory() : job_(NULL) {
-  }
+  MockURLRequestJobFactory() {}
 
   ~MockURLRequestJobFactory() override { DCHECK(!job_); }
 
-  void SetJob(net::URLRequestJob* job) {
-    job_ = job;
-  }
+  void SetJob(scoped_ptr<net::URLRequestJob> job) { job_ = std::move(job); }
 
-  bool has_job() const {
-    return job_ != NULL;
-  }
+  bool has_job() const { return job_.get() != nullptr; }
 
   // net::URLRequestJobFactory implementation.
   net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
@@ -80,9 +76,7 @@
       net::URLRequest* request,
       net::NetworkDelegate* network_delegate) const override {
     if (job_) {
-      net::URLRequestJob* temp = job_;
-      job_ = NULL;
-      return temp;
+      return job_.release();
     } else {
       return new net::URLRequestErrorJob(request,
                                          network_delegate,
@@ -116,9 +110,12 @@
   }
 
  private:
-  mutable net::URLRequestJob* job_;
+  // This is mutable because MaybeCreateJobWithProtocolHandler is const.
+  mutable scoped_ptr<net::URLRequestJob> job_;
 };
 
+}  // namespace
+
 class AppCacheURLRequestJobTest : public testing::Test {
  public:
 
@@ -449,15 +446,14 @@
   // Basic -------------------------------------------------------------------
   void Basic() {
     AppCacheStorage* storage = service_->storage();
-    scoped_ptr<net::URLRequest> request(empty_context_->CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, NULL));
-    scoped_refptr<AppCacheURLRequestJob> job;
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, nullptr);
 
     // Create an instance and see that it looks as expected.
 
-    job = new AppCacheURLRequestJob(
-      request.get(), NULL, storage, NULL, false,
-      base::Bind(&ExpectNotRestarted));
+    scoped_ptr<AppCacheURLRequestJob> job(
+        new AppCacheURLRequestJob(request_.get(), nullptr, storage, nullptr,
+                                  false, base::Bind(&ExpectNotRestarted)));
     EXPECT_TRUE(job->is_waiting());
     EXPECT_FALSE(job->is_delivering_appcache_response());
     EXPECT_FALSE(job->is_delivering_network_response());
@@ -475,29 +471,28 @@
   void DeliveryOrders() {
     AppCacheStorage* storage = service_->storage();
     scoped_ptr<net::URLRequest> request(empty_context_->CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, NULL));
-    scoped_refptr<AppCacheURLRequestJob> job;
+        GURL("http://blah/"), net::DEFAULT_PRIORITY, nullptr));
 
     // Create an instance, give it a delivery order and see that
     // it looks as expected.
 
-    job = new AppCacheURLRequestJob(
-        request.get(), NULL, storage, NULL, false,
-        base::Bind(&ExpectNotRestarted));
+    scoped_ptr<AppCacheURLRequestJob> job(
+        new AppCacheURLRequestJob(request.get(), nullptr, storage, nullptr,
+                                  false, base::Bind(&ExpectNotRestarted)));
     job->DeliverErrorResponse();
     EXPECT_TRUE(job->is_delivering_error_response());
     EXPECT_FALSE(job->has_been_started());
 
-    job = new AppCacheURLRequestJob(
-        request.get(), NULL, storage, NULL, false,
-        base::Bind(&ExpectNotRestarted));
+    job.reset(new AppCacheURLRequestJob(request.get(), nullptr, storage,
+                                        nullptr, false,
+                                        base::Bind(&ExpectNotRestarted)));
     job->DeliverNetworkResponse();
     EXPECT_TRUE(job->is_delivering_network_response());
     EXPECT_FALSE(job->has_been_started());
 
-    job = new AppCacheURLRequestJob(
-        request.get(), NULL, storage, NULL, false,
-        base::Bind(&ExpectNotRestarted));
+    job.reset(new AppCacheURLRequestJob(request.get(), nullptr, storage,
+                                        nullptr, false,
+                                        base::Bind(&ExpectNotRestarted)));
     const GURL kManifestUrl("http://blah/");
     const int64 kCacheId(1);
     const int64 kGroupId(1);
@@ -531,13 +526,13 @@
 
     // Set up to create an AppCacheURLRequestJob with orders to deliver
     // a network response.
-    AppCacheURLRequestJob* mock_job = new AppCacheURLRequestJob(
-        request_.get(), NULL, storage, NULL, false,
-        base::Bind(&SetIfCalled, &restart_callback_invoked_));
-    job_factory_->SetJob(mock_job);
+    scoped_ptr<AppCacheURLRequestJob> mock_job(new AppCacheURLRequestJob(
+        request_.get(), nullptr, storage, nullptr, false,
+        base::Bind(&SetIfCalled, &restart_callback_invoked_)));
     mock_job->DeliverNetworkResponse();
     EXPECT_TRUE(mock_job->is_delivering_network_response());
     EXPECT_FALSE(mock_job->has_been_started());
+    job_factory_->SetJob(std::move(mock_job));
 
     // Start the request.
     request_->Start();
@@ -569,13 +564,13 @@
 
     // Setup to create an AppCacheURLRequestJob with orders to deliver
     // a network response.
-    AppCacheURLRequestJob* mock_job = new AppCacheURLRequestJob(
-        request_.get(), NULL, storage, NULL, false,
-        base::Bind(&ExpectNotRestarted));
-    job_factory_->SetJob(mock_job);
+    scoped_ptr<AppCacheURLRequestJob> mock_job(
+        new AppCacheURLRequestJob(request_.get(), nullptr, storage, nullptr,
+                                  false, base::Bind(&ExpectNotRestarted)));
     mock_job->DeliverErrorResponse();
     EXPECT_TRUE(mock_job->is_delivering_error_response());
     EXPECT_FALSE(mock_job->has_been_started());
+    job_factory_->SetJob(std::move(mock_job));
 
     // Start the request.
     request_->Start();
@@ -621,9 +616,9 @@
 
     // Setup to create an AppCacheURLRequestJob with orders to deliver
     // a network response.
-    scoped_refptr<AppCacheURLRequestJob> job(new AppCacheURLRequestJob(
-        request_.get(), NULL, storage, NULL, false,
-        base::Bind(&ExpectNotRestarted)));
+    scoped_ptr<AppCacheURLRequestJob> job(
+        new AppCacheURLRequestJob(request_.get(), NULL, storage, NULL, false,
+                                  base::Bind(&ExpectNotRestarted)));
 
     if (start_after_delivery_orders) {
       job->DeliverAppCachedResponse(
@@ -635,17 +630,19 @@
 
     // Start the request.
     EXPECT_FALSE(job->has_been_started());
-    job_factory_->SetJob(job.get());
+    base::WeakPtr<AppCacheURLRequestJob> weak_job = job->GetWeakPtr();
+    job_factory_->SetJob(std::move(job));
     request_->Start();
     EXPECT_FALSE(job_factory_->has_job());
-    EXPECT_TRUE(job->has_been_started());
+    ASSERT_TRUE(weak_job);
+    EXPECT_TRUE(weak_job->has_been_started());
 
     if (!start_after_delivery_orders) {
-      job->DeliverAppCachedResponse(
+      weak_job->DeliverAppCachedResponse(
           GURL(), 0, 111,
-          AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_),
-          false);
-      EXPECT_TRUE(job->is_delivering_appcache_response());
+          AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_), false);
+      ASSERT_TRUE(weak_job);
+      EXPECT_TRUE(weak_job->is_delivering_appcache_response());
     }
 
     // Completion is async.
@@ -740,9 +737,9 @@
     request_->SetExtraRequestHeaders(extra_headers);
 
     // Create job with orders to deliver an appcached entry.
-    scoped_refptr<AppCacheURLRequestJob> job(new AppCacheURLRequestJob(
-        request_.get(), NULL, storage, NULL, false,
-        base::Bind(&ExpectNotRestarted)));
+    scoped_ptr<AppCacheURLRequestJob> job(
+        new AppCacheURLRequestJob(request_.get(), NULL, storage, NULL, false,
+                                  base::Bind(&ExpectNotRestarted)));
     job->DeliverAppCachedResponse(
         GURL(), 0, 111,
         AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_),
@@ -751,10 +748,9 @@
 
     // Start the request.
     EXPECT_FALSE(job->has_been_started());
-    job_factory_->SetJob(job.get());
+    job_factory_->SetJob(std::move(job));
     request_->Start();
     EXPECT_FALSE(job_factory_->has_job());
-    EXPECT_TRUE(job->has_been_started());
     // Completion is async.
   }
 
@@ -899,6 +895,4 @@
   RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequestWithIOPending);
 }
 
-}  // namespace
-
 }  // namespace content
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc
index 91922d98..98a780c 100644
--- a/content/browser/browser_child_process_host_impl.cc
+++ b/content/browser/browser_child_process_host_impl.cc
@@ -38,6 +38,12 @@
 #include "content/browser/mach_broker_mac.h"
 #endif
 
+
+#if defined(MOJO_SHELL_CLIENT)
+#include "content/browser/mojo/mojo_shell_client_host.h"
+#include "content/common/mojo/mojo_shell_connection_impl.h"
+#endif
+
 namespace content {
 namespace {
 
@@ -402,8 +408,15 @@
   DCHECK(process.IsValid());
 
   if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) {
-    mojo::embedder::ScopedPlatformHandle client_pipe =
-        mojo::embedder::ChildProcessLaunched(process.Handle());
+    mojo::embedder::ScopedPlatformHandle client_pipe;
+#if defined(MOJO_SHELL_CLIENT)
+    if (IsRunningInMojoShell()) {
+      client_pipe = RegisterProcessWithBroker(process.Pid());
+    } else
+#endif
+    {
+      client_pipe = mojo::embedder::ChildProcessLaunched(process.Handle());
+    }
     Send(new ChildProcessMsg_SetMojoParentPipeHandle(
         IPC::GetFileHandleForProcess(
 #if defined(OS_WIN)
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 05de1cb0..85f3e44 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -179,6 +179,7 @@
 #include "content/common/mojo/mojo_shell_connection_impl.h"
 #include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/converters/network/network_type_converters.h"
+#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
 #include "ui/views/mus/window_manager_connection.h"
 #endif
 
@@ -927,6 +928,7 @@
 int BrowserMainLoop::PreMainMessageLoopRun() {
 #if defined(MOJO_SHELL_CLIENT)
   if (IsRunningInMojoShell()) {
+    mojo::embedder::PreInitializeChildProcess();
     MojoShellConnectionImpl::Create();
     MojoShellConnectionImpl::Get()->BindToCommandLinePlatformChannel();
 #if defined(USE_AURA)
diff --git a/content/browser/browser_plugin/OWNERS b/content/browser/browser_plugin/OWNERS
index 0521a45..e3502a8 100644
--- a/content/browser/browser_plugin/OWNERS
+++ b/content/browser/browser_plugin/OWNERS
@@ -1,3 +1,4 @@
 fsamuel@chromium.org
 lazyboy@chromium.org
+lfg@chromium.org
 wjmaclean@chromium.org
diff --git a/content/browser/devtools/service_worker_devtools_manager.cc b/content/browser/devtools/service_worker_devtools_manager.cc
index 2eae6ab..c6cf7c7 100644
--- a/content/browser/devtools/service_worker_devtools_manager.cc
+++ b/content/browser/devtools/service_worker_devtools_manager.cc
@@ -107,7 +107,8 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   const WorkerId id(worker_process_id, worker_route_id);
   AgentHostMap::iterator it = workers_.find(id);
-  DCHECK(it != workers_.end());
+  if (it == workers_.end())
+    return;
   scoped_refptr<ServiceWorkerDevToolsAgentHost> host = it->second;
   host->WorkerReadyForInspection();
   FOR_EACH_OBSERVER(Observer, observer_list_,
@@ -132,7 +133,8 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   const WorkerId id(worker_process_id, worker_route_id);
   AgentHostMap::iterator it = workers_.find(id);
-  DCHECK(it != workers_.end());
+  if (it == workers_.end())
+    return;
   scoped_refptr<WorkerDevToolsAgentHost> agent_host(it->second);
   agent_host->WorkerDestroyed();
   FOR_EACH_OBSERVER(Observer, observer_list_, WorkerDestroyed(it->second));
diff --git a/content/browser/devtools/shared_worker_devtools_manager_unittest.cc b/content/browser/devtools/shared_worker_devtools_manager_unittest.cc
index b56c07b..554b83e3 100644
--- a/content/browser/devtools/shared_worker_devtools_manager_unittest.cc
+++ b/content/browser/devtools/shared_worker_devtools_manager_unittest.cc
@@ -97,12 +97,11 @@
 TEST_F(SharedWorkerDevToolsManagerTest, BasicTest) {
   scoped_refptr<DevToolsAgentHostImpl> agent_host;
 
-  SharedWorkerInstance instance1(GURL("http://example.com/w.js"),
-                                 base::string16(),
-                                 base::string16(),
-                                 blink::WebContentSecurityPolicyTypeReport,
-                                 browser_context_->GetResourceContext(),
-                                 partition_id_);
+  SharedWorkerInstance instance1(
+      GURL("http://example.com/w.js"), base::string16(), base::string16(),
+      blink::WebContentSecurityPolicyTypeReport,
+      browser_context_->GetResourceContext(), partition_id_,
+      blink::WebSharedWorkerCreationContextTypeNonsecure);
 
   agent_host = manager_->GetDevToolsAgentHostForWorker(1, 1);
   EXPECT_FALSE(agent_host.get());
@@ -180,18 +179,16 @@
   scoped_refptr<DevToolsAgentHostImpl> agent_host1;
   scoped_refptr<DevToolsAgentHostImpl> agent_host2;
 
-  SharedWorkerInstance instance1(GURL("http://example.com/w1.js"),
-                                 base::string16(),
-                                 base::string16(),
-                                 blink::WebContentSecurityPolicyTypeReport,
-                                 browser_context_->GetResourceContext(),
-                                 partition_id_);
-  SharedWorkerInstance instance2(GURL("http://example.com/w2.js"),
-                                 base::string16(),
-                                 base::string16(),
-                                 blink::WebContentSecurityPolicyTypeReport,
-                                 browser_context_->GetResourceContext(),
-                                 partition_id_);
+  SharedWorkerInstance instance1(
+      GURL("http://example.com/w1.js"), base::string16(), base::string16(),
+      blink::WebContentSecurityPolicyTypeReport,
+      browser_context_->GetResourceContext(), partition_id_,
+      blink::WebSharedWorkerCreationContextTypeNonsecure);
+  SharedWorkerInstance instance2(
+      GURL("http://example.com/w2.js"), base::string16(), base::string16(),
+      blink::WebContentSecurityPolicyTypeReport,
+      browser_context_->GetResourceContext(), partition_id_,
+      blink::WebSharedWorkerCreationContextTypeNonsecure);
 
   // Created -> GetDevToolsAgentHost -> Register -> Started -> Destroyed
   scoped_ptr<TestDevToolsClientHost> client_host1(new TestDevToolsClientHost());
@@ -265,12 +262,11 @@
 }
 
 TEST_F(SharedWorkerDevToolsManagerTest, ReattachTest) {
-  SharedWorkerInstance instance(GURL("http://example.com/w3.js"),
-                                base::string16(),
-                                base::string16(),
-                                blink::WebContentSecurityPolicyTypeReport,
-                                browser_context_->GetResourceContext(),
-                                partition_id_);
+  SharedWorkerInstance instance(
+      GURL("http://example.com/w3.js"), base::string16(), base::string16(),
+      blink::WebContentSecurityPolicyTypeReport,
+      browser_context_->GetResourceContext(), partition_id_,
+      blink::WebSharedWorkerCreationContextTypeNonsecure);
   scoped_ptr<TestDevToolsClientHost> client_host(new TestDevToolsClientHost());
   // Created -> GetDevToolsAgentHost -> Register -> Destroyed
   manager_->WorkerCreated(3, 1, instance);
diff --git a/content/browser/download/save_file.h b/content/browser/download/save_file.h
index e00be68..bfce4d9 100644
--- a/content/browser/download/save_file.h
+++ b/content/browser/download/save_file.h
@@ -39,7 +39,7 @@
   std::string DebugString() const;
 
   // Accessors.
-  int save_id() const { return info_->save_id; }
+  int save_item_id() const { return info_->save_item_id; }
   int render_process_id() const { return info_->render_process_id; }
   int request_id() const { return info_->request_id; }
   SaveFileCreateInfo::SaveFileSource save_source() const {
diff --git a/content/browser/download/save_file_manager.cc b/content/browser/download/save_file_manager.cc
index 3b6cd227..01874d0 100644
--- a/content/browser/download/save_file_manager.cc
+++ b/content/browser/download/save_file_manager.cc
@@ -25,9 +25,7 @@
 
 namespace content {
 
-SaveFileManager::SaveFileManager()
-    : next_id_(0) {
-}
+SaveFileManager::SaveFileManager() {}
 
 SaveFileManager::~SaveFileManager() {
   // Check for clean shutdown.
@@ -48,72 +46,23 @@
   STLDeleteValues(&save_file_map_);
 }
 
-SaveFile* SaveFileManager::LookupSaveFile(int save_id) {
-  SaveFileMap::iterator it = save_file_map_.find(save_id);
+SaveFile* SaveFileManager::LookupSaveFile(int save_item_id) {
+  SaveFileMap::iterator it = save_file_map_.find(save_item_id);
   return it == save_file_map_.end() ? NULL : it->second;
 }
 
-// Called on the IO thread when
-// a) The ResourceDispatcherHostImpl has decided that a request is savable.
-// b) The resource does not come from the network, but we still need a
-// save ID for for managing the status of the saving operation. So we
-// file a request from the file thread to the IO thread to generate a
-// unique save ID.
-int SaveFileManager::GetNextId() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  return next_id_++;
-}
-
-void SaveFileManager::RegisterStartingRequest(const GURL& save_url,
-                                              SavePackage* save_package) {
-  // Make sure it runs in the UI thread.
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  int save_package_id = save_package->id();
-
-  // Register this starting request.
-  StartingRequestsMap& starting_requests =
-      contents_starting_requests_[save_package_id];
-  bool never_present = starting_requests.insert(
-      StartingRequestsMap::value_type(save_url.spec(), save_package)).second;
-  DCHECK(never_present);
-}
-
-SavePackage* SaveFileManager::UnregisterStartingRequest(const GURL& save_url,
-                                                        int save_package_id) {
-  // Make sure it runs in UI thread.
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  ContentsToStartingRequestsMap::iterator it =
-      contents_starting_requests_.find(save_package_id);
-  if (it != contents_starting_requests_.end()) {
-    StartingRequestsMap& requests = it->second;
-    StartingRequestsMap::iterator sit = requests.find(save_url.spec());
-    if (sit == requests.end())
-      return NULL;
-
-    // Found, erase it from starting list and return SavePackage.
-    SavePackage* save_package = sit->second;
-    requests.erase(sit);
-    // If there is no element in requests, remove it
-    if (requests.empty())
-      contents_starting_requests_.erase(it);
-    return save_package;
-  }
-
-  return NULL;
-}
-
 // Look up a SavePackage according to a save id.
-SavePackage* SaveFileManager::LookupPackage(int save_id) {
+SavePackage* SaveFileManager::LookupPackage(int save_item_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  SavePackageMap::iterator it = packages_.find(save_id);
+  SavePackageMap::iterator it = packages_.find(save_item_id);
   if (it != packages_.end())
     return it->second;
   return NULL;
 }
 
 // Call from SavePackage for starting a saving job
-void SaveFileManager::SaveURL(const GURL& url,
+void SaveFileManager::SaveURL(int save_item_id,
+                              const GURL& url,
                               const Referrer& referrer,
                               int render_process_host_id,
                               int render_view_routing_id,
@@ -125,56 +74,40 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // Register a saving job.
-  RegisterStartingRequest(url, save_package);
   if (save_source == SaveFileCreateInfo::SAVE_FILE_FROM_NET) {
     DCHECK(url.is_valid());
 
     BrowserThread::PostTask(
         BrowserThread::IO, FROM_HERE,
         base::Bind(&SaveFileManager::OnSaveURL, this, url, referrer,
-                   save_package->id(), render_process_host_id,
+                   save_item_id, save_package->id(), render_process_host_id,
                    render_view_routing_id, render_frame_routing_id, context));
   } else {
     // We manually start the save job.
-    SaveFileCreateInfo* info = new SaveFileCreateInfo(file_full_path,
-         url,
-         save_source,
-         -1);
-    info->render_process_id = render_process_host_id;
-    info->render_frame_routing_id = render_frame_routing_id;
-    info->save_package_id = save_package->id();
+    SaveFileCreateInfo* info = new SaveFileCreateInfo(
+        file_full_path, url, save_item_id, save_package->id(),
+        render_process_host_id, render_frame_routing_id, save_source);
 
     // Since the data will come from render process, so we need to start
     // this kind of save job by ourself.
     BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::Bind(&SaveFileManager::OnRequireSaveJobFromOtherSource,
-            this, info));
+        BrowserThread::FILE, FROM_HERE,
+        base::Bind(&SaveFileManager::StartSave, this, info));
   }
 }
 
 // Utility function for look up table maintenance, called on the UI thread.
 // A manager may have multiple save page job (SavePackage) in progress,
 // so we just look up the save id and remove it from the tracking table.
-// If the save id is -1, it means we just send a request to save, but the
-// saving action has still not happened, need to call UnregisterStartingRequest
-// to remove it from the tracking map.
-void SaveFileManager::RemoveSaveFile(int save_id,
-                                     const GURL& save_url,
+void SaveFileManager::RemoveSaveFile(int save_item_id,
                                      SavePackage* save_package) {
   DCHECK(save_package);
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // A save page job (SavePackage) can only have one manager,
   // so remove it if it exists.
-  if (save_id == -1) {
-    SavePackage* old_package =
-        UnregisterStartingRequest(save_url, save_package->id());
-    DCHECK_EQ(old_package, save_package);
-  } else {
-    SavePackageMap::iterator it = packages_.find(save_id);
-    if (it != packages_.end())
-      packages_.erase(it);
-  }
+  SavePackageMap::iterator it = packages_.find(save_item_id);
+  if (it != packages_.end())
+    packages_.erase(it);
 }
 
 // Static
@@ -204,12 +137,12 @@
           this, full_path, is_dir));
 }
 
-void SaveFileManager::SendCancelRequest(int save_id) {
+void SaveFileManager::SendCancelRequest(int save_item_id) {
   // Cancel the request which has specific save id.
-  DCHECK_GT(save_id, -1);
+  DCHECK_GT(save_item_id, -1);
   BrowserThread::PostTask(
       BrowserThread::FILE, FROM_HERE,
-      base::Bind(&SaveFileManager::CancelSave, this, save_id));
+      base::Bind(&SaveFileManager::CancelSave, this, save_item_id));
 }
 
 // Notifications sent from the IO thread and run on the file thread:
@@ -226,8 +159,8 @@
   // TODO(phajdan.jr): We should check the return value and handle errors here.
   save_file->Initialize();
 
-  DCHECK(!LookupSaveFile(info->save_id));
-  save_file_map_[info->save_id] = save_file;
+  DCHECK(!LookupSaveFile(info->save_item_id));
+  save_file_map_[info->save_item_id] = save_file;
   info->path = save_file->FullPath();
 
   BrowserThread::PostTask(
@@ -239,11 +172,11 @@
 // update the UI. If the user has canceled the saving action (in the UI
 // thread). We may receive a few more updates before the IO thread gets the
 // cancel message. We just delete the data since the SaveFile has been deleted.
-void SaveFileManager::UpdateSaveProgress(int save_id,
+void SaveFileManager::UpdateSaveProgress(int save_item_id,
                                          net::IOBuffer* data,
                                          int data_len) {
   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-  SaveFile* save_file = LookupSaveFile(save_id);
+  SaveFile* save_file = LookupSaveFile(save_item_id);
   if (save_file) {
     DCHECK(save_file->InProgress());
 
@@ -251,54 +184,36 @@
         save_file->AppendDataToFile(data->data(), data_len);
     BrowserThread::PostTask(
         BrowserThread::UI, FROM_HERE,
-        base::Bind(&SaveFileManager::OnUpdateSaveProgress,
-                   this,
-                   save_file->save_id(),
-                   save_file->BytesSoFar(),
+        base::Bind(&SaveFileManager::OnUpdateSaveProgress, this,
+                   save_file->save_item_id(), save_file->BytesSoFar(),
                    reason == DOWNLOAD_INTERRUPT_REASON_NONE));
   }
 }
 
 // The IO thread will call this when saving is completed or it got error when
-// fetching data. In the former case, we forward the message to OnSaveFinished
-// in UI thread. In the latter case, the save ID will be -1, which means the
-// saving action did not even start, so we need to call OnErrorFinished in UI
-// thread, which will use the save URL to find corresponding request record and
-// delete it.
-void SaveFileManager::SaveFinished(int save_id,
-                                   const GURL& save_url,
+// fetching data. We forward the message to OnSaveFinished in UI thread.
+void SaveFileManager::SaveFinished(int save_item_id,
                                    int save_package_id,
                                    bool is_success) {
   DVLOG(20) << " " << __FUNCTION__ << "()"
-            << " save_id = " << save_id << " save_url = \"" << save_url.spec()
-            << "\""
+            << " save_item_id = " << save_item_id
             << " save_package_id = " << save_package_id
             << " is_success = " << is_success;
   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-  SaveFileMap::iterator it = save_file_map_.find(save_id);
+  SaveFileMap::iterator it = save_file_map_.find(save_item_id);
   if (it != save_file_map_.end()) {
     SaveFile* save_file = it->second;
-    // This routine may be called twice from the same SavePackage - once for the
-    // file itself, and once when all frames have been serialized.
-    // So we can't assert that the file is InProgress() here.
-    // TODO(rdsmith): Fix this logic and put the DCHECK below back in.
-    // DCHECK(save_file->InProgress());
+    DCHECK(save_file->InProgress());
 
     DVLOG(20) << " " << __FUNCTION__ << "()"
               << " save_file = " << save_file->DebugString();
     BrowserThread::PostTask(
         BrowserThread::UI, FROM_HERE,
-        base::Bind(&SaveFileManager::OnSaveFinished, this, save_id,
-            save_file->BytesSoFar(), is_success));
+        base::Bind(&SaveFileManager::OnSaveFinished, this, save_item_id,
+                   save_file->BytesSoFar(), is_success));
 
     save_file->Finish();
     save_file->Detach();
-  } else if (save_id == -1) {
-    // Before saving started, we got error. We still call finish process.
-    DCHECK(!save_url.is_empty());
-    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
-                            base::Bind(&SaveFileManager::OnErrorFinished, this,
-                                       save_url, save_package_id));
   }
 }
 
@@ -310,64 +225,44 @@
       info->render_process_id, info->render_frame_routing_id);
   if (!save_package) {
     // Cancel this request.
-    SendCancelRequest(info->save_id);
+    SendCancelRequest(info->save_item_id);
     return;
   }
 
   // Insert started saving job to tracking list.
-  SavePackageMap::iterator sit = packages_.find(info->save_id);
-  if (sit == packages_.end()) {
-    // Find the registered request. If we can not find, it means we have
-    // canceled the job before.
-    SavePackage* old_save_package =
-        UnregisterStartingRequest(info->url, info->save_package_id);
-    if (!old_save_package) {
-      // Cancel this request.
-      SendCancelRequest(info->save_id);
-      return;
-    }
-    DCHECK_EQ(old_save_package, save_package);
-    packages_[info->save_id] = save_package;
-  } else {
-    NOTREACHED();
-  }
+  SavePackageMap::iterator sit = packages_.find(info->save_item_id);
+  DCHECK(sit == packages_.end());
+  packages_[info->save_item_id] = save_package;
 
   // Forward this message to SavePackage.
   save_package->StartSave(info);
 }
 
-void SaveFileManager::OnUpdateSaveProgress(int save_id, int64 bytes_so_far,
+void SaveFileManager::OnUpdateSaveProgress(int save_item_id,
+                                           int64 bytes_so_far,
                                            bool write_success) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  SavePackage* package = LookupPackage(save_id);
+  SavePackage* package = LookupPackage(save_item_id);
   if (package)
-    package->UpdateSaveProgress(save_id, bytes_so_far, write_success);
+    package->UpdateSaveProgress(save_item_id, bytes_so_far, write_success);
   else
-    SendCancelRequest(save_id);
+    SendCancelRequest(save_item_id);
 }
 
-void SaveFileManager::OnSaveFinished(int save_id,
+void SaveFileManager::OnSaveFinished(int save_item_id,
                                      int64 bytes_so_far,
                                      bool is_success) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  SavePackage* package = LookupPackage(save_id);
+  SavePackage* package = LookupPackage(save_item_id);
   if (package)
-    package->SaveFinished(save_id, bytes_so_far, is_success);
-}
-
-void SaveFileManager::OnErrorFinished(const GURL& save_url,
-                                      int save_package_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  SavePackage* save_package =
-      UnregisterStartingRequest(save_url, save_package_id);
-  if (save_package)
-    save_package->SaveFailed(save_url);
+    package->SaveFinished(save_item_id, bytes_so_far, is_success);
 }
 
 // Notifications sent from the UI thread and run on the IO thread.
 
 void SaveFileManager::OnSaveURL(const GURL& url,
                                 const Referrer& referrer,
+                                int save_item_id,
                                 int save_package_id,
                                 int render_process_host_id,
                                 int render_view_routing_id,
@@ -375,22 +270,10 @@
                                 ResourceContext* context) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   ResourceDispatcherHostImpl::Get()->BeginSaveFile(
-      url, referrer, save_package_id, render_process_host_id,
+      url, referrer, save_item_id, save_package_id, render_process_host_id,
       render_view_routing_id, render_frame_routing_id, context);
 }
 
-void SaveFileManager::OnRequireSaveJobFromOtherSource(
-    SaveFileCreateInfo* info) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK_EQ(info->save_id, -1);
-  // Generate a unique save id.
-  info->save_id = GetNextId();
-  // Start real saving action.
-  BrowserThread::PostTask(
-      BrowserThread::FILE, FROM_HERE,
-      base::Bind(&SaveFileManager::StartSave, this, info));
-}
-
 void SaveFileManager::ExecuteCancelSaveRequest(int render_process_id,
                                                int request_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -405,9 +288,9 @@
 // but we do forward the cancel to the IO thread. Since this message has been
 // sent from the UI thread, the saving job may have already completed and
 // won't exist in our map.
-void SaveFileManager::CancelSave(int save_id) {
+void SaveFileManager::CancelSave(int save_item_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-  SaveFileMap::iterator it = save_file_map_.find(save_id);
+  SaveFileMap::iterator it = save_file_map_.find(save_item_id);
   if (it != save_file_map_.end()) {
     SaveFile* save_file = it->second;
 
@@ -435,14 +318,15 @@
   }
 }
 
-// It is possible that SaveItem which has specified save_id has been canceled
+// It is possible that SaveItem which has specified save_item_id has been
+// canceled
 // before this function runs. So if we can not find corresponding SaveFile by
-// using specified save_id, just return.
+// using specified save_item_id, just return.
 void SaveFileManager::SaveLocalFile(const GURL& original_file_url,
-                                    int save_id,
+                                    int save_item_id,
                                     int save_package_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-  SaveFile* save_file = LookupSaveFile(save_id);
+  SaveFile* save_file = LookupSaveFile(save_item_id);
   if (!save_file)
     return;
   // If it has finished, just return.
@@ -459,14 +343,14 @@
   // If we can not get valid file path from original URL, treat it as
   // disk error.
   if (file_path.empty())
-    SaveFinished(save_id, original_file_url, save_package_id, false);
+    SaveFinished(save_item_id, save_package_id, false);
 
   // Copy the local file to the temporary file. It will be renamed to its
   // final name later.
   bool success = base::CopyFile(file_path, save_file->FullPath());
   if (!success)
     base::DeleteFile(save_file->FullPath(), false);
-  SaveFinished(save_id, original_file_url, save_package_id, success);
+  SaveFinished(save_item_id, save_package_id, success);
 }
 
 void SaveFileManager::OnDeleteDirectoryOrFile(const base::FilePath& full_path,
@@ -477,7 +361,7 @@
   base::DeleteFile(full_path, is_dir);
 }
 
-void SaveFileManager::RenameAllFiles(const FinalNameList& final_names,
+void SaveFileManager::RenameAllFiles(const FinalNamesMap& final_names,
                                      const base::FilePath& resource_dir,
                                      int render_process_id,
                                      int render_frame_routing_id,
@@ -487,13 +371,15 @@
   if (!resource_dir.empty() && !base::PathExists(resource_dir))
     base::CreateDirectory(resource_dir);
 
-  for (FinalNameList::const_iterator i = final_names.begin();
-      i != final_names.end(); ++i) {
-    SaveFileMap::iterator it = save_file_map_.find(i->first);
+  for (const auto& i : final_names) {
+    int save_item_id = i.first;
+    const base::FilePath& final_name = i.second;
+
+    SaveFileMap::iterator it = save_file_map_.find(save_item_id);
     if (it != save_file_map_.end()) {
       SaveFile* save_file = it->second;
       DCHECK(!save_file->InProgress());
-      save_file->Rename(i->second);
+      save_file->Rename(final_name);
       delete save_file;
       save_file_map_.erase(it);
     }
@@ -518,12 +404,11 @@
 }
 
 void SaveFileManager::RemoveSavedFileFromFileMap(
-    const SaveIDList& save_ids) {
+    const std::vector<int>& save_item_ids) {
   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
 
-  for (SaveIDList::const_iterator i = save_ids.begin();
-      i != save_ids.end(); ++i) {
-    SaveFileMap::iterator it = save_file_map_.find(*i);
+  for (const int save_item_id : save_item_ids) {
+    SaveFileMap::iterator it = save_file_map_.find(save_item_id);
     if (it != save_file_map_.end()) {
       SaveFile* save_file = it->second;
       DCHECK(!save_file->InProgress());
diff --git a/content/browser/download/save_file_manager.h b/content/browser/download/save_file_manager.h
index d42bafa..9b0abe5 100644
--- a/content/browser/download/save_file_manager.h
+++ b/content/browser/download/save_file_manager.h
@@ -49,11 +49,10 @@
 //                                           data)
 //
 //
-// The SaveFileManager tracks saving requests, mapping from a save ID (unique
-// integer created in the IO thread) to the SavePackage for the contents where
-// the saving job was initiated. In the event of a contents closure during
-// saving, the SavePackage will notify the SaveFileManage to cancel all SaveFile
-// jobs.
+// The SaveFileManager tracks saving requests, mapping from a save item id to
+// the SavePackage for the contents where the saving job was initiated. In the
+// event of a contents closure during saving, the SavePackage will notify the
+// SaveFileManage to cancel all SaveFile jobs.
 
 #ifndef CONTENT_BROWSER_DOWNLOAD_SAVE_FILE_MANAGER_H_
 #define CONTENT_BROWSER_DOWNLOAD_SAVE_FILE_MANAGER_H_
@@ -89,14 +88,10 @@
   // Lifetime management.
   CONTENT_EXPORT void Shutdown();
 
-  // Called on the IO thread. This generates unique IDs for
-  // SaveFileResourceHandler objects (there's one per file in a SavePackage).
-  // Note that this is different from the SavePackage's id.
-  int GetNextId();
-
   // Save the specified URL. Called on the UI thread and forwarded to the
   // ResourceDispatcherHostImpl on the IO thread.
-  void SaveURL(const GURL& url,
+  void SaveURL(int save_item_id,
+               const GURL& url,
                const Referrer& referrer,
                int render_process_host_id,
                int render_view_routing_id,
@@ -108,20 +103,16 @@
 
   // Notifications sent from the IO thread and run on the file thread:
   void StartSave(SaveFileCreateInfo* info);
-  void UpdateSaveProgress(int save_id, net::IOBuffer* data, int size);
-  void SaveFinished(int save_id,
-                    const GURL& save_url,
-                    int save_package_id,
-                    bool is_success);
+  void UpdateSaveProgress(int save_item_id, net::IOBuffer* data, int size);
+  void SaveFinished(int save_item_id, int save_package_id, bool is_success);
 
   // Notifications sent from the UI thread and run on the file thread.
-  // Cancel a SaveFile instance which has specified save id.
-  void CancelSave(int save_id);
+  // Cancel a SaveFile instance which has specified save item id.
+  void CancelSave(int save_item_id);
 
   // Called on the UI thread to remove a save package from SaveFileManager's
   // tracking map.
-  void RemoveSaveFile(int save_id, const GURL& save_url,
-                      SavePackage* package);
+  void RemoveSaveFile(int save_item_id, SavePackage* package);
 
   // Helper function for deleting specified file.
   void DeleteDirectoryOrFile(const base::FilePath& full_path, bool is_dir);
@@ -129,13 +120,11 @@
   // Runs on file thread to save a file by copying from file system when
   // original url is using file scheme.
   void SaveLocalFile(const GURL& original_file_url,
-                     int save_id,
+                     int save_item_id,
                      int save_package_id);
 
   // Renames all the successfully saved files.
-  // |final_names| points to a vector which contains pairs of save ids and
-  // final names of successfully saved files.
-  void RenameAllFiles(const FinalNameList& final_names,
+  void RenameAllFiles(const FinalNamesMap& final_names,
                       const base::FilePath& resource_dir,
                       int render_process_id,
                       int render_frame_routing_id,
@@ -143,7 +132,7 @@
 
   // When the user cancels the saving, we need to remove all remaining saved
   // files of this page saving job from save_file_map_.
-  void RemoveSavedFileFromFileMap(const SaveIDList & save_ids);
+  void RemoveSavedFileFromFileMap(const std::vector<int>& save_item_ids);
 
  private:
   friend class base::RefCountedThreadSafe<SaveFileManager>;
@@ -158,24 +147,15 @@
   static SavePackage* GetSavePackageFromRenderIds(int render_process_id,
                                                   int render_frame_routing_id);
 
-  // Register a starting request. Associate the save URL with a
-  // SavePackage for further matching.
-  void RegisterStartingRequest(const GURL& save_url,
-                               SavePackage* save_package);
-  // Unregister a start request according save URL, disassociate
-  // the save URL and SavePackage.
-  SavePackage* UnregisterStartingRequest(const GURL& save_url,
-                                         int save_package_id);
-
-  // Look up the SavePackage according to save id.
-  SavePackage* LookupPackage(int save_id);
+  // Look up the SavePackage according to save item id.
+  SavePackage* LookupPackage(int save_item_id);
 
   // Called only on the file thread.
-  // Look up one in-progress saving item according to save id.
-  SaveFile* LookupSaveFile(int save_id);
+  // Look up one in-progress saving item according to save item id.
+  SaveFile* LookupSaveFile(int save_item_id);
 
   // Help function for sending notification of canceling specific request.
-  void SendCancelRequest(int save_id);
+  void SendCancelRequest(int save_item_id);
 
   // Notifications sent from the file thread and run on the UI thread.
 
@@ -184,15 +164,12 @@
   void OnStartSave(const SaveFileCreateInfo* info);
   // Update the SavePackage with the current state of a started saving job.
   // If the SavePackage for this saving job is gone, cancel the request.
-  void OnUpdateSaveProgress(int save_id,
+  void OnUpdateSaveProgress(int save_item_id,
                             int64 bytes_so_far,
                             bool write_success);
   // Update the SavePackage with the finish state, and remove the request
   // tracking entries.
-  void OnSaveFinished(int save_id, int64 bytes_so_far, bool is_success);
-  // For those requests that do not have valid save id, use
-  // map:(url, SavePackage) to find the request and remove it.
-  void OnErrorFinished(const GURL& save_url, int save_package_id);
+  void OnSaveFinished(int save_item_id, int64 bytes_so_far, bool is_success);
   // Notifies SavePackage that the whole page saving job is finished.
   void OnFinishSavePageJob(int render_process_id,
                            int render_frame_routing_id,
@@ -208,44 +185,25 @@
   // Initiates a request for URL to be saved.
   void OnSaveURL(const GURL& url,
                  const Referrer& referrer,
+                 int save_item_id,
+                 int save_package_id,
                  int render_process_host_id,
                  int render_view_routing_id,
                  int render_frame_routing_id,
-                 int save_package_id,
                  ResourceContext* context);
-  // Handler for a notification sent to the IO thread for generating save id.
-  void OnRequireSaveJobFromOtherSource(SaveFileCreateInfo* info);
   // Call ResourceDispatcherHostImpl's CancelRequest method to execute cancel
   // action in the IO thread.
   void ExecuteCancelSaveRequest(int render_process_id, int request_id);
 
-  // Unique ID for the next SaveFile object.
-  int next_id_;
-
-  // A map of all saving jobs by using save id.
+  // A map from save_item_id into SaveFiles.
   typedef base::hash_map<int, SaveFile*> SaveFileMap;
   SaveFileMap save_file_map_;
 
   // Tracks which SavePackage to send data to, called only on UI thread.
-  // SavePackageMap maps save IDs to their SavePackage.
+  // SavePackageMap maps save item ids to their SavePackage.
   typedef base::hash_map<int, SavePackage*> SavePackageMap;
   SavePackageMap packages_;
 
-  // There is a gap between after calling SaveURL() and before calling
-  // StartSave(). In this gap, each request does not have save id for tracking.
-  // But sometimes users might want to stop saving job or ResourceDispatcherHost
-  // calls SaveFinished with save id -1 for network error. We name the requests
-  // as starting requests. For tracking those starting requests, we need to
-  // have some data structure.
-  // First we use a hashmap to map the request URL to SavePackage, then we use a
-  // hashmap to map the contents id (we actually use render_process_id) to the
-  // hashmap since it is possible to save the same URL in different contents at
-  // same time.
-  typedef base::hash_map<std::string, SavePackage*> StartingRequestsMap;
-  typedef base::hash_map<int, StartingRequestsMap>
-      ContentsToStartingRequestsMap;
-  ContentsToStartingRequestsMap contents_starting_requests_;
-
   DISALLOW_COPY_AND_ASSIGN(SaveFileManager);
 };
 
diff --git a/content/browser/download/save_file_resource_handler.cc b/content/browser/download/save_file_resource_handler.cc
index 43555ad..e20c0361 100644
--- a/content/browser/download/save_file_resource_handler.cc
+++ b/content/browser/download/save_file_resource_handler.cc
@@ -17,13 +17,14 @@
 namespace content {
 
 SaveFileResourceHandler::SaveFileResourceHandler(net::URLRequest* request,
+                                                 int save_item_id,
                                                  int save_package_id,
                                                  int render_process_host_id,
                                                  int render_frame_routing_id,
                                                  const GURL& url,
                                                  SaveFileManager* manager)
     : ResourceHandler(request),
-      save_id_(-1),
+      save_item_id_(save_item_id),
       save_package_id_(save_package_id),
       render_process_id_(render_process_host_id),
       render_frame_routing_id_(render_frame_routing_id),
@@ -44,19 +45,11 @@
 
 bool SaveFileResourceHandler::OnResponseStarted(ResourceResponse* response,
                                                 bool* defer) {
-  save_id_ = save_manager_->GetNextId();
   // |save_manager_| consumes (deletes):
-  SaveFileCreateInfo* info = new SaveFileCreateInfo;
-  info->url = url_;
-  info->final_url = final_url_;
-  info->total_bytes = content_length_;
-  info->save_id = save_id_;
-  info->save_package_id = save_package_id_;
-  info->render_process_id = render_process_id_;
-  info->render_frame_routing_id = render_frame_routing_id_;
-  info->request_id = GetRequestID();
-  info->content_disposition = content_disposition_;
-  info->save_source = SaveFileCreateInfo::SAVE_FILE_FROM_NET;
+  SaveFileCreateInfo* info = new SaveFileCreateInfo(
+      url_, final_url_, save_item_id_, save_package_id_, render_process_id_,
+      render_frame_routing_id_, GetRequestID(), content_disposition_,
+      content_length_);
   BrowserThread::PostTask(
       BrowserThread::FILE, FROM_HERE,
       base::Bind(&SaveFileManager::StartSave, save_manager_, info));
@@ -91,8 +84,8 @@
   read_buffer_.swap(buffer);
   BrowserThread::PostTask(
       BrowserThread::FILE, FROM_HERE,
-      base::Bind(&SaveFileManager::UpdateSaveProgress,
-          save_manager_, save_id_, buffer, bytes_read));
+      base::Bind(&SaveFileManager::UpdateSaveProgress, save_manager_,
+                 save_item_id_, buffer, bytes_read));
   return true;
 }
 
@@ -102,7 +95,7 @@
     bool* defer) {
   BrowserThread::PostTask(
       BrowserThread::FILE, FROM_HERE,
-      base::Bind(&SaveFileManager::SaveFinished, save_manager_, save_id_, url_,
+      base::Bind(&SaveFileManager::SaveFinished, save_manager_, save_item_id_,
                  save_package_id_,
                  status.is_success() && !status.is_io_pending()));
   read_buffer_ = NULL;
diff --git a/content/browser/download/save_file_resource_handler.h b/content/browser/download/save_file_resource_handler.h
index a2bc2ee7..6912ac4 100644
--- a/content/browser/download/save_file_resource_handler.h
+++ b/content/browser/download/save_file_resource_handler.h
@@ -22,6 +22,7 @@
 class SaveFileResourceHandler : public ResourceHandler {
  public:
   SaveFileResourceHandler(net::URLRequest* request,
+                          int save_item_id,
                           int save_package_id,
                           int render_process_host_id,
                           int render_frame_routing_id,
@@ -72,7 +73,7 @@
   }
 
  private:
-  int save_id_;
+  int save_item_id_;
   int save_package_id_;
   int render_process_id_;
   int render_frame_routing_id_;
diff --git a/content/browser/download/save_item.cc b/content/browser/download/save_item.cc
index 9e51620..a8aeefd 100644
--- a/content/browser/download/save_item.cc
+++ b/content/browser/download/save_item.cc
@@ -9,24 +9,35 @@
 #include "content/browser/download/save_file.h"
 #include "content/browser/download/save_file_manager.h"
 #include "content/browser/download/save_package.h"
+#include "content/public/browser/browser_thread.h"
 
 namespace content {
 
+namespace {
+
+int GetNextSaveItemId() {
+  static int g_next_save_item_id = 0;
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  return g_next_save_item_id++;
+}
+
+}  // namespace
+
 // Constructor for SaveItem when creating each saving job.
 SaveItem::SaveItem(const GURL& url,
                    const Referrer& referrer,
                    SavePackage* package,
                    SaveFileCreateInfo::SaveFileSource save_source)
-  : save_id_(-1),
-    url_(url),
-    referrer_(referrer),
-    total_bytes_(0),
-    received_bytes_(0),
-    state_(WAIT_START),
-    has_final_name_(false),
-    is_success_(false),
-    save_source_(save_source),
-    package_(package) {
+    : save_item_id_(GetNextSaveItemId()),
+      url_(url),
+      referrer_(referrer),
+      total_bytes_(0),
+      received_bytes_(0),
+      state_(WAIT_START),
+      has_final_name_(false),
+      is_success_(false),
+      save_source_(save_source),
+      package_(package) {
   DCHECK(package);
 }
 
@@ -76,16 +87,7 @@
 
 // Set finish state for a save item
 void SaveItem::Finish(int64 size, bool is_success) {
-  // When this function is called, the SaveItem should be one of following
-  // three situations.
-  // a) The data of this SaveItem is finished saving. So it should have
-  // generated final name.
-  // b) Error happened before the start of saving process. So no |save_id_| is
-  // generated for this SaveItem and the |is_success_| should be false.
-  // c) Error happened in the start of saving process, the SaveItem has a save
-  // id, |is_success_| should be false, and the |size| should be 0.
-  DCHECK(has_final_name() || (save_id_ == -1 && !is_success_) ||
-         (save_id_ != -1 && !is_success_ && !size));
+  DCHECK(has_final_name() || !is_success_);
   state_ = COMPLETE;
   is_success_ = is_success;
   UpdateSize(size);
@@ -120,11 +122,6 @@
   has_final_name_ = true;
 }
 
-void SaveItem::SetSaveId(int32 save_id) {
-  DCHECK_EQ(-1, save_id_);
-  save_id_ = save_id;
-}
-
 void SaveItem::SetTotalBytes(int64 total_bytes) {
   DCHECK_EQ(0, total_bytes_);
   total_bytes_ = total_bytes;
diff --git a/content/browser/download/save_item.h b/content/browser/download/save_item.h
index d7cbb4f..468b1d238 100644
--- a/content/browser/download/save_item.h
+++ b/content/browser/download/save_item.h
@@ -50,11 +50,10 @@
   // Update path for SaveItem, the actual file is renamed on the file thread.
   void Rename(const base::FilePath& full_path);
 
-  void SetSaveId(int32 save_id);
-
   void SetTotalBytes(int64 total_bytes);
 
   // Accessors.
+  int id() const { return save_item_id_; }
   SaveState state() const { return state_; }
   const base::FilePath& full_path() const { return full_path_; }
   const base::FilePath& file_name() const { return file_name_; }
@@ -62,7 +61,6 @@
   const Referrer& referrer() const { return referrer_; }
   int64 total_bytes() const { return total_bytes_; }
   int64 received_bytes() const { return received_bytes_; }
-  int32 save_id() const { return save_id_; }
   bool has_final_name() const { return has_final_name_; }
   bool success() const { return is_success_; }
   SaveFileCreateInfo::SaveFileSource save_source() const {
@@ -74,8 +72,8 @@
   // Internal helper for maintaining consistent received and total sizes.
   void UpdateSize(int64 size);
 
-  // Request ID assigned by the ResourceDispatcherHost.
-  int32 save_id_;
+  // Unique identifier for this SaveItem instance.
+  const int save_item_id_;
 
   // Full path to the save item file.
   base::FilePath full_path_;
diff --git a/content/browser/download/save_package.cc b/content/browser/download/save_package.cc
index 15886f8..4682969 100644
--- a/content/browser/download/save_package.cc
+++ b/content/browser/download/save_package.cc
@@ -551,7 +551,7 @@
 void SavePackage::StartSave(const SaveFileCreateInfo* info) {
   DCHECK(info && !info->url.is_empty());
 
-  SaveUrlItemMap::iterator it = in_progress_items_.find(info->url.spec());
+  SaveItemIdMap::iterator it = in_progress_items_.find(info->save_item_id);
   if (it == in_progress_items_.end()) {
     // If not found, we must have cancel action.
     DCHECK(canceled());
@@ -561,7 +561,6 @@
 
   DCHECK(!saved_main_file_path_.empty());
 
-  save_item->SetSaveId(info->save_id);
   save_item->SetTotalBytes(info->total_bytes);
 
   // Determine the proper path for a saving job, by choosing either the default
@@ -588,7 +587,7 @@
       if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM)
         Cancel(true);
       else
-        SaveFinished(save_item->save_id(), 0, false);
+        SaveFinished(save_item->id(), 0, false);
       return;
     }
 
@@ -613,7 +612,7 @@
     BrowserThread::PostTask(
         BrowserThread::FILE, FROM_HERE,
         base::Bind(&SaveFileManager::SaveLocalFile, file_manager_,
-                   save_item->url(), save_item->save_id(), id()));
+                   save_item->url(), save_item->id(), id()));
     return;
   }
 
@@ -626,46 +625,42 @@
   }
 }
 
-SaveItem* SavePackage::LookupItemInProcessBySaveId(int32 save_id) {
-  if (in_process_count()) {
-    for (SaveUrlItemMap::iterator it = in_progress_items_.begin();
-        it != in_progress_items_.end(); ++it) {
-      SaveItem* save_item = it->second;
-      DCHECK_EQ(SaveItem::IN_PROGRESS, save_item->state());
-      if (save_item->save_id() == save_id)
-        return save_item;
-    }
+SaveItem* SavePackage::LookupSaveItemInProcess(int32 save_item_id) {
+  auto it = in_progress_items_.find(save_item_id);
+  if (it != in_progress_items_.end()) {
+    SaveItem* save_item = it->second;
+    DCHECK_EQ(SaveItem::IN_PROGRESS, save_item->state());
+    return save_item;
   }
-  return NULL;
+  return nullptr;
 }
 
 void SavePackage::PutInProgressItemToSavedMap(SaveItem* save_item) {
-  SaveUrlItemMap::iterator it = in_progress_items_.find(
-      save_item->url().spec());
+  SaveItemIdMap::iterator it = in_progress_items_.find(save_item->id());
   DCHECK(it != in_progress_items_.end());
   DCHECK(save_item == it->second);
   in_progress_items_.erase(it);
 
   if (save_item->success()) {
     // Add it to saved_success_items_.
-    DCHECK(saved_success_items_.find(save_item->save_id()) ==
+    DCHECK(saved_success_items_.find(save_item->id()) ==
            saved_success_items_.end());
-    saved_success_items_[save_item->save_id()] = save_item;
+    saved_success_items_[save_item->id()] = save_item;
   } else {
     // Add it to saved_failed_items_.
-    DCHECK(saved_failed_items_.find(save_item->url().spec()) ==
+    DCHECK(saved_failed_items_.find(save_item->id()) ==
            saved_failed_items_.end());
-    saved_failed_items_[save_item->url().spec()] = save_item;
+    saved_failed_items_[save_item->id()] = save_item;
   }
 }
 
 // Called for updating saving state.
-bool SavePackage::UpdateSaveProgress(int32 save_id,
+bool SavePackage::UpdateSaveProgress(int32 save_item_id,
                                      int64 size,
                                      bool write_success) {
   // Because we might have canceled this saving job before,
   // so we might not find corresponding SaveItem.
-  SaveItem* save_item = LookupItemInProcessBySaveId(save_id);
+  SaveItem* save_item = LookupSaveItemInProcess(save_item_id);
   if (!save_item)
     return false;
 
@@ -690,7 +685,7 @@
   // When stopping, if it still has some items in in_progress, cancel them.
   DCHECK(canceled());
   if (in_process_count()) {
-    SaveUrlItemMap::iterator it = in_progress_items_.begin();
+    SaveItemIdMap::iterator it = in_progress_items_.begin();
     for (; it != in_progress_items_.end(); ++it) {
       SaveItem* save_item = it->second;
       DCHECK_EQ(SaveItem::IN_PROGRESS, save_item->state());
@@ -705,19 +700,16 @@
 
   // This vector contains the save ids of the save files which SaveFileManager
   // needs to remove from its save_file_map_.
-  SaveIDList save_ids;
-  for (SavedItemMap::iterator it = saved_success_items_.begin();
-      it != saved_success_items_.end(); ++it)
-    save_ids.push_back(it->first);
-  for (SaveUrlItemMap::iterator it = saved_failed_items_.begin();
-      it != saved_failed_items_.end(); ++it)
-    save_ids.push_back(it->second->save_id());
+  std::vector<int> save_item_ids;
+  for (const auto& it : saved_success_items_)
+    save_item_ids.push_back(it.first);
+  for (const auto& it : saved_failed_items_)
+    save_item_ids.push_back(it.first);
 
   BrowserThread::PostTask(
       BrowserThread::FILE, FROM_HERE,
-      base::Bind(&SaveFileManager::RemoveSavedFileFromFileMap,
-                 file_manager_,
-                 save_ids));
+      base::Bind(&SaveFileManager::RemoveSavedFileFromFileMap, file_manager_,
+                 save_item_ids));
 
   finished_ = true;
   wait_state_ = FAILED;
@@ -737,14 +729,9 @@
                         saved_success_items_.size() > 1) ?
                         saved_main_directory_path_ : base::FilePath();
 
-  // This vector contains the final names of all the successfully saved files
-  // along with their save ids. It will be passed to SaveFileManager to do the
-  // renaming job.
-  FinalNameList final_names;
-  for (SavedItemMap::iterator it = saved_success_items_.begin();
-      it != saved_success_items_.end(); ++it)
-    final_names.push_back(std::make_pair(it->first,
-                                         it->second->full_path()));
+  FinalNamesMap final_names;
+  for (const auto& it : saved_success_items_)
+    final_names.insert(std::make_pair(it.first, it.second->full_path()));
 
   BrowserThread::PostTask(
       BrowserThread::FILE, FROM_HERE,
@@ -770,26 +757,25 @@
   RecordSavePackageEvent(SAVE_PACKAGE_FINISHED);
 
   // Record any errors that occurred.
-  if (wrote_to_completed_file_) {
+  if (wrote_to_completed_file_)
     RecordSavePackageEvent(SAVE_PACKAGE_WRITE_TO_COMPLETED);
-  }
 
-  if (wrote_to_failed_file_) {
+  if (wrote_to_failed_file_)
     RecordSavePackageEvent(SAVE_PACKAGE_WRITE_TO_FAILED);
-  }
 
   // This vector contains the save ids of the save files which SaveFileManager
   // needs to remove from its save_file_map_.
-  SaveIDList save_ids;
-  for (SaveUrlItemMap::iterator it = saved_failed_items_.begin();
-       it != saved_failed_items_.end(); ++it)
-    save_ids.push_back(it->second->save_id());
+  std::vector<int> list_of_failed_save_item_ids;
+  for (const auto& it : saved_failed_items_) {
+    SaveItem* save_item = it.second;
+    DCHECK_EQ(it.first, save_item->id());
+    list_of_failed_save_item_ids.push_back(save_item->id());
+  }
 
   BrowserThread::PostTask(
       BrowserThread::FILE, FROM_HERE,
-      base::Bind(&SaveFileManager::RemoveSavedFileFromFileMap,
-                 file_manager_,
-                 save_ids));
+      base::Bind(&SaveFileManager::RemoveSavedFileFromFileMap, file_manager_,
+                 list_of_failed_save_item_ids));
 
   if (download_) {
     // Hack to avoid touching download_ after user cancel.
@@ -808,17 +794,19 @@
 }
 
 // Called for updating end state.
-void SavePackage::SaveFinished(int32 save_id, int64 size, bool is_success) {
+void SavePackage::SaveFinished(int32 save_item_id,
+                               int64 size,
+                               bool is_success) {
   // Because we might have canceled this saving job before,
   // so we might not find corresponding SaveItem. Just ignore it.
-  SaveItem* save_item = LookupItemInProcessBySaveId(save_id);
+  SaveItem* save_item = LookupSaveItemInProcess(save_item_id);
   if (!save_item)
     return;
 
   // Let SaveItem set end state.
   save_item->Finish(size, is_success);
   // Remove the associated save id and SavePackage.
-  file_manager_->RemoveSaveFile(save_id, save_item->url(), this);
+  file_manager_->RemoveSaveFile(save_item->id(), this);
 
   PutInProgressItemToSavedMap(save_item);
 
@@ -851,63 +839,12 @@
   CheckFinish();
 }
 
-// Sometimes, the net io will only call SaveFileManager::SaveFinished with
-// save id -1 when it encounters error. Since in this case, save id will be
-// -1, so we can only use URL to find which SaveItem is associated with
-// this error.
-// Saving an item failed. If it's a sub-resource, ignore it. If the error comes
-// from serializing HTML data, then cancel saving page.
-void SavePackage::SaveFailed(const GURL& save_url) {
-  SaveUrlItemMap::iterator it = in_progress_items_.find(save_url.spec());
-  if (it == in_progress_items_.end()) {
-    NOTREACHED();  // Should not exist!
-    return;
-  }
-  SaveItem* save_item = it->second;
-
-  save_item->Finish(0, false);
-
-  PutInProgressItemToSavedMap(save_item);
-
-  // Inform the DownloadItem to update UI.
-  // We use the received bytes as number of saved files.
-  // Hack to avoid touching download_ after user cancel.
-  // TODO(rdsmith/benjhayden): Integrate canceling on DownloadItem
-  // with SavePackage flow.
-  if (download_ && (download_->GetState() == DownloadItem::IN_PROGRESS)) {
-    download_->DestinationUpdate(
-        completed_count(), CurrentSpeed(), std::string());
-  }
-
-  if ((save_type_ == SAVE_PAGE_TYPE_AS_ONLY_HTML) ||
-      (save_type_ == SAVE_PAGE_TYPE_AS_MHTML) ||
-      (save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM)) {
-    // We got error when saving page. Treat it as disk error.
-    Cancel(true);
-  }
-
-  if (canceled()) {
-    DCHECK(finished_);
-    return;
-  }
-
-  // Continue processing the save page job.
-  DoSavingProcess();
-
-  CheckFinish();
-}
-
 void SavePackage::SaveCanceled(SaveItem* save_item) {
   // Call the RemoveSaveFile in UI thread.
-  file_manager_->RemoveSaveFile(save_item->save_id(),
-                                save_item->url(),
-                                this);
-  if (save_item->save_id() != -1)
-    BrowserThread::PostTask(
-        BrowserThread::FILE, FROM_HERE,
-        base::Bind(&SaveFileManager::CancelSave,
-                   file_manager_,
-                   save_item->save_id()));
+  file_manager_->RemoveSaveFile(save_item->id(), this);
+  BrowserThread::PostTask(
+      BrowserThread::FILE, FROM_HERE,
+      base::Bind(&SaveFileManager::CancelSave, file_manager_, save_item->id()));
 }
 
 // Initiate a saving job of a specific URL. We send the request to
@@ -924,21 +861,16 @@
     waiting_item_queue_.pop_front();
 
     // Add the item to in_progress_items_.
-    SaveUrlItemMap::iterator it = in_progress_items_.find(
-        save_item->url().spec());
+    SaveItemIdMap::iterator it = in_progress_items_.find(save_item->id());
     DCHECK(it == in_progress_items_.end());
-    in_progress_items_[save_item->url().spec()] = save_item;
+    in_progress_items_[save_item->id()] = save_item;
     save_item->Start();
-    file_manager_->SaveURL(save_item->url(),
-                           save_item->referrer(),
-                           web_contents()->GetRenderProcessHost()->GetID(),
-                           routing_id(),
-                           web_contents()->GetMainFrame()->GetRoutingID(),
-                           save_item->save_source(),
-                           save_item->full_path(),
-                           web_contents()->
-                               GetBrowserContext()->GetResourceContext(),
-                           this);
+    file_manager_->SaveURL(
+        save_item->id(), save_item->url(), save_item->referrer(),
+        web_contents()->GetRenderProcessHost()->GetID(), routing_id(),
+        web_contents()->GetMainFrame()->GetRoutingID(),
+        save_item->save_source(), save_item->full_path(),
+        web_contents()->GetBrowserContext()->GetResourceContext(), this);
   } while (process_all_remaining_items && waiting_item_queue_.size());
 }
 
@@ -1067,26 +999,25 @@
   // SECURITY NOTE: We don't send *all* urls / local paths, but only
   // those that the given frame had access to already (because it contained
   // the savable resources / subframes associated with save items).
-  std::vector<GURL> saved_links;
-  std::vector<base::FilePath> saved_file_paths;
+  std::map<GURL, base::FilePath> url_to_local_path;
   auto it = frame_tree_node_id_to_contained_save_items_.find(
       target_frame_tree_node_id);
   if (it != frame_tree_node_id_to_contained_save_items_.end()) {
     for (SaveItem* save_item : it->second) {
       DCHECK(save_item->has_final_name());
-      saved_links.push_back(save_item->url());
-      saved_file_paths.push_back(save_item->file_name());
+      base::FilePath local_path(base::FilePath::kCurrentDirectory);
+      if (target_tree_node->IsMainFrame()) {
+        local_path = local_path.Append(saved_main_directory_path_.BaseName());
+      }
+      local_path = local_path.Append(save_item->file_name());
+      url_to_local_path[save_item->url()] = local_path;
     }
   }
 
-  base::FilePath directory = target_tree_node->IsMainFrame()
-                                 ? saved_main_directory_path_.BaseName()
-                                 : base::FilePath();
-
   // Ask target frame to serialize itself.
   RenderFrameHostImpl* target = target_tree_node->current_frame_host();
   target->Send(new FrameMsg_GetSerializedHtmlWithLocalLinks(
-      target->GetRoutingID(), saved_links, saved_file_paths, directory));
+      target->GetRoutingID(), url_to_local_path));
 }
 
 // Process the serialized HTML content data of a specified frame
@@ -1119,7 +1050,7 @@
       }
     }
 
-    auto it2 = saved_failed_items_.find(save_item->url().spec());
+    auto it2 = saved_failed_items_.find(save_item->id());
     if (it2 != saved_failed_items_.end())
       wrote_to_failed_file_ = true;
 
@@ -1134,40 +1065,22 @@
     // Call write file functionality in file thread.
     BrowserThread::PostTask(
         BrowserThread::FILE, FROM_HERE,
-        base::Bind(&SaveFileManager::UpdateSaveProgress,
-                   file_manager_,
-                   save_item->save_id(),
-                   new_data,
-                   static_cast<int>(data.size())));
+        base::Bind(&SaveFileManager::UpdateSaveProgress, file_manager_,
+                   save_item->id(), new_data, static_cast<int>(data.size())));
   }
 
   // Current frame is completed saving, call finish in file thread.
   if (end_of_data) {
     DVLOG(20) << " " << __FUNCTION__ << "()"
-              << " save_id = " << save_item->save_id()
-              << " url = \"" << save_item->url().spec() << "\"";
+              << " save_item_id = " << save_item->id() << " url = \""
+              << save_item->url().spec() << "\"";
     BrowserThread::PostTask(
         BrowserThread::FILE, FROM_HERE,
         base::Bind(&SaveFileManager::SaveFinished, file_manager_,
-                   save_item->save_id(), save_item->url(), id(), true));
+                   save_item->id(), id(), true));
     number_of_frames_pending_response_--;
     DCHECK_LE(0, number_of_frames_pending_response_);
   }
-
-  // If all frames are finished saving, we need to close the remaining
-  // SaveItems.
-  if (number_of_frames_pending_response_ == 0) {
-    for (SaveUrlItemMap::iterator it = in_progress_items_.begin();
-         it != in_progress_items_.end(); ++it) {
-      DVLOG(20) << " " << __FUNCTION__ << "()"
-                << " save_id = " << it->second->save_id() << " url = \""
-                << it->second->url().spec() << "\"";
-      BrowserThread::PostTask(
-          BrowserThread::FILE, FROM_HERE,
-          base::Bind(&SaveFileManager::SaveFinished, file_manager_,
-                     it->second->save_id(), it->second->url(), id(), true));
-    }
-  }
 }
 
 // Ask for all savable resource links from backend, include main frame and
@@ -1233,7 +1146,7 @@
   CompleteSavableResourceLinksResponse();
 }
 
-SaveItem* SavePackage::FindOrCreatePendingSaveItem(
+SaveItem* SavePackage::CreatePendingSaveItem(
     int container_frame_tree_node_id,
     const GURL& url,
     const Referrer& referrer,
@@ -1241,21 +1154,40 @@
   DCHECK(url.is_valid());  // |url| should be validated by the callers.
 
   SaveItem* save_item;
-  auto it = url_to_save_item_.find(url);
-  if (it != url_to_save_item_.end()) {
-    save_item = it->second;
-  } else {
-    Referrer sanitized_referrer = Referrer::SanitizeForRequest(url, referrer);
-    save_item = new SaveItem(url, sanitized_referrer, this, save_source);
-    waiting_item_queue_.push_back(save_item);
-    url_to_save_item_[url] = save_item;
-  }
+  Referrer sanitized_referrer = Referrer::SanitizeForRequest(url, referrer);
+  save_item = new SaveItem(url, sanitized_referrer, this, save_source);
+  waiting_item_queue_.push_back(save_item);
 
   frame_tree_node_id_to_contained_save_items_[container_frame_tree_node_id]
       .push_back(save_item);
   return save_item;
 }
 
+SaveItem* SavePackage::CreatePendingSaveItemDeduplicatingByUrl(
+    int container_frame_tree_node_id,
+    const GURL& url,
+    const Referrer& referrer,
+    SaveFileCreateInfo::SaveFileSource save_source) {
+  DCHECK(url.is_valid());  // |url| should be validated by the callers.
+
+  // Frames should not be deduplicated by URL.
+  DCHECK_NE(SaveFileCreateInfo::SAVE_FILE_FROM_DOM, save_source);
+
+  SaveItem* save_item;
+  auto it = url_to_save_item_.find(url);
+  if (it != url_to_save_item_.end()) {
+    save_item = it->second;
+    frame_tree_node_id_to_contained_save_items_[container_frame_tree_node_id]
+        .push_back(save_item);
+  } else {
+    save_item = CreatePendingSaveItem(container_frame_tree_node_id, url,
+                                      referrer, save_source);
+    url_to_save_item_[url] = save_item;
+  }
+
+  return save_item;
+}
+
 void SavePackage::EnqueueSavableResource(int container_frame_tree_node_id,
                                          const GURL& url,
                                          const Referrer& referrer) {
@@ -1265,8 +1197,8 @@
   SaveFileCreateInfo::SaveFileSource save_source =
       url.SchemeIsFile() ? SaveFileCreateInfo::SAVE_FILE_FROM_FILE
                          : SaveFileCreateInfo::SAVE_FILE_FROM_NET;
-  FindOrCreatePendingSaveItem(container_frame_tree_node_id, url, referrer,
-                              save_source);
+  CreatePendingSaveItemDeduplicatingByUrl(container_frame_tree_node_id, url,
+                                          referrer, save_source);
 }
 
 void SavePackage::EnqueueFrame(int container_frame_tree_node_id,
@@ -1275,9 +1207,9 @@
   if (!frame_original_url.is_valid())
     return;
 
-  SaveItem* save_item = FindOrCreatePendingSaveItem(
-      container_frame_tree_node_id, frame_original_url, Referrer(),
-      SaveFileCreateInfo::SAVE_FILE_FROM_DOM);
+  SaveItem* save_item =
+      CreatePendingSaveItem(container_frame_tree_node_id, frame_original_url,
+                            Referrer(), SaveFileCreateInfo::SAVE_FILE_FROM_DOM);
   DCHECK(save_item);
   frame_tree_node_id_to_save_item_[frame_tree_node_id] = save_item;
 }
diff --git a/content/browser/download/save_package.h b/content/browser/download/save_package.h
index 8c06208..19ba225 100644
--- a/content/browser/download/save_package.h
+++ b/content/browser/download/save_package.h
@@ -107,9 +107,8 @@
 
   // Notifications sent from the file thread to the UI thread.
   void StartSave(const SaveFileCreateInfo* info);
-  bool UpdateSaveProgress(int32 save_id, int64 size, bool write_success);
-  void SaveFinished(int32 save_id, int64 size, bool is_success);
-  void SaveFailed(const GURL& save_url);
+  bool UpdateSaveProgress(int32 save_item_id, int64 size, bool write_success);
+  void SaveFinished(int32 save_item_id, int64 size, bool is_success);
   void SaveCanceled(SaveItem* save_item);
 
   // Rough percent complete, -1 means we don't know (since we didn't receive a
@@ -186,9 +185,9 @@
   // and pending responses are counted/tracked by
   // CompleteSavableResourceLinksResponse.
   //
-  // OnSavableResourceLinksResponse creates of SaveItems for each savable
-  // resource and each subframe which get enqueued into |waiting_item_queue_|
-  // with the help of FindOrCreatePendingSaveItem, EnqueueSavableResource,
+  // OnSavableResourceLinksResponse creates SaveItems for each savable resource
+  // and each subframe - these SaveItems get enqueued into |waiting_item_queue_|
+  // with the help of CreatePendingSaveItem, EnqueueSavableResource,
   // EnqueueFrame.
   void GetSavableResourceLinks();
 
@@ -203,7 +202,15 @@
       const std::vector<SavableSubframe>& subframes);
 
   // Helper for finding or creating a SaveItem with the given parameters.
-  SaveItem* FindOrCreatePendingSaveItem(
+  SaveItem* CreatePendingSaveItem(
+      int container_frame_tree_node_id,
+      const GURL& url,
+      const Referrer& referrer,
+      SaveFileCreateInfo::SaveFileSource save_source);
+
+  // Helper for finding a SaveItem with the given url, or falling back to
+  // creating a SaveItem with the given parameters.
+  SaveItem* CreatePendingSaveItemDeduplicatingByUrl(
       int container_frame_tree_node_id,
       const GURL& url,
       const Referrer& referrer,
@@ -243,8 +250,8 @@
                                               const std::string& data,
                                               bool end_of_data);
 
-  // Look up SaveItem by save id from in progress map.
-  SaveItem* LookupItemInProcessBySaveId(int32 save_id);
+  // Look up SaveItem by save item id from in progress map.
+  SaveItem* LookupSaveItemInProcess(int32 save_item_id);
 
   // Remove SaveItem from in progress map and put it to saved map.
   void PutInProgressItemToSavedMap(SaveItem* save_item);
@@ -264,11 +271,12 @@
       SavePageType type,
       const SavePackageDownloadCreatedCallback& cb);
 
-  typedef base::hash_map<std::string, SaveItem*> SaveUrlItemMap;
+  // Map from SaveItem::id() (aka save_item_id) into a SaveItem.
+  typedef base::hash_map<int, SaveItem*> SaveItemIdMap;
   // in_progress_items_ is map of all saving job in in-progress state.
-  SaveUrlItemMap in_progress_items_;
+  SaveItemIdMap in_progress_items_;
   // saved_failed_items_ is map of all saving job which are failed.
-  SaveUrlItemMap saved_failed_items_;
+  SaveItemIdMap saved_failed_items_;
 
   // The number of in process SaveItems.
   int in_process_count() const {
diff --git a/content/browser/download/save_types.cc b/content/browser/download/save_types.cc
index b2965326..d9cc0fc 100644
--- a/content/browser/download/save_types.cc
+++ b/content/browser/download/save_types.cc
@@ -4,30 +4,46 @@
 
 #include "content/browser/download/save_types.h"
 
+#include "base/files/file_path.h"
+
 namespace content {
 
 SaveFileCreateInfo::SaveFileCreateInfo(const base::FilePath& path,
                                        const GURL& url,
-                                       SaveFileSource save_source,
-                                       int32 save_id)
+                                       int save_item_id,
+                                       int save_package_id,
+                                       int render_process_id,
+                                       int render_frame_routing_id,
+                                       SaveFileSource save_source)
     : path(path),
       url(url),
-      save_id(save_id),
-      save_package_id(-1),
-      render_process_id(-1),
-      render_frame_routing_id(-1),
+      save_item_id(save_item_id),
+      save_package_id(save_package_id),
+      render_process_id(render_process_id),
+      render_frame_routing_id(render_frame_routing_id),
       request_id(-1),
       total_bytes(0),
       save_source(save_source) {}
 
-SaveFileCreateInfo::SaveFileCreateInfo()
-    : save_id(-1),
-      save_package_id(-1),
-      render_process_id(-1),
-      render_frame_routing_id(-1),
-      request_id(-1),
-      total_bytes(0),
-      save_source(SAVE_FILE_FROM_UNKNOWN) {}
+SaveFileCreateInfo::SaveFileCreateInfo(const GURL& url,
+                                       const GURL& final_url,
+                                       int save_item_id,
+                                       int save_package_id,
+                                       int render_process_id,
+                                       int render_frame_routing_id,
+                                       int request_id,
+                                       const std::string& content_disposition,
+                                       int64 total_bytes)
+    : url(url),
+      final_url(final_url),
+      save_item_id(save_item_id),
+      save_package_id(save_package_id),
+      render_process_id(render_process_id),
+      render_frame_routing_id(render_frame_routing_id),
+      request_id(request_id),
+      content_disposition(content_disposition),
+      total_bytes(total_bytes),
+      save_source(SaveFileCreateInfo::SAVE_FILE_FROM_NET) {}
 
 SaveFileCreateInfo::~SaveFileCreateInfo() {}
 
diff --git a/content/browser/download/save_types.h b/content/browser/download/save_types.h
index 504be2f3..c7da3bd 100644
--- a/content/browser/download/save_types.h
+++ b/content/browser/download/save_types.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_BROWSER_DOWNLOAD_SAVE_TYPES_H_
 #define CONTENT_BROWSER_DOWNLOAD_SAVE_TYPES_H_
 
+#include <map>
 #include <string>
 #include <utility>
 #include <vector>
@@ -14,8 +15,9 @@
 #include "url/gurl.h"
 
 namespace content {
-typedef std::vector<std::pair<int, base::FilePath> > FinalNameList;
-typedef std::vector<int> SaveIDList;
+
+// Map from save_item_id into final file path.
+typedef std::map<int, base::FilePath> FinalNamesMap;
 
 // This structure is used to handle and deliver some info
 // when processing each save item job.
@@ -33,12 +35,25 @@
     SAVE_FILE_FROM_FILE
   };
 
+  // Constructor for SAVE_FILE_FROM_DOM and/or SAVE_FILE_FROM_FILE.
   SaveFileCreateInfo(const base::FilePath& path,
                      const GURL& url,
-                     SaveFileSource save_source,
-                     int32 save_id);
+                     int save_item_id,
+                     int save_package_id,
+                     int render_process_id,
+                     int render_frame_routing_id,
+                     SaveFileSource save_source);
 
-  SaveFileCreateInfo();
+  // Constructor for SAVE_FILE_FROM_NET case.
+  SaveFileCreateInfo(const GURL& url,
+                     const GURL& final_url,
+                     int save_item_id,
+                     int save_package_id,
+                     int render_process_id,
+                     int render_frame_routing_id,
+                     int request_id,
+                     const std::string& content_disposition,
+                     int64 total_bytes);
 
   ~SaveFileCreateInfo();
 
@@ -49,9 +64,8 @@
   GURL url;
   // Final URL of the saved resource since some URL might be redirected.
   GURL final_url;
-  // The unique identifier for saving job, assigned at creation by
-  // the SaveFileManager for its internal record keeping.
-  int save_id;
+  // The unique identifier of SaveItem object associated with this job.
+  int save_item_id;
   // ID of SavePackage object.
   int save_package_id;
   // IDs for looking up the contents we are associated with.
diff --git a/content/browser/file_descriptor_info_impl.cc b/content/browser/file_descriptor_info_impl.cc
index c6cf831..f071b42 100644
--- a/content/browser/file_descriptor_info_impl.cc
+++ b/content/browser/file_descriptor_info_impl.cc
@@ -6,6 +6,8 @@
 
 #include <utility>
 
+#include "base/stl_util.h"
+
 namespace content {
 
 // static
@@ -25,7 +27,7 @@
 
 void FileDescriptorInfoImpl::Transfer(int id, base::ScopedFD fd) {
   AddToMapping(id, fd.get());
-  owned_descriptors_.push_back(new base::ScopedFD(std::move(fd)));
+  owned_descriptors_.push_back(std::move(fd));
 }
 
 base::PlatformFile FileDescriptorInfoImpl::GetFDAt(size_t i) const {
@@ -50,21 +52,17 @@
 }
 
 bool FileDescriptorInfoImpl::OwnsFD(base::PlatformFile file) const {
-  return owned_descriptors_.end() !=
-         std::find_if(
-             owned_descriptors_.begin(), owned_descriptors_.end(),
-             [file](const base::ScopedFD* fd) { return fd->get() == file; });
+  return ContainsValue(owned_descriptors_, file);
 }
 
 base::ScopedFD FileDescriptorInfoImpl::ReleaseFD(base::PlatformFile file) {
   DCHECK(OwnsFD(file));
 
   base::ScopedFD fd;
-  auto found = std::find_if(
-      owned_descriptors_.begin(), owned_descriptors_.end(),
-      [file](const base::ScopedFD* fd) { return fd->get() == file; });
+  auto found =
+      std::find(owned_descriptors_.begin(), owned_descriptors_.end(), file);
 
-  (*found)->swap(fd);
+  std::swap(*found, fd);
   owned_descriptors_.erase(found);
 
   return fd;
diff --git a/content/browser/file_descriptor_info_impl.h b/content/browser/file_descriptor_info_impl.h
index 40db959..0e25abf 100644
--- a/content/browser/file_descriptor_info_impl.h
+++ b/content/browser/file_descriptor_info_impl.h
@@ -5,8 +5,9 @@
 #ifndef CONTENT_BROWSER_FILE_DESCRIPTOR_INFO_IMPL_H_
 #define CONTENT_BROWSER_FILE_DESCRIPTOR_INFO_IMPL_H_
 
+#include <vector>
+
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/file_descriptor_info.h"
 
@@ -34,7 +35,7 @@
   void AddToMapping(int id, base::PlatformFile fd);
   bool HasID(int id) const;
   base::FileHandleMappingVector mapping_;
-  ScopedVector<base::ScopedFD> owned_descriptors_;
+  std::vector<base::ScopedFD> owned_descriptors_;
 };
 }
 
diff --git a/content/browser/fileapi/blob_url_request_job_unittest.cc b/content/browser/fileapi/blob_url_request_job_unittest.cc
index 96becf0..5edc79a 100644
--- a/content/browser/fileapi/blob_url_request_job_unittest.cc
+++ b/content/browser/fileapi/blob_url_request_job_unittest.cc
@@ -2,7 +2,10 @@
 // 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 <limits>
+
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -224,7 +227,7 @@
   }
 
   void TestSuccessNonrangeRequest(const std::string& expected_response,
-                                  int64 expected_content_length) {
+                                  int64_t expected_content_length) {
     expected_status_code_ = 200;
     expected_response_ = expected_response;
     TestRequest("GET", net::HttpRequestHeaders());
@@ -292,14 +295,14 @@
 
   // This only works if all the Blob items have a definite pre-computed length.
   // Otherwise, this will fail a CHECK.
-  int64 GetTotalBlobLength() {
-    int64 total = 0;
+  int64_t GetTotalBlobLength() {
+    int64_t total = 0;
     scoped_ptr<BlobDataSnapshot> data =
         GetHandleFromBuilder()->CreateSnapshot();
     const auto& items = data->items();
     for (const auto& item : items) {
-      int64 length = base::checked_cast<int64>(item->length());
-      CHECK(length <= kint64max - total);
+      int64_t length = base::checked_cast<int64_t>(item->length());
+      CHECK(length <= std::numeric_limits<int64_t>::max() - total);
       total += length;
     }
     return total;
@@ -342,7 +345,8 @@
 }
 
 TEST_F(BlobURLRequestJobTest, TestGetSimpleFileRequest) {
-  blob_data_->AppendFile(temp_file1_, 0, kuint64max, base::Time());
+  blob_data_->AppendFile(temp_file1_, 0, std::numeric_limits<uint64_t>::max(),
+                         base::Time());
   TestSuccessNonrangeRequest(kTestFileData1, arraysize(kTestFileData1) - 1);
 }
 
@@ -356,14 +360,16 @@
   ASSERT_EQ(static_cast<int>(large_data.size()),
             base::WriteFile(large_temp_file, large_data.data(),
                             large_data.size()));
-  blob_data_->AppendFile(large_temp_file, 0, kuint64max, base::Time());
+  blob_data_->AppendFile(large_temp_file, 0,
+                         std::numeric_limits<uint64_t>::max(), base::Time());
   TestSuccessNonrangeRequest(large_data, large_data.size());
 }
 
 TEST_F(BlobURLRequestJobTest, TestGetNonExistentFileRequest) {
   base::FilePath non_existent_file =
       temp_file1_.InsertBeforeExtension(FILE_PATH_LITERAL("-na"));
-  blob_data_->AppendFile(non_existent_file, 0, kuint64max, base::Time());
+  blob_data_->AppendFile(non_existent_file, 0,
+                         std::numeric_limits<uint64_t>::max(), base::Time());
   TestErrorRequest(404);
 }
 
@@ -382,7 +388,8 @@
 
 TEST_F(BlobURLRequestJobTest, TestGetSimpleFileSystemFileRequest) {
   SetUpFileSystem();
-  blob_data_->AppendFileSystemFile(temp_file_system_file1_, 0, kuint64max,
+  blob_data_->AppendFileSystemFile(temp_file_system_file1_, 0,
+                                   std::numeric_limits<uint64_t>::max(),
                                    base::Time());
   TestSuccessNonrangeRequest(kTestFileSystemFileData1,
                              arraysize(kTestFileSystemFileData1) - 1);
@@ -398,7 +405,8 @@
   const char kFilename[] = "LargeBlob.dat";
   WriteFileSystemFile(kFilename, large_data.data(), large_data.size(), NULL);
 
-  blob_data_->AppendFileSystemFile(GetFileSystemURL(kFilename), 0, kuint64max,
+  blob_data_->AppendFileSystemFile(GetFileSystemURL(kFilename), 0,
+                                   std::numeric_limits<uint64_t>::max(),
                                    base::Time());
   TestSuccessNonrangeRequest(large_data, large_data.size());
 }
@@ -406,15 +414,16 @@
 TEST_F(BlobURLRequestJobTest, TestGetNonExistentFileSystemFileRequest) {
   SetUpFileSystem();
   GURL non_existent_file = GetFileSystemURL("non-existent.dat");
-  blob_data_->AppendFileSystemFile(non_existent_file, 0, kuint64max,
-                                   base::Time());
+  blob_data_->AppendFileSystemFile(
+      non_existent_file, 0, std::numeric_limits<uint64_t>::max(), base::Time());
   TestErrorRequest(404);
 }
 
 TEST_F(BlobURLRequestJobTest, TestGetInvalidFileSystemFileRequest) {
   SetUpFileSystem();
   GURL invalid_file;
-  blob_data_->AppendFileSystemFile(invalid_file, 0, kuint64max, base::Time());
+  blob_data_->AppendFileSystemFile(
+      invalid_file, 0, std::numeric_limits<uint64_t>::max(), base::Time());
   TestErrorRequest(500);
 }
 
@@ -463,7 +472,7 @@
 
   EXPECT_EQ(6, request_->response_headers()->GetContentLength());
 
-  int64 first = 0, last = 0, length = 0;
+  int64_t first = 0, last = 0, length = 0;
   EXPECT_TRUE(
       request_->response_headers()->GetContentRange(&first, &last, &length));
   EXPECT_EQ(5, first);
@@ -484,8 +493,8 @@
 
   EXPECT_EQ(10, request_->response_headers()->GetContentLength());
 
-  int64 total = GetTotalBlobLength();
-  int64 first = 0, last = 0, length = 0;
+  int64_t total = GetTotalBlobLength();
+  int64_t first = 0, last = 0, length = 0;
   EXPECT_TRUE(
       request_->response_headers()->GetContentRange(&first, &last, &length));
   EXPECT_EQ(total - 10, first);
@@ -506,7 +515,7 @@
 
   EXPECT_EQ(3, request_->response_headers()->GetContentLength());
 
-  int64 first = 0, last = 0, length = 0;
+  int64_t first = 0, last = 0, length = 0;
   EXPECT_TRUE(
       request_->response_headers()->GetContentRange(&first, &last, &length));
   EXPECT_EQ(0, first);
diff --git a/content/browser/fileapi/file_system_usage_cache_unittest.cc b/content/browser/fileapi/file_system_usage_cache_unittest.cc
index f67485c..e6bbdc9 100644
--- a/content/browser/fileapi/file_system_usage_cache_unittest.cc
+++ b/content/browser/fileapi/file_system_usage_cache_unittest.cc
@@ -4,7 +4,10 @@
 
 #include "storage/browser/fileapi/file_system_usage_cache.h"
 
-#include "base/basictypes.h"
+#include <stdint.h>
+
+#include <limits>
+
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/message_loop/message_loop.h"
@@ -45,18 +48,18 @@
 }
 
 TEST_F(FileSystemUsageCacheTest, SetSizeTest) {
-  static const int64 size = 240122;
+  static const int64_t size = 240122;
   base::FilePath usage_file_path = GetUsageFilePath();
-  int64 usage = 0;
+  int64_t usage = 0;
   ASSERT_TRUE(usage_cache()->UpdateUsage(usage_file_path, size));
   EXPECT_TRUE(usage_cache()->GetUsage(usage_file_path, &usage));
   EXPECT_EQ(size, usage);
 }
 
 TEST_F(FileSystemUsageCacheTest, SetLargeSizeTest) {
-  static const int64 size = kint64max;
+  static const int64_t size = std::numeric_limits<int64_t>::max();
   base::FilePath usage_file_path = GetUsageFilePath();
-  int64 usage = 0;
+  int64_t usage = 0;
   ASSERT_TRUE(usage_cache()->UpdateUsage(usage_file_path, size));
   EXPECT_TRUE(usage_cache()->GetUsage(usage_file_path, &usage));
   EXPECT_EQ(size, usage);
@@ -64,8 +67,8 @@
 
 TEST_F(FileSystemUsageCacheTest, IncAndGetSizeTest) {
   base::FilePath usage_file_path = GetUsageFilePath();
-  uint32 dirty = 0;
-  int64 usage = 0;
+  uint32_t dirty = 0;
+  int64_t usage = 0;
   ASSERT_TRUE(usage_cache()->UpdateUsage(usage_file_path, 98214));
   ASSERT_TRUE(usage_cache()->IncrementDirty(usage_file_path));
   EXPECT_TRUE(usage_cache()->GetDirty(usage_file_path, &dirty));
@@ -75,9 +78,9 @@
 }
 
 TEST_F(FileSystemUsageCacheTest, DecAndGetSizeTest) {
-  static const int64 size = 71839;
+  static const int64_t size = 71839;
   base::FilePath usage_file_path = GetUsageFilePath();
-  int64 usage = 0;
+  int64_t usage = 0;
   ASSERT_TRUE(usage_cache()->UpdateUsage(usage_file_path, size));
   // DecrementDirty for dirty = 0 is invalid. It returns false.
   ASSERT_FALSE(usage_cache()->DecrementDirty(usage_file_path));
@@ -86,9 +89,9 @@
 }
 
 TEST_F(FileSystemUsageCacheTest, IncDecAndGetSizeTest) {
-  static const int64 size = 198491;
+  static const int64_t size = 198491;
   base::FilePath usage_file_path = GetUsageFilePath();
-  int64 usage = 0;
+  int64_t usage = 0;
   ASSERT_TRUE(usage_cache()->UpdateUsage(usage_file_path, size));
   ASSERT_TRUE(usage_cache()->IncrementDirty(usage_file_path));
   ASSERT_TRUE(usage_cache()->DecrementDirty(usage_file_path));
@@ -98,8 +101,8 @@
 
 TEST_F(FileSystemUsageCacheTest, DecIncAndGetSizeTest) {
   base::FilePath usage_file_path = GetUsageFilePath();
-  uint32 dirty = 0;
-  int64 usage = 0;
+  uint32_t dirty = 0;
+  int64_t usage = 0;
   ASSERT_TRUE(usage_cache()->UpdateUsage(usage_file_path, 854238));
   // DecrementDirty for dirty = 0 is invalid. It returns false.
   ASSERT_FALSE(usage_cache()->DecrementDirty(usage_file_path));
@@ -113,9 +116,9 @@
 }
 
 TEST_F(FileSystemUsageCacheTest, ManyIncsSameDecsAndGetSizeTest) {
-  static const int64 size = 82412;
+  static const int64_t size = 82412;
   base::FilePath usage_file_path = GetUsageFilePath();
-  int64 usage = 0;
+  int64_t usage = 0;
   ASSERT_TRUE(usage_cache()->UpdateUsage(usage_file_path, size));
   for (int i = 0; i < 20; i++)
     ASSERT_TRUE(usage_cache()->IncrementDirty(usage_file_path));
@@ -126,8 +129,8 @@
 }
 
 TEST_F(FileSystemUsageCacheTest, ManyIncsLessDecsAndGetSizeTest) {
-  uint32 dirty = 0;
-  int64 usage = 0;
+  uint32_t dirty = 0;
+  int64_t usage = 0;
   base::FilePath usage_file_path = GetUsageFilePath();
   ASSERT_TRUE(usage_cache()->UpdateUsage(usage_file_path, 19319));
   for (int i = 0; i < 20; i++)
@@ -141,7 +144,7 @@
 }
 
 TEST_F(FileSystemUsageCacheTest, GetSizeWithoutCacheFileTest) {
-  int64 usage = 0;
+  int64_t usage = 0;
   base::FilePath usage_file_path = GetUsageFilePath();
   EXPECT_FALSE(usage_cache()->GetUsage(usage_file_path, &usage));
 }
diff --git a/content/browser/fileapi/file_writer_delegate_unittest.cc b/content/browser/fileapi/file_writer_delegate_unittest.cc
index 9eb73b1..cba75304 100644
--- a/content/browser/fileapi/file_writer_delegate_unittest.cc
+++ b/content/browser/fileapi/file_writer_delegate_unittest.cc
@@ -2,14 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <stdint.h>
+
+#include <limits>
 #include <string>
 #include <vector>
 
-#include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/location.h"
+#include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
@@ -52,12 +55,13 @@
         write_status_(FileWriterDelegate::SUCCESS_IO_PENDING) {}
 
   base::File::Error status() const { return status_; }
-  int64 bytes_written() const { return bytes_written_; }
+  int64_t bytes_written() const { return bytes_written_; }
   FileWriterDelegate::WriteProgressStatus write_status() const {
     return write_status_;
   }
 
-  void DidWrite(base::File::Error status, int64 bytes,
+  void DidWrite(base::File::Error status,
+                int64_t bytes,
                 FileWriterDelegate::WriteProgressStatus write_status) {
     write_status_ = write_status;
     if (status == base::File::FILE_OK) {
@@ -74,7 +78,7 @@
  private:
   // For post-operation status.
   base::File::Error status_;
-  int64 bytes_written_;
+  int64_t bytes_written_;
   FileWriterDelegate::WriteProgressStatus write_status_;
 };
 
@@ -90,13 +94,13 @@
   void SetUp() override;
   void TearDown() override;
 
-  int64 usage() {
+  int64_t usage() {
     return file_system_context_->GetQuotaUtil(kFileSystemType)
         ->GetOriginUsageOnFileTaskRunner(
               file_system_context_.get(), kOrigin, kFileSystemType);
   }
 
-  int64 GetFileSizeOnDisk(const char* test_file_path) {
+  int64_t GetFileSizeOnDisk(const char* test_file_path) {
     // There might be in-flight flush/write.
     base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
                                                   base::Bind(&base::DoNothing));
@@ -115,10 +119,9 @@
         kOrigin, kFileSystemType, base::FilePath().FromUTF8Unsafe(file_name));
   }
 
-  FileWriterDelegate* CreateWriterDelegate(
-      const char* test_file_path,
-      int64 offset,
-      int64 allowed_growth) {
+  FileWriterDelegate* CreateWriterDelegate(const char* test_file_path,
+                                           int64_t offset,
+                                           int64_t allowed_growth) {
     storage::SandboxFileStreamWriter* writer =
         new storage::SandboxFileStreamWriter(
             file_system_context_.get(),
@@ -138,8 +141,8 @@
   // and creates a new FileWriterDelegate for the file.
   void PrepareForWrite(const char* test_file_path,
                        const GURL& blob_url,
-                       int64 offset,
-                       int64 allowed_growth) {
+                       int64_t offset,
+                       int64_t allowed_growth) {
     file_writer_delegate_.reset(
         CreateWriterDelegate(test_file_path, offset, allowed_growth));
     request_ = empty_context_.CreateRequest(
@@ -175,13 +178,13 @@
       : net::URLRequestJob(request, network_delegate),
         content_(content),
         remaining_bytes_(content.length()),
-        cursor_(0) {
-  }
+        cursor_(0),
+        weak_factory_(this) {}
 
   void Start() override {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::Bind(&FileWriterDelegateTestJob::NotifyHeadersComplete, this));
+        FROM_HERE, base::Bind(&FileWriterDelegateTestJob::NotifyHeadersComplete,
+                              weak_factory_.GetWeakPtr()));
   }
 
   int ReadRawData(net::IOBuffer* buf, int buf_size) override {
@@ -204,6 +207,8 @@
   std::string content_;
   int remaining_bytes_;
   int cursor_;
+
+  base::WeakPtrFactory<FileWriterDelegateTestJob> weak_factory_;
 };
 
 class BlobURLRequestJobFactory : public net::URLRequestJobFactory {
@@ -274,7 +279,7 @@
   const GURL kBlobURL("blob:nolimit");
   content_ = kData;
 
-  PrepareForWrite("test", kBlobURL, 0, kint64max);
+  PrepareForWrite("test", kBlobURL, 0, std::numeric_limits<int64_t>::max());
 
   Result result;
   ASSERT_EQ(0, usage());
@@ -293,7 +298,7 @@
 TEST_F(FileWriterDelegateTest, WriteSuccessWithJustQuota) {
   const GURL kBlobURL("blob:just");
   content_ = kData;
-  const int64 kAllowedGrowth = kDataSize;
+  const int64_t kAllowedGrowth = kDataSize;
   PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
 
   Result result;
@@ -313,7 +318,7 @@
 TEST_F(FileWriterDelegateTest, DISABLED_WriteFailureByQuota) {
   const GURL kBlobURL("blob:failure");
   content_ = kData;
-  const int64 kAllowedGrowth = kDataSize - 1;
+  const int64_t kAllowedGrowth = kDataSize - 1;
   PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
 
   Result result;
@@ -334,7 +339,7 @@
 TEST_F(FileWriterDelegateTest, WriteZeroBytesSuccessfullyWithZeroQuota) {
   const GURL kBlobURL("blob:zero");
   content_ = "";
-  int64 kAllowedGrowth = 0;
+  int64_t kAllowedGrowth = 0;
   PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
 
   Result result;
@@ -364,10 +369,11 @@
   const GURL kBlobURL2("blob:nolimitconcurrent2");
   content_ = kData;
 
-  PrepareForWrite("test", kBlobURL, 0, kint64max);
+  PrepareForWrite("test", kBlobURL, 0, std::numeric_limits<int64_t>::max());
 
   // Credate another FileWriterDelegate for concurrent write.
-  file_writer_delegate2.reset(CreateWriterDelegate("test2", 0, kint64max));
+  file_writer_delegate2.reset(
+      CreateWriterDelegate("test2", 0, std::numeric_limits<int64_t>::max()));
   request2 = empty_context_.CreateRequest(
       kBlobURL2, net::DEFAULT_PRIORITY, file_writer_delegate2.get());
 
@@ -399,8 +405,8 @@
   content_ = kData;
 
   // Writing kDataSize (=45) bytes data while allowed_growth is 100.
-  int64 offset = 0;
-  int64 allowed_growth = 100;
+  int64_t offset = 0;
+  int64_t allowed_growth = 100;
   ASSERT_LT(kDataSize, allowed_growth);
   PrepareForWrite("test", kBlobURL, offset, allowed_growth);
 
@@ -457,7 +463,7 @@
   offset = 0;
   allowed_growth = -20;
   PrepareForWrite("test", kBlobURL, offset, allowed_growth);
-  int64 pre_write_usage = GetFileSizeOnDisk("test");
+  int64_t pre_write_usage = GetFileSizeOnDisk("test");
 
   {
     Result result;
diff --git a/content/browser/fileapi/obfuscated_file_util_unittest.cc b/content/browser/fileapi/obfuscated_file_util_unittest.cc
index 06638ff..d04e517 100644
--- a/content/browser/fileapi/obfuscated_file_util_unittest.cc
+++ b/content/browser/fileapi/obfuscated_file_util_unittest.cc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <stdint.h>
+
+#include <limits>
 #include <set>
 #include <string>
 #include <vector>
@@ -54,8 +57,8 @@
   return base::PathExists(path) && !base::DirectoryExists(path);
 }
 
-int64 GetSize(const base::FilePath& path) {
-  int64 size;
+int64_t GetSize(const base::FilePath& path) {
+  int64_t size;
   EXPECT_TRUE(base::GetFileSize(path, &size));
   return size;
 }
@@ -182,7 +185,7 @@
   }
 
   scoped_ptr<FileSystemOperationContext> LimitedContext(
-      int64 allowed_bytes_growth) {
+      int64_t allowed_bytes_growth) {
     scoped_ptr<FileSystemOperationContext> context(
         sandbox_file_system_.NewOperationContext());
     context->set_allowed_bytes_growth(allowed_bytes_growth);
@@ -190,7 +193,7 @@
   }
 
   scoped_ptr<FileSystemOperationContext> UnlimitedContext() {
-    return LimitedContext(kint64max);
+    return LimitedContext(std::numeric_limits<int64_t>::max());
   }
 
   FileSystemOperationContext* NewContext(
@@ -253,13 +256,13 @@
     return GetTypeString(type_);
   }
 
-  int64 ComputeTotalFileSize() {
+  int64_t ComputeTotalFileSize() {
     return sandbox_file_system_.ComputeCurrentOriginUsage() -
         sandbox_file_system_.ComputeCurrentDirectoryDatabaseUsage();
   }
 
   void GetUsageFromQuotaManager() {
-    int64 quota = -1;
+    int64_t quota = -1;
     quota_status_ =
         AsyncFileTestHelper::GetUsageAndQuota(quota_manager_.get(),
                                               origin(),
@@ -274,13 +277,13 @@
     usage_cache()->Delete(sandbox_file_system_.GetUsageCachePath());
   }
 
-  int64 SizeByQuotaUtil() {
+  int64_t SizeByQuotaUtil() {
     return sandbox_file_system_.GetCachedOriginUsage();
   }
 
-  int64 SizeInUsageFile() {
+  int64_t SizeInUsageFile() {
     base::RunLoop().RunUntilIdle();
-    int64 usage = 0;
+    int64_t usage = 0;
     return usage_cache()->GetUsage(
         sandbox_file_system_.GetUsageCachePath(), &usage) ? usage : -1;
   }
@@ -298,7 +301,7 @@
     return AsyncFileTestHelper::DirectoryExists(file_system_context(), url);
   }
 
-  int64 usage() const { return usage_; }
+  int64_t usage() const { return usage_; }
   storage::FileSystemUsageCache* usage_cache() {
     return sandbox_file_system_.usage_cache();
   }
@@ -307,7 +310,7 @@
     return sandbox_file_system_.CreateURLFromUTF8(path);
   }
 
-  int64 PathCost(const FileSystemURL& url) {
+  int64_t PathCost(const FileSystemURL& url) {
     return ObfuscatedFileUtil::ComputeFilePathCost(url.path());
   }
 
@@ -393,7 +396,7 @@
    public:
     UsageVerifyHelper(scoped_ptr<FileSystemOperationContext> context,
                       SandboxFileSystemTestHelper* file_system,
-                      int64 expected_usage)
+                      int64_t expected_usage)
         : context_(context.Pass()),
           sandbox_file_system_(file_system),
           expected_usage_(expected_usage) {}
@@ -415,18 +418,19 @@
 
     scoped_ptr<FileSystemOperationContext> context_;
     SandboxFileSystemTestHelper* sandbox_file_system_;
-    int64 expected_usage_;
+    int64_t expected_usage_;
   };
 
-  scoped_ptr<UsageVerifyHelper> AllowUsageIncrease(int64 requested_growth) {
-    int64 usage = sandbox_file_system_.GetCachedOriginUsage();
+  scoped_ptr<UsageVerifyHelper> AllowUsageIncrease(int64_t requested_growth) {
+    int64_t usage = sandbox_file_system_.GetCachedOriginUsage();
     return scoped_ptr<UsageVerifyHelper>(new UsageVerifyHelper(
         LimitedContext(requested_growth),
         &sandbox_file_system_, usage + requested_growth));
   }
 
-  scoped_ptr<UsageVerifyHelper> DisallowUsageIncrease(int64 requested_growth) {
-    int64 usage = sandbox_file_system_.GetCachedOriginUsage();
+  scoped_ptr<UsageVerifyHelper> DisallowUsageIncrease(
+      int64_t requested_growth) {
+    int64_t usage = sandbox_file_system_.GetCachedOriginUsage();
     return scoped_ptr<UsageVerifyHelper>(new UsageVerifyHelper(
         LimitedContext(requested_growth - 1), &sandbox_file_system_, usage));
   }
@@ -544,7 +548,7 @@
     base::FilePath root_file_path = source_dir.path();
     base::FilePath src_file_path = root_file_path.AppendASCII("file_name");
     FileSystemURL dest_url = CreateURLFromUTF8("new file");
-    int64 src_file_length = 87;
+    int64_t src_file_length = 87;
 
     base::File file(src_file_path,
                     base::File::FLAG_CREATE | base::File::FLAG_WRITE);
@@ -567,7 +571,7 @@
       EXPECT_TRUE(change_observer()->HasNoChange());
     }
 
-    const int64 path_cost =
+    const int64_t path_cost =
         ObfuscatedFileUtil::ComputeFilePathCost(dest_url.path());
     if (!overwrite) {
       // Verify that file creation requires sufficient quota for the path.
@@ -779,7 +783,7 @@
     EXPECT_EQ(kFakeDirectoryData, origin_db_data);
   }
 
-  int64 ComputeCurrentUsage() {
+  int64_t ComputeCurrentUsage() {
     return sandbox_file_system_.ComputeCurrentOriginUsage() -
         sandbox_file_system_.ComputeCurrentDirectoryDatabaseUsage();
   }
@@ -802,7 +806,7 @@
   storage::FileSystemType type_;
   SandboxFileSystemTestHelper sandbox_file_system_;
   storage::QuotaStatusCode quota_status_;
-  int64 usage_;
+  int64_t usage_;
   storage::MockFileChangeObserver change_observer_;
   storage::ChangeObserverList change_observers_;
   base::WeakPtrFactory<ObfuscatedFileUtilTest> weak_factory_;
@@ -1264,7 +1268,7 @@
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), url, &created));
   EXPECT_TRUE(created);
-  int64 path_cost = ObfuscatedFileUtil::ComputeFilePathCost(url.path());
+  int64_t path_cost = ObfuscatedFileUtil::ComputeFilePathCost(url.path());
   EXPECT_EQ(1024 - path_cost, context->allowed_bytes_growth());
 
   context->set_allowed_bytes_growth(1024);
@@ -1330,8 +1334,8 @@
 }
 
 TEST_F(ObfuscatedFileUtilTest, TestCopyOrMoveFileSuccess) {
-  const int64 kSourceLength = 5;
-  const int64 kDestLength = 50;
+  const int64_t kSourceLength = 5;
+  const int64_t kDestLength = 50;
 
   for (size_t i = 0; i < arraysize(kCopyMoveTestCases); ++i) {
     SCOPED_TRACE(testing::Message() << "kCopyMoveTestCase " << i);
@@ -1504,7 +1508,7 @@
       dir_url, src_url.path().value());
 
   bool is_copy = false;
-  int64 allowed_bytes_growth = -1000;  // Over quota, this should still work.
+  int64_t allowed_bytes_growth = -1000;  // Over quota, this should still work.
   // Move, no rename, no overwrite.
   context.reset(NewContext(NULL));
   context->set_allowed_bytes_growth(allowed_bytes_growth);
@@ -1655,7 +1659,7 @@
 TEST_F(ObfuscatedFileUtilTest, TestRevokeUsageCache) {
   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
 
-  int64 expected_quota = 0;
+  int64_t expected_quota = 0;
 
   for (size_t i = 0; i < kRegularFileSystemTestCaseSize; ++i) {
     SCOPED_TRACE(testing::Message() << "Creating kRegularTestCase " << i);
@@ -2072,7 +2076,7 @@
   FileSystemURL to_file2(CreateURLFromUTF8("tofile2"));
   bool created;
 
-  int64 expected_total_file_size = 0;
+  int64_t expected_total_file_size = 0;
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(
                 AllowUsageIncrease(PathCost(from_file))->context(),
@@ -2087,7 +2091,7 @@
   ASSERT_TRUE(created);
   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
 
-  int64 from_file_size = 1020;
+  int64_t from_file_size = 1020;
   expected_total_file_size += from_file_size;
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->Truncate(
@@ -2095,7 +2099,7 @@
                 from_file, from_file_size));
   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
 
-  int64 obstacle_file_size = 1;
+  int64_t obstacle_file_size = 1;
   expected_total_file_size += obstacle_file_size;
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->Truncate(
@@ -2103,7 +2107,7 @@
                 obstacle_file, obstacle_file_size));
   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
 
-  int64 to_file1_size = from_file_size;
+  int64_t to_file1_size = from_file_size;
   expected_total_file_size += to_file1_size;
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->CopyOrMoveFile(
@@ -2122,7 +2126,7 @@
                 true /* copy */));
   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
 
-  int64 old_obstacle_file_size = obstacle_file_size;
+  int64_t old_obstacle_file_size = obstacle_file_size;
   obstacle_file_size = from_file_size;
   expected_total_file_size += obstacle_file_size - old_obstacle_file_size;
   ASSERT_EQ(base::File::FILE_OK,
@@ -2134,7 +2138,7 @@
                 true /* copy */));
   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
 
-  int64 old_from_file_size = from_file_size;
+  int64_t old_from_file_size = from_file_size;
   from_file_size = old_from_file_size - 1;
   expected_total_file_size += from_file_size - old_from_file_size;
   ASSERT_EQ(base::File::FILE_OK,
@@ -2169,7 +2173,7 @@
   FileSystemURL to_file(CreateURLFromUTF8("tofile"));
   bool created;
 
-  int64 expected_total_file_size = 0;
+  int64_t expected_total_file_size = 0;
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(
                 AllowUsageIncrease(PathCost(from_file))->context(),
@@ -2177,7 +2181,7 @@
   ASSERT_TRUE(created);
   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
 
-  int64 from_file_size = 1020;
+  int64_t from_file_size = 1020;
   expected_total_file_size += from_file_size;
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->Truncate(
@@ -2217,7 +2221,7 @@
                 from_file, from_file_size));
   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
 
-  int64 obstacle_file_size = 1;
+  int64_t obstacle_file_size = 1;
   expected_total_file_size += obstacle_file_size;
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->Truncate(
@@ -2225,7 +2229,7 @@
                 obstacle_file, obstacle_file_size));
   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
 
-  int64 old_obstacle_file_size = obstacle_file_size;
+  int64_t old_obstacle_file_size = obstacle_file_size;
   obstacle_file_size = from_file_size;
   from_file_size = 0;
   expected_total_file_size -= old_obstacle_file_size;
diff --git a/content/browser/fileapi/sandbox_database_test_helper.cc b/content/browser/fileapi/sandbox_database_test_helper.cc
index bedc104..45dbaff7 100644
--- a/content/browser/fileapi/sandbox_database_test_helper.cc
+++ b/content/browser/fileapi/sandbox_database_test_helper.cc
@@ -4,8 +4,11 @@
 
 #include "content/browser/fileapi/sandbox_database_test_helper.h"
 
+#include <stdint.h>
+
 #include <algorithm>
 #include <functional>
+#include <limits>
 #include <vector>
 
 #include "base/files/file.h"
@@ -26,22 +29,23 @@
       base::FileEnumerator::DIRECTORIES | base::FileEnumerator::FILES);
   base::FilePath file_path;
   base::FilePath picked_file_path;
-  uint64 picked_file_number = kuint64max;
+  uint64_t picked_file_number = std::numeric_limits<uint64_t>::max();
 
   while (!(file_path = file_enum.Next()).empty()) {
-    uint64 number = kuint64max;
+    uint64_t number = std::numeric_limits<uint64_t>::max();
     leveldb::FileType file_type;
     EXPECT_TRUE(leveldb::ParseFileName(FilePathToString(file_path.BaseName()),
                                        &number, &file_type));
     if (file_type == type &&
-        (picked_file_number == kuint64max || picked_file_number < number)) {
+        (picked_file_number == std::numeric_limits<uint64_t>::max() ||
+         picked_file_number < number)) {
       picked_file_path = file_path;
       picked_file_number = number;
     }
   }
 
   EXPECT_FALSE(picked_file_path.empty());
-  EXPECT_NE(kuint64max, picked_file_number);
+  EXPECT_NE(std::numeric_limits<uint64_t>::max(), picked_file_number);
 
   base::File file(picked_file_path,
                   base::File::FLAG_OPEN | base::File::FLAG_READ |
@@ -78,7 +82,7 @@
       base::FileEnumerator::DIRECTORIES | base::FileEnumerator::FILES);
   base::FilePath file_path;
   while (!(file_path = file_enum.Next()).empty()) {
-    uint64 number = kuint64max;
+    uint64_t number = std::numeric_limits<uint64_t>::max();
     leveldb::FileType file_type;
     EXPECT_TRUE(leveldb::ParseFileName(FilePathToString(file_path.BaseName()),
                                        &number, &file_type));
diff --git a/content/browser/fileapi/upload_file_system_file_element_reader.cc b/content/browser/fileapi/upload_file_system_file_element_reader.cc
index 3cf45fe4..1951b94 100644
--- a/content/browser/fileapi/upload_file_system_file_element_reader.cc
+++ b/content/browser/fileapi/upload_file_system_file_element_reader.cc
@@ -19,8 +19,8 @@
 UploadFileSystemFileElementReader::UploadFileSystemFileElementReader(
     storage::FileSystemContext* file_system_context,
     const GURL& url,
-    uint64 range_offset,
-    uint64 range_length,
+    uint64_t range_offset,
+    uint64_t range_length,
     const base::Time& expected_modification_time)
     : file_system_context_(file_system_context),
       url_(url),
@@ -29,8 +29,7 @@
       expected_modification_time_(expected_modification_time),
       stream_length_(0),
       position_(0),
-      weak_ptr_factory_(this) {
-}
+      weak_ptr_factory_(this) {}
 
 UploadFileSystemFileElementReader::~UploadFileSystemFileElementReader() {
 }
@@ -44,18 +43,16 @@
 
   // Initialize the stream reader and the length.
   stream_reader_ = file_system_context_->CreateFileStreamReader(
-      file_system_context_->CrackURL(url_),
-      range_offset_,
-      range_length_ == std::numeric_limits<uint64>::max()
+      file_system_context_->CrackURL(url_), range_offset_,
+      range_length_ == std::numeric_limits<uint64_t>::max()
           ? storage::kMaximumLength
-          : base::checked_cast<int64>(range_length_),
+          : base::checked_cast<int64_t>(range_length_),
       expected_modification_time_);
   DCHECK(stream_reader_);
 
-  const int64 result = stream_reader_->GetLength(
+  const int64_t result = stream_reader_->GetLength(
       base::Bind(&UploadFileSystemFileElementReader::OnGetLength,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 callback));
+                 weak_ptr_factory_.GetWeakPtr(), callback));
   if (result >= 0) {
     stream_length_ = result;
     return net::OK;
@@ -65,11 +62,11 @@
   return static_cast<int>(result);
 }
 
-uint64 UploadFileSystemFileElementReader::GetContentLength() const {
+uint64_t UploadFileSystemFileElementReader::GetContentLength() const {
   return std::min(stream_length_, range_length_);
 }
 
-uint64 UploadFileSystemFileElementReader::BytesRemaining() const {
+uint64_t UploadFileSystemFileElementReader::BytesRemaining() const {
   return GetContentLength() - position_;
 }
 
@@ -80,8 +77,8 @@
   DCHECK_LT(0, buf_length);
   DCHECK(stream_reader_);
 
-  const uint64 num_bytes_to_read =
-      std::min(BytesRemaining(), static_cast<uint64>(buf_length));
+  const uint64_t num_bytes_to_read =
+      std::min(BytesRemaining(), static_cast<uint64_t>(buf_length));
 
   if (num_bytes_to_read == 0)
     return 0;
@@ -98,7 +95,7 @@
 
 void UploadFileSystemFileElementReader::OnGetLength(
     const net::CompletionCallback& callback,
-    int64 result) {
+    int64_t result) {
   if (result >= 0) {
     stream_length_ = result;
     callback.Run(net::OK);
diff --git a/content/browser/fileapi/upload_file_system_file_element_reader.h b/content/browser/fileapi/upload_file_system_file_element_reader.h
index bc2a6f7..582e65cd 100644
--- a/content/browser/fileapi/upload_file_system_file_element_reader.h
+++ b/content/browser/fileapi/upload_file_system_file_element_reader.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_BROWSER_FILEAPI_UPLOAD_FILE_SYSTEM_FILE_ELEMENT_READER_H_
 #define CONTENT_BROWSER_FILEAPI_UPLOAD_FILE_SYSTEM_FILE_ELEMENT_READER_H_
 
+#include <stdint.h>
+
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "content/common/content_export.h"
@@ -28,33 +30,33 @@
   UploadFileSystemFileElementReader(
       storage::FileSystemContext* file_system_context,
       const GURL& url,
-      uint64 range_offset,
-      uint64 range_length,
+      uint64_t range_offset,
+      uint64_t range_length,
       const base::Time& expected_modification_time);
   ~UploadFileSystemFileElementReader() override;
 
   // UploadElementReader overrides:
   int Init(const net::CompletionCallback& callback) override;
-  uint64 GetContentLength() const override;
-  uint64 BytesRemaining() const override;
+  uint64_t GetContentLength() const override;
+  uint64_t BytesRemaining() const override;
   int Read(net::IOBuffer* buf,
            int buf_length,
            const net::CompletionCallback& callback) override;
 
  private:
-  void OnGetLength(const net::CompletionCallback& callback, int64 result);
+  void OnGetLength(const net::CompletionCallback& callback, int64_t result);
   void OnRead(const net::CompletionCallback& callback, int result);
 
   scoped_refptr<storage::FileSystemContext> file_system_context_;
   const GURL url_;
-  const uint64 range_offset_;
-  const uint64 range_length_;
+  const uint64_t range_offset_;
+  const uint64_t range_length_;
   const base::Time expected_modification_time_;
 
   scoped_ptr<storage::FileStreamReader> stream_reader_;
 
-  uint64 stream_length_;
-  uint64 position_;
+  uint64_t stream_length_;
+  uint64_t position_;
 
   base::WeakPtrFactory<UploadFileSystemFileElementReader> weak_ptr_factory_;
 
diff --git a/content/browser/fileapi/upload_file_system_file_element_reader_unittest.cc b/content/browser/fileapi/upload_file_system_file_element_reader_unittest.cc
index 7e16a725..e54923c6 100644
--- a/content/browser/fileapi/upload_file_system_file_element_reader_unittest.cc
+++ b/content/browser/fileapi/upload_file_system_file_element_reader_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/fileapi/upload_file_system_file_element_reader.h"
 
+#include <limits>
+
 #include "base/files/scoped_temp_dir.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
@@ -60,12 +62,9 @@
                         &file_modification_time_);
 
     // Create and initialize a reader.
-    reader_.reset(
-        new UploadFileSystemFileElementReader(file_system_context_.get(),
-                                              file_url_,
-                                              0,
-                                              kuint64max,
-                                              file_modification_time_));
+    reader_.reset(new UploadFileSystemFileElementReader(
+        file_system_context_.get(), file_url_, 0,
+        std::numeric_limits<uint64_t>::max(), file_modification_time_));
     net::TestCompletionCallback callback;
     ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(callback.callback()));
     EXPECT_EQ(net::OK, callback.WaitForResult());
@@ -244,8 +243,8 @@
   net::TestCompletionCallback init_callback;
   ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback.callback()));
   EXPECT_EQ(net::OK, init_callback.WaitForResult());
-  EXPECT_EQ(static_cast<uint64>(kLength), reader_->GetContentLength());
-  EXPECT_EQ(static_cast<uint64>(kLength), reader_->BytesRemaining());
+  EXPECT_EQ(static_cast<uint64_t>(kLength), reader_->GetContentLength());
+  EXPECT_EQ(static_cast<uint64_t>(kLength), reader_->BytesRemaining());
   scoped_refptr<net::IOBufferWithSize> buf = new net::IOBufferWithSize(kLength);
   net::TestCompletionCallback read_callback;
   ASSERT_EQ(net::ERR_IO_PENDING,
@@ -260,12 +259,9 @@
   // Expect one second before the actual modification time to simulate change.
   const base::Time expected_modification_time =
       file_modification_time_ - base::TimeDelta::FromSeconds(1);
-  reader_.reset(
-      new UploadFileSystemFileElementReader(file_system_context_.get(),
-                                            file_url_,
-                                            0,
-                                            kuint64max,
-                                            expected_modification_time));
+  reader_.reset(new UploadFileSystemFileElementReader(
+      file_system_context_.get(), file_url_, 0,
+      std::numeric_limits<uint64_t>::max(), expected_modification_time));
   net::TestCompletionCallback init_callback;
   ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback.callback()));
   EXPECT_EQ(net::ERR_UPLOAD_FILE_CHANGED, init_callback.WaitForResult());
@@ -274,7 +270,8 @@
 TEST_F(UploadFileSystemFileElementReaderTest, WrongURL) {
   const GURL wrong_url = GetFileSystemURL("wrong_file_name.dat");
   reader_.reset(new UploadFileSystemFileElementReader(
-      file_system_context_.get(), wrong_url, 0, kuint64max, base::Time()));
+      file_system_context_.get(), wrong_url, 0,
+      std::numeric_limits<uint64_t>::max(), base::Time()));
   net::TestCompletionCallback init_callback;
   ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback.callback()));
   EXPECT_EQ(net::ERR_FILE_NOT_FOUND, init_callback.WaitForResult());
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 38642fc..58d1bd9c 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/browser/frame_host/frame_navigation_entry.h"
@@ -26,6 +27,7 @@
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
+#include "content/shell/common/shell_switches.h"
 #include "content/test/content_browser_test_utils_internal.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -2680,6 +2682,105 @@
   EXPECT_EQ(dsn_3, dsn_4);
 }
 
+// Support a set of tests that isolate only a subset of sites with
+// out-of-process iframes (OOPIFs).
+class NavigationControllerOopifBrowserTest
+    : public NavigationControllerBrowserTest {
+ public:
+  NavigationControllerOopifBrowserTest() {}
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    // Enable the OOPIF framework but only isolate sites from a single TLD.
+    command_line->AppendSwitchASCII(switches::kIsolateSitesForTesting, "*.is");
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NavigationControllerOopifBrowserTest);
+};
+
+// Verify that restoring a NavigationEntry with cross-site subframes does not
+// create out-of-process iframes unless the current SiteIsolationPolicy says to.
+IN_PROC_BROWSER_TEST_F(NavigationControllerOopifBrowserTest,
+                       RestoreWithoutExtraOopifs) {
+  // This test requires OOPIFs to be possible.
+  EXPECT_TRUE(SiteIsolationPolicy::AreCrossProcessFramesPossible());
+
+  // 1. Start on a page with a data URL iframe.
+  GURL main_url_a(embedded_test_server()->GetURL(
+      "a.com", "/navigation_controller/page_with_data_iframe.html"));
+  GURL data_url("data:text/html,Subframe");
+  EXPECT_TRUE(NavigateToURL(shell(), main_url_a));
+  const NavigationControllerImpl& controller =
+      static_cast<const NavigationControllerImpl&>(
+          shell()->web_contents()->GetController());
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+  EXPECT_EQ(main_url_a, root->current_url());
+  EXPECT_EQ(data_url, root->child_at(0)->current_url());
+
+  // 2. Navigate the iframe cross-site.
+  GURL frame_url_b(embedded_test_server()->GetURL(
+      "b.com", "/navigation_controller/simple_page_1.html"));
+  NavigateFrameToURL(root->child_at(0), frame_url_b);
+  EXPECT_EQ(main_url_a, root->current_url());
+  EXPECT_EQ(frame_url_b, root->child_at(0)->current_url());
+
+  EXPECT_EQ(2, controller.GetEntryCount());
+  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
+  NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
+
+  // 3. Create a NavigationEntry with the same PageState as |entry2|.
+  scoped_ptr<NavigationEntryImpl> restored_entry =
+      NavigationEntryImpl::FromNavigationEntry(
+          NavigationControllerImpl::CreateNavigationEntry(
+              main_url_a, Referrer(), ui::PAGE_TRANSITION_RELOAD, false,
+              std::string(), controller.GetBrowserContext()));
+  restored_entry->SetPageID(0);
+  EXPECT_EQ(0U, restored_entry->root_node()->children.size());
+  restored_entry->SetPageState(entry2->GetPageState());
+
+  // The entry should have no SiteInstance in the FrameNavigationEntry for the
+  // b.com subframe.
+  EXPECT_FALSE(
+      restored_entry->root_node()->children[0]->frame_entry->site_instance());
+
+  // 4. Restore the new entry in a new tab and verify the correct URLs load.
+  std::vector<scoped_ptr<NavigationEntry>> entries;
+  entries.push_back(restored_entry.Pass());
+  Shell* new_shell = Shell::CreateNewWindow(
+      controller.GetBrowserContext(), GURL::EmptyGURL(), nullptr, gfx::Size());
+  FrameTreeNode* new_root =
+      static_cast<WebContentsImpl*>(new_shell->web_contents())
+          ->GetFrameTree()
+          ->root();
+  NavigationControllerImpl& new_controller =
+      static_cast<NavigationControllerImpl&>(
+          new_shell->web_contents()->GetController());
+  new_controller.Restore(
+      entries.size() - 1,
+      NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY, &entries);
+  ASSERT_EQ(0u, entries.size());
+  {
+    TestNavigationObserver restore_observer(new_shell->web_contents());
+    new_controller.LoadIfNecessary();
+    restore_observer.Wait();
+  }
+  ASSERT_EQ(1U, new_root->child_count());
+  EXPECT_EQ(main_url_a, new_root->current_url());
+  EXPECT_EQ(frame_url_b, new_root->child_at(0)->current_url());
+
+  // The subframe should only be in a different SiteInstance if OOPIFs are
+  // required for all sites.
+  if (AreAllSitesIsolatedForTesting()) {
+    EXPECT_NE(new_root->current_frame_host()->GetSiteInstance(),
+              new_root->child_at(0)->current_frame_host()->GetSiteInstance());
+  } else {
+    EXPECT_EQ(new_root->current_frame_host()->GetSiteInstance(),
+              new_root->child_at(0)->current_frame_host()->GetSiteInstance());
+  }
+}
+
 namespace {
 
 // Loads |start_url|, then loads |stalled_url| which stalls. While the page is
diff --git a/content/browser/frame_host/navigation_entry_impl.cc b/content/browser/frame_host/navigation_entry_impl.cc
index dae19c67..343951e 100644
--- a/content/browser/frame_host/navigation_entry_impl.cc
+++ b/content/browser/frame_host/navigation_entry_impl.cc
@@ -601,12 +601,13 @@
     current_offset_to_send = -1;
     current_length_to_send = 0;
   }
+
   return RequestNavigationParams(
       GetIsOverridingUserAgent(), redirects, GetCanLoadLocalResources(),
       base::Time::Now(), frame_entry.page_state(), GetPageID(), GetUniqueID(),
       is_same_document_history_load, has_committed_real_load,
       intended_as_new_entry, pending_offset_to_send, current_offset_to_send,
-      current_length_to_send, should_clear_history_list());
+      current_length_to_send, IsViewSourceMode(), should_clear_history_list());
 }
 
 void NavigationEntryImpl::ResetForCommit() {
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 769c868..027ba758 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -138,6 +138,7 @@
       false,                   // intended_as_new_entry
       -1,                      // pending_history_list_offset
       current_history_list_offset, current_history_list_length,
+      false,                   // is_view_source
       false);                  // should_clear_history_list
   scoped_ptr<NavigationRequest> navigation_request(
       new NavigationRequest(frame_tree_node, common_params, begin_params,
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index dab752c..96d6c1f 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -2319,11 +2319,34 @@
     bool dest_is_view_source_mode,
     const GlobalRequestID& transferred_request_id,
     int bindings) {
-  // Don't swap for subframes unless we are in --site-per-process.  We can get
-  // here in tests for subframes (e.g., NavigateFrameToURL).
-  if (!frame_tree_node_->IsMainFrame() &&
-      !SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
-    return render_frame_host_.get();
+  if (!frame_tree_node_->IsMainFrame()) {
+    // Don't swap for subframes unless we are in an OOPIF-enabled mode.  We can
+    // get here in tests for subframes (e.g., NavigateFrameToURL).
+    if (!SiteIsolationPolicy::AreCrossProcessFramesPossible())
+      return render_frame_host_.get();
+
+    // If dest_url is a unique origin like about:blank, then the need for a swap
+    // is determined by the source_instance.
+    GURL resolved_url = dest_url;
+    if (url::Origin(resolved_url).unique()) {
+      // If there is no source_instance for a unique origin, then we should
+      // avoid a process swap.
+      if (!source_instance)
+        return render_frame_host_.get();
+
+      // Use source_instance to determine if a swap is needed.
+      resolved_url = source_instance->GetSiteURL();
+    }
+
+    // If we are in an OOPIF mode that only applies to some sites, only swap if
+    // the policy determines that a transfer would have been needed.  We can get
+    // here for session restore.
+    if (!IsRendererTransferNeededForNavigation(render_frame_host_.get(),
+                                               resolved_url)) {
+      DCHECK(!dest_instance ||
+             dest_instance == render_frame_host_->GetSiteInstance());
+      return render_frame_host_.get();
+    }
   }
 
   SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
diff --git a/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc b/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc
index 4882efbf..f944ead 100644
--- a/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc
@@ -34,7 +34,7 @@
   return ((value + 32768.f) / 32767.5f) - 1.f;
 }
 
-const WebUChar* const GamepadSubTypeName(BYTE sub_type) {
+const WebUChar* GamepadSubTypeName(BYTE sub_type) {
   switch (sub_type) {
     case kDeviceSubTypeGamepad: return L"GAMEPAD";
     case kDeviceSubTypeWheel: return L"WHEEL";
diff --git a/content/browser/gamepad/raw_input_data_fetcher_win.cc b/content/browser/gamepad/raw_input_data_fetcher_win.cc
index 8b3b34f..670a022 100644
--- a/content/browser/gamepad/raw_input_data_fetcher_win.cc
+++ b/content/browser/gamepad/raw_input_data_fetcher_win.cc
@@ -58,9 +58,9 @@
 }
 
 RAWINPUTDEVICE* RawInputDataFetcher::GetRawInputDevices(DWORD flags) {
-  int usage_count = arraysize(DeviceUsages);
+  size_t usage_count = arraysize(DeviceUsages);
   scoped_ptr<RAWINPUTDEVICE[]> devices(new RAWINPUTDEVICE[usage_count]);
-  for (int i = 0; i < usage_count; ++i) {
+  for (size_t i = 0; i < usage_count; ++i) {
     devices[i].dwFlags = flags;
     devices[i].usUsagePage = 1;
     devices[i].usUsage = DeviceUsages[i];
@@ -200,8 +200,8 @@
 
   // Make sure this device is of a type that we want to observe.
   bool valid_type = false;
-  for (int i = 0; i < arraysize(DeviceUsages); ++i) {
-    if (device_info->hid.usUsage == DeviceUsages[i]) {
+  for (USHORT device_usage : DeviceUsages) {
+    if (device_info->hid.usUsage == device_usage) {
       valid_type = true;
       break;
     }
@@ -389,8 +389,10 @@
       for (uint32_t j = 0; j < buttons_length; j++) {
         int32_t button_index = usages[j].Usage - 1;
         if (button_index >= 0 &&
-            button_index < blink::WebGamepad::buttonsLengthCap)
+            button_index <
+                static_cast<int>(blink::WebGamepad::buttonsLengthCap)) {
           gamepad_info->buttons[button_index] = true;
+        }
       }
     }
   }
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index c0217b8..de22507b 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -482,6 +482,7 @@
   gpu_info.gl_renderer = gl_renderer;
   gpu_info.gl_version = gl_version;
 
+  gpu::IdentifyActiveGPU(&gpu_info);
   gpu::CollectDriverInfoGL(&gpu_info);
 
   UpdateGpuInfo(gpu_info);
diff --git a/content/browser/loader/async_resource_handler.cc b/content/browser/loader/async_resource_handler.cc
index da777dc..ec02d13 100644
--- a/content/browser/loader/async_resource_handler.cc
+++ b/content/browser/loader/async_resource_handler.cc
@@ -335,6 +335,7 @@
   // TODO(erikchen): Temporary debugging. http://crbug.com/527588.
   CHECK_LE(data_offset, kBufferSize);
 
+  filter->Send(new ResourceMsg_DataReceivedDebug(GetRequestID(), data_offset));
   filter->Send(new ResourceMsg_DataReceived(
       GetRequestID(), data_offset, bytes_read, encoded_data_length));
   ++pending_data_count_;
diff --git a/content/browser/loader/async_revalidation_driver.cc b/content/browser/loader/async_revalidation_driver.cc
new file mode 100644
index 0000000..3c5d45bc
--- /dev/null
+++ b/content/browser/loader/async_revalidation_driver.cc
@@ -0,0 +1,274 @@
+// 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/browser/loader/async_revalidation_driver.h"
+
+#include <utility>
+
+#include "base/callback_helpers.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "net/base/net_errors.h"
+#include "net/url_request/url_request_status.h"
+
+namespace content {
+
+namespace {
+// This matches the maximum allocation size of AsyncResourceHandler.
+const int kReadBufSize = 32 * 1024;
+
+// The time to wait for a response. Since this includes the time taken to
+// connect, this has been set to match the connect timeout
+// kTransportConnectJobTimeoutInSeconds.
+const int kResponseTimeoutInSeconds = 240;  // 4 minutes.
+
+// This value should not be too large, as this request may be tying up a socket
+// that could be used for something better. However, if it is too small, the
+// cache entry will be truncated for no good reason.
+// TODO(ricea): Find a more scientific way to set this timeout.
+const int kReadTimeoutInSeconds = 30;
+}  // namespace
+
+AsyncRevalidationDriver::AsyncRevalidationDriver(
+    scoped_ptr<net::URLRequest> request,
+    scoped_ptr<ResourceThrottle> throttle,
+    const base::Closure& completion_callback)
+    : request_(std::move(request)),
+      throttle_(std::move(throttle)),
+      completion_callback_(completion_callback),
+      weak_ptr_factory_(this) {
+  request_->set_delegate(this);
+  throttle_->set_controller(this);
+}
+
+AsyncRevalidationDriver::~AsyncRevalidationDriver() {}
+
+void AsyncRevalidationDriver::StartRequest() {
+  // Give the handler a chance to delay the URLRequest from being started.
+  bool defer_start = false;
+  throttle_->WillStartRequest(&defer_start);
+
+  if (defer_start) {
+    RecordDefer();
+  } else {
+    StartRequestInternal();
+  }
+}
+
+void AsyncRevalidationDriver::OnReceivedRedirect(
+    net::URLRequest* request,
+    const net::RedirectInfo& redirect_info,
+    bool* defer) {
+  DCHECK_EQ(request_.get(), request);
+
+  // The async revalidation should not follow redirects, because caching is
+  // a property of an individual HTTP resource.
+  DVLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
+  CancelRequestInternal(net::ERR_ABORTED, RESULT_GOT_REDIRECT);
+}
+
+void AsyncRevalidationDriver::OnAuthRequired(
+    net::URLRequest* request,
+    net::AuthChallengeInfo* auth_info) {
+  DCHECK_EQ(request_.get(), request);
+  // This error code doesn't have exactly the right semantics, but it should
+  // be sufficient to narrow down the problem in net logs.
+  CancelRequestInternal(net::ERR_ACCESS_DENIED, RESULT_AUTH_FAILED);
+}
+
+void AsyncRevalidationDriver::OnBeforeNetworkStart(net::URLRequest* request,
+                                                   bool* defer) {
+  DCHECK_EQ(request_.get(), request);
+
+  // Verify that the ResourceScheduler does not defer here.
+  throttle_->WillStartUsingNetwork(defer);
+  DCHECK(!*defer);
+
+  // Start the response timer. This use of base::Unretained() is guaranteed safe
+  // by the semantics of base::OneShotTimer.
+  timer_.Start(FROM_HERE,
+               base::TimeDelta::FromSeconds(kResponseTimeoutInSeconds),
+               base::Bind(&AsyncRevalidationDriver::OnTimeout,
+                          base::Unretained(this), RESULT_RESPONSE_TIMEOUT));
+}
+
+void AsyncRevalidationDriver::OnResponseStarted(net::URLRequest* request) {
+  DCHECK_EQ(request_.get(), request);
+
+  DVLOG(1) << "OnResponseStarted: " << request_->url().spec();
+
+  // We have the response. No need to wait any longer.
+  timer_.Stop();
+
+  if (!request_->status().is_success()) {
+    UMA_HISTOGRAM_SPARSE_SLOWLY("Net.AsyncRevalidation.ResponseError",
+                                -request_->status().ToNetError());
+    ResponseCompleted(RESULT_NET_ERROR);
+    // |this| may be deleted after this point.
+    return;
+  }
+
+  const net::HttpResponseInfo& response_info = request_->response_info();
+  if (!response_info.response_time.is_null() && response_info.was_cached) {
+    // The cached entry was revalidated. No need to read it in.
+    ResponseCompleted(RESULT_REVALIDATED);
+    // |this| may be deleted after this point.
+    return;
+  }
+
+  bool defer = false;
+  throttle_->WillProcessResponse(&defer);
+  DCHECK(!defer);
+
+  // Set up the timer for reading the body. This use of base::Unretained() is
+  // guaranteed safe by the semantics of base::OneShotTimer.
+  timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(kReadTimeoutInSeconds),
+               base::Bind(&AsyncRevalidationDriver::OnTimeout,
+                          base::Unretained(this), RESULT_BODY_TIMEOUT));
+  StartReading(false);  // Read the first chunk.
+}
+
+void AsyncRevalidationDriver::OnReadCompleted(net::URLRequest* request,
+                                              int bytes_read) {
+  // request_ could be NULL if a timeout happened while OnReadCompleted() was
+  // queued to run asynchronously.
+  if (!request_)
+    return;
+  DCHECK_EQ(request_.get(), request);
+  DCHECK(!is_deferred_);
+  DVLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
+           << " bytes_read = " << bytes_read;
+
+  // bytes_read == 0 is EOF.
+  if (bytes_read == 0) {
+    ResponseCompleted(RESULT_LOADED);
+    return;
+  }
+  // bytes_read == -1 is an error.
+  if (bytes_read == -1 || !request_->status().is_success()) {
+    UMA_HISTOGRAM_SPARSE_SLOWLY("Net.AsyncRevalidation.ReadError",
+                                -request_->status().ToNetError());
+    ResponseCompleted(RESULT_READ_ERROR);
+    // |this| may be deleted after this point.
+    return;
+  }
+
+  DCHECK_GT(bytes_read, 0);
+  StartReading(true);  // Read the next chunk.
+}
+
+void AsyncRevalidationDriver::Resume() {
+  DCHECK(is_deferred_);
+  DCHECK(request_);
+  is_deferred_ = false;
+  request_->LogUnblocked();
+  StartRequestInternal();
+}
+
+void AsyncRevalidationDriver::Cancel() {
+  NOTREACHED();
+}
+
+void AsyncRevalidationDriver::CancelAndIgnore() {
+  NOTREACHED();
+}
+
+void AsyncRevalidationDriver::CancelWithError(int error_code) {
+  NOTREACHED();
+}
+
+void AsyncRevalidationDriver::StartRequestInternal() {
+  DCHECK(request_);
+  DCHECK(!request_->is_pending());
+
+  request_->Start();
+}
+
+void AsyncRevalidationDriver::CancelRequestInternal(
+    int error,
+    AsyncRevalidationResult result) {
+  DVLOG(1) << "CancelRequestInternal: " << request_->url().spec();
+
+  // Set the error code since this will be reported to the NetworkDelegate and
+  // recorded in the NetLog.
+  request_->CancelWithError(error);
+
+  // The ResourceScheduler needs to be able to examine the request when the
+  // ResourceThrottle is destroyed, so delete it first.
+  throttle_.reset();
+
+  // Destroy the request so that it doesn't try to send an asynchronous
+  // notification of completion.
+  request_.reset();
+
+  // Cancel timer to prevent OnTimeout() being called.
+  timer_.Stop();
+
+  ResponseCompleted(result);
+  // |this| may deleted after this point.
+}
+
+void AsyncRevalidationDriver::StartReading(bool is_continuation) {
+  int bytes_read = 0;
+  ReadMore(&bytes_read);
+
+  // If IO is pending, wait for the URLRequest to call OnReadCompleted.
+  if (request_->status().is_io_pending())
+    return;
+
+  if (!is_continuation || bytes_read <= 0) {
+    OnReadCompleted(request_.get(), bytes_read);
+  } else {
+    // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
+    // thread in case the URLRequest can provide data synchronously.
+    scoped_refptr<base::SingleThreadTaskRunner> single_thread_task_runner =
+        base::ThreadTaskRunnerHandle::Get();
+    single_thread_task_runner->PostTask(
+        FROM_HERE,
+        base::Bind(&AsyncRevalidationDriver::OnReadCompleted,
+                   weak_ptr_factory_.GetWeakPtr(), request_.get(), bytes_read));
+  }
+}
+
+void AsyncRevalidationDriver::ReadMore(int* bytes_read) {
+  DCHECK(!is_deferred_);
+
+  if (!read_buffer_)
+    read_buffer_ = new net::IOBuffer(kReadBufSize);
+
+  timer_.Reset();
+  request_->Read(read_buffer_.get(), kReadBufSize, bytes_read);
+
+  // No need to check the return value here as we'll detect errors by
+  // inspecting the URLRequest's status.
+}
+
+void AsyncRevalidationDriver::ResponseCompleted(
+    AsyncRevalidationResult result) {
+  DVLOG(1) << "ResponseCompleted: "
+           << (request_ ? request_->url().spec() : "(request deleted)")
+           << "result = " << result;
+  UMA_HISTOGRAM_ENUMERATION("Net.AsyncRevalidation.Result", result, RESULT_MAX);
+  DCHECK(!completion_callback_.is_null());
+  base::ResetAndReturn(&completion_callback_).Run();
+  // |this| may be deleted after this point.
+}
+
+void AsyncRevalidationDriver::OnTimeout(AsyncRevalidationResult result) {
+  CancelRequestInternal(net::ERR_TIMED_OUT, result);
+}
+
+void AsyncRevalidationDriver::RecordDefer() {
+  request_->LogBlockedBy(throttle_->GetNameForLogging());
+  DCHECK(!is_deferred_);
+  is_deferred_ = true;
+}
+
+}  // namespace content
diff --git a/content/browser/loader/async_revalidation_driver.h b/content/browser/loader/async_revalidation_driver.h
new file mode 100644
index 0000000..b96e06e
--- /dev/null
+++ b/content/browser/loader/async_revalidation_driver.h
@@ -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.
+
+#ifndef CONTENT_BROWSER_LOADER_ASYNC_REVALIDATION_DRIVER_H_
+#define CONTENT_BROWSER_LOADER_ASYNC_REVALIDATION_DRIVER_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/resource_controller.h"
+#include "content/public/browser/resource_throttle.h"
+#include "net/base/io_buffer.h"
+#include "net/url_request/url_request.h"
+
+namespace net {
+class HttpCache;
+}
+
+namespace content {
+
+// This class is responsible for driving the URLRequest for an async
+// revalidation. It is passed an instance of ResourceThrottle created by
+// content::ResourceScheduler to perform throttling on the request.
+class CONTENT_EXPORT AsyncRevalidationDriver : public net::URLRequest::Delegate,
+                                               public ResourceController {
+ public:
+  // |completion_callback| is guaranteed to be called on completion,
+  // regardless of success or failure.
+  AsyncRevalidationDriver(scoped_ptr<net::URLRequest> request,
+                          scoped_ptr<ResourceThrottle> throttle,
+                          const base::Closure& completion_callback);
+  ~AsyncRevalidationDriver() override;
+
+  void StartRequest();
+
+ private:
+  // This enum is logged as histogram "Net.AsyncRevalidation.Result". Only add
+  // new entries at the end and update histograms.xml to match.
+  enum AsyncRevalidationResult {
+    RESULT_LOADED,
+    RESULT_REVALIDATED,
+    RESULT_NET_ERROR,
+    RESULT_READ_ERROR,
+    RESULT_GOT_REDIRECT,
+    RESULT_AUTH_FAILED,
+    RESULT_RESPONSE_TIMEOUT,
+    RESULT_BODY_TIMEOUT,
+    RESULT_MAX
+  };
+
+  // net::URLRequest::Delegate implementation:
+  void OnReceivedRedirect(net::URLRequest* request,
+                          const net::RedirectInfo& redirect_info,
+                          bool* defer) override;
+  void OnAuthRequired(net::URLRequest* request,
+                      net::AuthChallengeInfo* info) override;
+  void OnBeforeNetworkStart(net::URLRequest* request, bool* defer) override;
+  void OnResponseStarted(net::URLRequest* request) override;
+  void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
+
+  // ResourceController implementation:
+  void Resume() override;
+
+  // For simplicity, this class assumes that ResourceScheduler never cancels
+  // requests, and so these three methods are never called.
+  void Cancel() override;
+  void CancelAndIgnore() override;
+  void CancelWithError(int error_code) override;
+
+  // Internal methods.
+  void StartRequestInternal();
+  void CancelRequestInternal(int error, AsyncRevalidationResult result);
+  void StartReading(bool is_continuation);
+  void ReadMore(int* bytes_read);
+  // Logs the result histogram, then calls and clears |completion_callback_|.
+  void ResponseCompleted(AsyncRevalidationResult result);
+  void OnTimeout(AsyncRevalidationResult result);
+  void RecordDefer();
+
+  bool is_deferred_ = false;
+
+  scoped_refptr<net::IOBuffer> read_buffer_;
+  base::OneShotTimer timer_;
+
+  scoped_ptr<net::URLRequest> request_;
+  scoped_ptr<ResourceThrottle> throttle_;
+
+  base::Closure completion_callback_;
+
+  base::WeakPtrFactory<AsyncRevalidationDriver> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(AsyncRevalidationDriver);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_LOADER_ASYNC_REVALIDATION_DRIVER_H_
diff --git a/content/browser/loader/async_revalidation_driver_unittest.cc b/content/browser/loader/async_revalidation_driver_unittest.cc
new file mode 100644
index 0000000..1f5a7e4b
--- /dev/null
+++ b/content/browser/loader/async_revalidation_driver_unittest.cc
@@ -0,0 +1,397 @@
+// 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/browser/loader/async_revalidation_driver.h"
+
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "content/public/browser/client_certificate_delegate.h"
+#include "content/public/common/content_client.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/test/test_content_browser_client.h"
+#include "ipc/ipc_message.h"
+#include "net/base/net_errors.h"
+#include "net/base/network_delegate_impl.h"
+#include "net/base/request_priority.h"
+#include "net/ssl/ssl_cert_request_info.h"
+#include "net/url_request/url_request_job_factory.h"
+#include "net/url_request/url_request_job_factory_impl.h"
+#include "net/url_request/url_request_status.h"
+#include "net/url_request/url_request_test_job.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+
+// Dummy implementation of ResourceThrottle, an instance of which is needed to
+// initialize AsyncRevalidationDriver.
+class ResourceThrottleStub : public ResourceThrottle {
+ public:
+  ResourceThrottleStub() {}
+
+  // If true, defers the request in WillStartRequest.
+  void set_defer_request_on_will_start_request(
+      bool defer_request_on_will_start_request) {
+    defer_request_on_will_start_request_ = defer_request_on_will_start_request;
+  }
+
+  // ResourceThrottler implementation:
+  void WillStartRequest(bool* defer) override {
+    *defer = defer_request_on_will_start_request_;
+  }
+
+  const char* GetNameForLogging() const override {
+    return "ResourceThrottleStub";
+  }
+
+ private:
+  bool defer_request_on_will_start_request_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(ResourceThrottleStub);
+};
+
+// There are multiple layers of boilerplate needed to use a URLRequestTestJob
+// subclass.  Subclasses of AsyncRevalidationDriverTest can use
+// BindCreateProtocolHandlerCallback() to bypass most of that boilerplate.
+using CreateProtocolHandlerCallback =
+    base::Callback<scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>()>;
+
+template <typename T>
+CreateProtocolHandlerCallback BindCreateProtocolHandlerCallback() {
+  static_assert(std::is_base_of<net::URLRequestJob, T>::value,
+                "Template argument to BindCreateProtocolHandlerCallback() must "
+                "be a subclass of URLRequestJob.");
+
+  class TemplatedProtocolHandler
+      : public net::URLRequestJobFactory::ProtocolHandler {
+   public:
+    static scoped_ptr<net::URLRequestJobFactory::ProtocolHandler> Create() {
+      return make_scoped_ptr(new TemplatedProtocolHandler());
+    }
+
+    // URLRequestJobFactory::ProtocolHandler implementation:
+    net::URLRequestJob* MaybeCreateJob(
+        net::URLRequest* request,
+        net::NetworkDelegate* network_delegate) const override {
+      return new T(request, network_delegate);
+    }
+  };
+
+  return base::Bind(&TemplatedProtocolHandler::Create);
+}
+
+// An implementation of NetworkDelegate that captures the status of the last
+// URLRequest to be destroyed.
+class StatusCapturingNetworkDelegate : public net::NetworkDelegateImpl {
+ public:
+  const net::URLRequestStatus& last_status() { return last_status_; }
+
+ private:
+  // net::NetworkDelegate implementation.
+  void OnURLRequestDestroyed(net::URLRequest* request) override {
+    last_status_ = request->status();
+  }
+
+  net::URLRequestStatus last_status_;
+};
+
+class AsyncRevalidationDriverTest : public testing::Test {
+ protected:
+  // Constructor for test fixtures that subclass this one.
+  AsyncRevalidationDriverTest(
+      const CreateProtocolHandlerCallback& create_protocol_handler_callback)
+      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
+        create_protocol_handler_callback_(create_protocol_handler_callback),
+        raw_ptr_resource_throttle_(nullptr),
+        raw_ptr_request_(nullptr) {
+    test_url_request_context_.set_job_factory(&job_factory_);
+    test_url_request_context_.set_network_delegate(&network_delegate_);
+  }
+
+  // Constructor for tests that use this fixture directly.
+  AsyncRevalidationDriverTest()
+      : AsyncRevalidationDriverTest(
+            base::Bind(net::URLRequestTestJob::CreateProtocolHandler)) {}
+
+  bool async_revalidation_complete_called() const {
+    return async_revalidation_complete_called_;
+  }
+
+  const net::URLRequestStatus& last_status() {
+    return network_delegate_.last_status();
+  }
+
+  void SetUpAsyncRevalidationDriverWithRequestToUrl(const GURL& url) {
+    scoped_ptr<net::URLRequest> request(test_url_request_context_.CreateRequest(
+        url, net::DEFAULT_PRIORITY, nullptr /* delegate */));
+    raw_ptr_request_ = request.get();
+    raw_ptr_resource_throttle_ = new ResourceThrottleStub();
+    // This use of base::Unretained() is safe because |driver_|, and the closure
+    // passed to it, will be destroyed before this object is.
+    driver_.reset(new AsyncRevalidationDriver(
+        std::move(request), make_scoped_ptr(raw_ptr_resource_throttle_),
+        base::Bind(&AsyncRevalidationDriverTest::OnAsyncRevalidationComplete,
+                   base::Unretained(this))));
+  }
+
+  void SetUpAsyncRevalidationDriverWithDefaultRequest() {
+    SetUpAsyncRevalidationDriverWithRequestToUrl(
+        net::URLRequestTestJob::test_url_1());
+  }
+
+  void SetUp() override {
+    job_factory_.SetProtocolHandler("test",
+                                    create_protocol_handler_callback_.Run());
+    SetUpAsyncRevalidationDriverWithDefaultRequest();
+  }
+
+  void OnAsyncRevalidationComplete() {
+    EXPECT_FALSE(async_revalidation_complete_called_);
+    async_revalidation_complete_called_ = true;
+    driver_.reset();
+  }
+
+  TestBrowserThreadBundle thread_bundle_;
+  net::URLRequestJobFactoryImpl job_factory_;
+  net::TestURLRequestContext test_url_request_context_;
+  StatusCapturingNetworkDelegate network_delegate_;
+  CreateProtocolHandlerCallback create_protocol_handler_callback_;
+
+  // The AsyncRevalidationDriver owns the URLRequest and the ResourceThrottle.
+  ResourceThrottleStub* raw_ptr_resource_throttle_;
+  net::URLRequest* raw_ptr_request_;
+  scoped_ptr<AsyncRevalidationDriver> driver_;
+  bool async_revalidation_complete_called_ = false;
+};
+
+TEST_F(AsyncRevalidationDriverTest, NormalRequestCompletes) {
+  driver_->StartRequest();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(async_revalidation_complete_called());
+}
+
+// Verifies that request that should be deferred at start is deferred.
+TEST_F(AsyncRevalidationDriverTest, DeferOnStart) {
+  raw_ptr_resource_throttle_->set_defer_request_on_will_start_request(true);
+
+  driver_->StartRequest();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(raw_ptr_request_->is_pending());
+  EXPECT_FALSE(async_revalidation_complete_called());
+}
+
+// Verifies that resuming a deferred request works. Assumes that DeferOnStart
+// passes.
+TEST_F(AsyncRevalidationDriverTest, ResumeDeferredRequestWorks) {
+  raw_ptr_resource_throttle_->set_defer_request_on_will_start_request(true);
+
+  driver_->StartRequest();
+  base::RunLoop().RunUntilIdle();
+
+  ResourceController* driver_as_resource_controller = driver_.get();
+  driver_as_resource_controller->Resume();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(async_revalidation_complete_called());
+}
+
+// Verifies that redirects are not followed.
+TEST_F(AsyncRevalidationDriverTest, RedirectsAreNotFollowed) {
+  SetUpAsyncRevalidationDriverWithRequestToUrl(
+      net::URLRequestTestJob::test_url_redirect_to_url_2());
+
+  driver_->StartRequest();
+  while (net::URLRequestTestJob::ProcessOnePendingMessage())
+    base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(last_status().is_success());
+  EXPECT_EQ(net::ERR_ABORTED, last_status().error());
+  EXPECT_TRUE(async_revalidation_complete_called());
+}
+
+// A mock URLRequestJob which simulates an SSL client auth request.
+class MockClientCertURLRequestJob : public net::URLRequestTestJob {
+ public:
+  MockClientCertURLRequestJob(net::URLRequest* request,
+                              net::NetworkDelegate* network_delegate)
+      : net::URLRequestTestJob(request, network_delegate, true),
+        weak_factory_(this) {}
+
+  // net::URLRequestTestJob implementation:
+  void Start() override {
+    scoped_refptr<net::SSLCertRequestInfo> cert_request_info(
+        new net::SSLCertRequestInfo);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(&MockClientCertURLRequestJob::NotifyCertificateRequested,
+                   weak_factory_.GetWeakPtr(), cert_request_info));
+  }
+
+  void ContinueWithCertificate(
+      net::X509Certificate* cert,
+      net::SSLPrivateKey* client_private_key) override {
+    ADD_FAILURE() << "Certificate supplied.";
+  }
+
+  void Kill() override {
+    weak_factory_.InvalidateWeakPtrs();
+    URLRequestJob::Kill();
+  }
+
+ private:
+  base::WeakPtrFactory<MockClientCertURLRequestJob> weak_factory_;
+};
+
+class AsyncRevalidationDriverClientCertTest
+    : public AsyncRevalidationDriverTest {
+ protected:
+  AsyncRevalidationDriverClientCertTest()
+      : AsyncRevalidationDriverTest(
+            BindCreateProtocolHandlerCallback<MockClientCertURLRequestJob>()) {}
+};
+
+// Test browser client that causes the test to fail if SelectClientCertificate()
+// is called. Automatically sets itself as the browser client when constructed
+// and restores the old browser client in the destructor.
+class ScopedDontSelectCertificateBrowserClient
+    : public TestContentBrowserClient {
+ public:
+  ScopedDontSelectCertificateBrowserClient() {
+    old_client_ = SetBrowserClientForTesting(this);
+  }
+
+  ~ScopedDontSelectCertificateBrowserClient() override {
+    SetBrowserClientForTesting(old_client_);
+  }
+
+  void SelectClientCertificate(
+      WebContents* web_contents,
+      net::SSLCertRequestInfo* cert_request_info,
+      scoped_ptr<ClientCertificateDelegate> delegate) override {
+    ADD_FAILURE() << "SelectClientCertificate was called.";
+  }
+
+ private:
+  ContentBrowserClient* old_client_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedDontSelectCertificateBrowserClient);
+};
+
+// Verifies that async revalidation requests do not attempt to provide client
+// certificates.
+TEST_F(AsyncRevalidationDriverClientCertTest, RequestRejected) {
+  // Ensure that SelectClientCertificate is not called during this test.
+  ScopedDontSelectCertificateBrowserClient test_client;
+
+  // Start the request and wait for it to pause.
+  driver_->StartRequest();
+
+  // Because TestBrowserThreadBundle only uses one real thread, this is
+  // sufficient to ensure that tasks posted to the "UI thread" have run.
+  base::RunLoop().RunUntilIdle();
+
+  // Check that the request aborted.
+  EXPECT_FALSE(last_status().is_success());
+  EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, last_status().error());
+  EXPECT_TRUE(async_revalidation_complete_called());
+}
+
+// A mock URLRequestJob which simulates an SSL certificate error.
+class MockSSLErrorURLRequestJob : public net::URLRequestTestJob {
+ public:
+  MockSSLErrorURLRequestJob(net::URLRequest* request,
+                            net::NetworkDelegate* network_delegate)
+      : net::URLRequestTestJob(request, network_delegate, true),
+        weak_factory_(this) {}
+
+  // net::URLRequestTestJob implementation:
+  void Start() override {
+    // This SSLInfo isn't really valid, but it is good enough for testing.
+    net::SSLInfo ssl_info;
+    ssl_info.SetCertError(net::ERR_CERT_DATE_INVALID);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(&MockSSLErrorURLRequestJob::NotifySSLCertificateError,
+                   weak_factory_.GetWeakPtr(), ssl_info, false));
+  }
+
+  void ContinueDespiteLastError() override {
+    ADD_FAILURE() << "ContinueDespiteLastError called.";
+  }
+
+ private:
+  base::WeakPtrFactory<MockSSLErrorURLRequestJob> weak_factory_;
+};
+
+class AsyncRevalidationDriverSSLErrorTest : public AsyncRevalidationDriverTest {
+ protected:
+  AsyncRevalidationDriverSSLErrorTest()
+      : AsyncRevalidationDriverTest(
+            BindCreateProtocolHandlerCallback<MockSSLErrorURLRequestJob>()) {}
+};
+
+// Verifies that async revalidation requests do not attempt to recover from SSL
+// certificate errors.
+TEST_F(AsyncRevalidationDriverSSLErrorTest, RequestWithSSLErrorRejected) {
+  // Start the request and wait for it to pause.
+  driver_->StartRequest();
+  base::RunLoop().RunUntilIdle();
+
+  // Check that the request has been aborted.
+  EXPECT_FALSE(last_status().is_success());
+  EXPECT_EQ(net::ERR_ABORTED, last_status().error());
+  EXPECT_TRUE(async_revalidation_complete_called());
+}
+
+// A URLRequestTestJob that sets |request_time| and |was_cached| on their
+// response_info, and causes the test to fail if Read() is called.
+class FromCacheURLRequestJob : public net::URLRequestTestJob {
+ public:
+  FromCacheURLRequestJob(net::URLRequest* request,
+                         net::NetworkDelegate* network_delegate)
+      : net::URLRequestTestJob(request, network_delegate, true) {}
+
+  void GetResponseInfo(net::HttpResponseInfo* info) override {
+    URLRequestTestJob::GetResponseInfo(info);
+    info->request_time = base::Time::Now();
+    info->was_cached = true;
+  }
+
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override {
+    ADD_FAILURE() << "ReadRawData() was called.";
+    return URLRequestTestJob::ReadRawData(buf, buf_size);
+  }
+
+ private:
+  ~FromCacheURLRequestJob() override {}
+
+  DISALLOW_COPY_AND_ASSIGN(FromCacheURLRequestJob);
+};
+
+class AsyncRevalidationDriverFromCacheTest
+    : public AsyncRevalidationDriverTest {
+ protected:
+  AsyncRevalidationDriverFromCacheTest()
+      : AsyncRevalidationDriverTest(
+            BindCreateProtocolHandlerCallback<FromCacheURLRequestJob>()) {}
+};
+
+TEST_F(AsyncRevalidationDriverFromCacheTest,
+       CacheNotReadOnSuccessfulRevalidation) {
+  driver_->StartRequest();
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(async_revalidation_complete_called());
+}
+
+}  // namespace
+}  // namespace content
diff --git a/content/browser/loader/async_revalidation_manager.cc b/content/browser/loader/async_revalidation_manager.cc
new file mode 100644
index 0000000..26a639d
--- /dev/null
+++ b/content/browser/loader/async_revalidation_manager.cc
@@ -0,0 +1,190 @@
+// 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/browser/loader/async_revalidation_manager.h"
+
+#include <tuple>
+#include <utility>
+
+#include "base/logging.h"
+#include "content/browser/loader/async_revalidation_driver.h"
+#include "content/browser/loader/resource_message_filter.h"
+#include "content/browser/loader/resource_request_info_impl.h"
+#include "content/browser/loader/resource_scheduler.h"
+#include "content/common/resource_messages.h"
+#include "content/public/browser/resource_throttle.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_transaction_factory.h"
+#include "net/http/http_util.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
+#include "url/gurl.h"
+
+namespace content {
+
+AsyncRevalidationManager::AsyncRevalidationKey::AsyncRevalidationKey(
+    const ResourceContext* resource_context,
+    const net::HttpCache* http_cache,
+    const GURL& url)
+    : resource_context(resource_context),
+      http_cache(http_cache),
+      url_key(net::HttpUtil::SpecForRequest(url)) {}
+
+AsyncRevalidationManager::AsyncRevalidationKey::AsyncRevalidationKey(
+    const ResourceContext* resource_context)
+    : resource_context(resource_context), http_cache(nullptr), url_key() {}
+
+AsyncRevalidationManager::AsyncRevalidationKey::~AsyncRevalidationKey() {}
+
+bool AsyncRevalidationManager::AsyncRevalidationKey::LessThan::operator()(
+    const AsyncRevalidationKey& lhs,
+    const AsyncRevalidationKey& rhs) const {
+  return std::tie(lhs.resource_context, lhs.http_cache, lhs.url_key) <
+         std::tie(rhs.resource_context, rhs.http_cache, rhs.url_key);
+}
+
+AsyncRevalidationManager::AsyncRevalidationManager() {}
+
+AsyncRevalidationManager::~AsyncRevalidationManager() {
+  DCHECK(in_progress_.empty());
+}
+
+void AsyncRevalidationManager::BeginAsyncRevalidation(
+    const net::URLRequest& for_request,
+    ResourceScheduler* scheduler) {
+  DCHECK_EQ(for_request.url_chain().size(), 1u);
+  const ResourceRequestInfoImpl* info =
+      ResourceRequestInfoImpl::ForRequest(&for_request);
+  DCHECK(info);
+  if (!info->filter()) {
+    // The child has gone away and we can no longer get ResourceContext and
+    // URLRequestContext to perform async revalidation.
+    // This can happen in the following cases, ordered from bad to not-so-bad
+    //
+    // 1. PlzNavigate (but enabling PlzNavigate automatically disables
+    //    stale-while-revalidate; see crbug.com/561609)
+    // 2. <link rel=prefetch> may read a stale cache entry without a
+    //    revalidation being performed if the original renderer goes away. This
+    //    is a lost optimisation opportunity.
+    //
+    // Not an issue:
+    // 1. Implicit downloads. This method is called before
+    //    MimeTypeResourceHandler calls set_is_download, so the renderer process
+    //    must still exist for the request not to have been canceled.
+    // 2. Explicit downloads (ie. started via "Save As"). These never use
+    //    stale-while-revalidate.
+    // 3. Non-PlzNavigate navigations between renderers. The old renderer
+    //    still exists when this method is called.
+    // 4. <a ping>, navigation.sendBeacon() and Content-Security-Policy reports
+    //    are POST requests, so they never use stale-while-revalidate.
+    //
+    // TODO(ricea): Resolve these lifetime issues. crbug.com/561591
+    return;
+  }
+
+  ResourceContext* resource_context = nullptr;
+  net::URLRequestContext* request_context = nullptr;
+
+  // The embedder of //content needs to ensure that the URLRequestContext object
+  // remains valid until after the ResourceContext object is destroyed.
+  info->filter()->GetContexts(info->GetResourceType(), info->GetOriginPID(),
+                              &resource_context, &request_context);
+
+  AsyncRevalidationKey async_revalidation_key(
+      resource_context, request_context->http_transaction_factory()->GetCache(),
+      for_request.url());
+  std::pair<AsyncRevalidationMap::iterator, bool> insert_result =
+      in_progress_.insert(AsyncRevalidationMap::value_type(
+          async_revalidation_key, scoped_ptr<AsyncRevalidationDriver>()));
+  if (!insert_result.second) {
+    // A matching async revalidation is already in progress for this cache; we
+    // don't need another one.
+    return;
+  }
+
+  net::HttpRequestHeaders headers;
+  headers.AddHeadersFromString(info->original_headers());
+
+  // Construct the request.
+  scoped_ptr<net::URLRequest> new_request = request_context->CreateRequest(
+      for_request.url(), net::MINIMUM_PRIORITY, nullptr);
+
+  new_request->set_method(for_request.method());
+  new_request->set_first_party_for_cookies(
+      for_request.first_party_for_cookies());
+  new_request->set_first_party_url_policy(for_request.first_party_url_policy());
+
+  new_request->SetReferrer(for_request.referrer());
+  new_request->set_referrer_policy(for_request.referrer_policy());
+
+  new_request->SetExtraRequestHeaders(headers);
+
+  // Remove LOAD_SUPPORT_ASYNC_REVALIDATION and LOAD_MAIN_FRAME flags.
+  // Also remove things which shouldn't have been there to begin with,
+  // and unrecognised flags.
+  int load_flags =
+      for_request.load_flags() &
+      (net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_BYPASS_PROXY |
+       net::LOAD_VERIFY_EV_CERT | net::LOAD_DO_NOT_SEND_COOKIES |
+       net::LOAD_DO_NOT_SEND_AUTH_DATA | net::LOAD_MAYBE_USER_GESTURE |
+       net::LOAD_DO_NOT_USE_EMBEDDED_IDENTITY);
+  new_request->SetLoadFlags(load_flags);
+
+  // These values would be -1 if the request was created by PlzNavigate. This
+  // would cause the async revalidation to start immediately.
+  // stale-while-revalidate is disabled when PlzNavigate is enabled
+  // to prevent this and other issues. See crbug.com/561610.
+  int child_id = info->GetChildID();
+  int route_id = info->GetRouteID();
+
+  scoped_ptr<ResourceThrottle> throttle =
+      scheduler->ScheduleRequest(child_id, route_id, false, new_request.get());
+
+  // AsyncRevalidationDriver does not outlive its entry in |in_progress_|,
+  // so the iterator and |this| may be passed to base::Bind directly.
+  insert_result.first->second.reset(new AsyncRevalidationDriver(
+      std::move(new_request), std::move(throttle),
+      base::Bind(&AsyncRevalidationManager::OnAsyncRevalidationComplete,
+                 base::Unretained(this), insert_result.first)));
+  insert_result.first->second->StartRequest();
+}
+
+void AsyncRevalidationManager::CancelAsyncRevalidationsForResourceContext(
+    ResourceContext* resource_context) {
+  // |resource_context| is the first part of the key, so elements to be
+  // cancelled are contiguous in the map.
+  AsyncRevalidationKey partial_key(resource_context);
+  for (auto it = in_progress_.lower_bound(partial_key);
+       it != in_progress_.end() &&
+       it->first.resource_context == resource_context;) {
+    it = in_progress_.erase(it);
+  }
+}
+
+bool AsyncRevalidationManager::QualifiesForAsyncRevalidation(
+    const ResourceHostMsg_Request& request) {
+  if (request.load_flags &
+      (net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE |
+       net::LOAD_VALIDATE_CACHE | net::LOAD_PREFERRING_CACHE |
+       net::LOAD_ONLY_FROM_CACHE | net::LOAD_IGNORE_LIMITS |
+       net::LOAD_PREFETCH)) {
+    return false;
+  }
+  if (request.method != "GET")
+    return false;
+  // A GET request should not have a body.
+  if (request.request_body.get())
+    return false;
+  if (!request.url.SchemeIsHTTPOrHTTPS())
+    return false;
+
+  return true;
+}
+
+void AsyncRevalidationManager::OnAsyncRevalidationComplete(
+    AsyncRevalidationMap::iterator it) {
+  in_progress_.erase(it);
+}
+
+}  // namespace content
diff --git a/content/browser/loader/async_revalidation_manager.h b/content/browser/loader/async_revalidation_manager.h
new file mode 100644
index 0000000..1070ea9c
--- /dev/null
+++ b/content/browser/loader/async_revalidation_manager.h
@@ -0,0 +1,107 @@
+// 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_BROWSER_LOADER_ASYNC_REVALIDATION_MANAGER_H_
+#define CONTENT_BROWSER_LOADER_ASYNC_REVALIDATION_MANAGER_H_
+
+#include <map>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+
+class GURL;
+struct ResourceHostMsg_Request;
+
+namespace net {
+class URLRequest;
+class HttpCache;
+}
+
+namespace content {
+
+class AsyncRevalidationDriver;
+class ResourceContext;
+class ResourceScheduler;
+
+// One instance of this class manages all active AsyncRevalidationDriver objects
+// for all profiles. It is created by and owned by
+// ResourceDispatcherHostImpl. It also implements the creation of a new
+// net::URLRequest and AsyncRevalidationDriver from an existing net::URLRequest
+// that has had the stale-while-revalidate algorithm applied to it.
+class AsyncRevalidationManager {
+ public:
+  AsyncRevalidationManager();
+  ~AsyncRevalidationManager();
+
+  // Starts an async revalidation by copying |for_request|. |scheduler| must
+  // remain valid until this object is destroyed.
+  void BeginAsyncRevalidation(const net::URLRequest& for_request,
+                              ResourceScheduler* scheduler);
+
+  // Cancel all pending async revalidations that use ResourceContext.
+  void CancelAsyncRevalidationsForResourceContext(
+      ResourceContext* resource_context);
+
+  static bool QualifiesForAsyncRevalidation(
+      const ResourceHostMsg_Request& request);
+
+ private:
+  // The key of the map of pending async revalidations. This key has a distinct
+  // value for every in-progress async revalidation. It is used to avoid
+  // duplicate async revalidations, and also to cancel affected async
+  // revalidations when a ResourceContext is removed.
+  //
+  // Request headers are intentionally not included in the key for simplicity,
+  // as they usually don't affect caching.
+  //
+  // TODO(ricea): Behave correctly in cases where the request headers do make a
+  // difference. crbug.com/567721
+  struct AsyncRevalidationKey {
+    AsyncRevalidationKey(const ResourceContext* resource_context,
+                         const net::HttpCache* http_cache,
+                         const GURL& url);
+
+    // Create a prefix key that is used to match all of the
+    // AsyncRevalidationDrivers using |resource_context| in the map.
+    explicit AsyncRevalidationKey(const ResourceContext* resource_context);
+
+    // The key for a map needs to be copyable.
+    AsyncRevalidationKey(const AsyncRevalidationKey& rhs) = default;
+    ~AsyncRevalidationKey();
+
+    // No operator= is generated because the struct members are immutable.
+
+    // |resource_context| and |http_cache| are never dereferenced; they are only
+    // compared to other values.
+    const ResourceContext* const resource_context;
+
+    // There are multiple independent HttpCache objects per ResourceContext.
+    const net::HttpCache* const http_cache;
+
+    // Derived from the url via net::HttpUtil::SpecForRequest().
+    const std::string url_key;
+
+    struct LessThan {
+      bool operator()(const AsyncRevalidationKey& lhs,
+                      const AsyncRevalidationKey& rhs) const;
+    };
+  };
+
+  using AsyncRevalidationMap = std::map<AsyncRevalidationKey,
+                                        scoped_ptr<AsyncRevalidationDriver>,
+                                        AsyncRevalidationKey::LessThan>;
+
+  void OnAsyncRevalidationComplete(AsyncRevalidationMap::iterator it);
+
+  // Map of AsyncRevalidationDriver instances that are currently in-flight:
+  // either waiting to be scheduled or active on the network.
+  AsyncRevalidationMap in_progress_;
+
+  DISALLOW_COPY_AND_ASSIGN(AsyncRevalidationManager);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_LOADER_ASYNC_REVALIDATION_MANAGER_H_
diff --git a/content/browser/loader/async_revalidation_manager_unittest.cc b/content/browser/loader/async_revalidation_manager_unittest.cc
new file mode 100644
index 0000000..d0ec2061
--- /dev/null
+++ b/content/browser/loader/async_revalidation_manager_unittest.cc
@@ -0,0 +1,554 @@
+// 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/browser/loader/async_revalidation_manager.h"
+
+#include <deque>
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/shared_memory_handle.h"
+#include "base/pickle.h"
+#include "base/run_loop.h"
+#include "base/strings/string_util.h"
+#include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/loader/resource_message_filter.h"
+#include "content/common/child_process_host_impl.h"
+#include "content/common/resource_messages.h"
+#include "content/public/browser/resource_context.h"
+#include "content/public/common/appcache_info.h"
+#include "content/public/common/process_type.h"
+#include "content/public/common/resource_type.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "ipc/ipc_param_traits.h"
+#include "net/base/load_flags.h"
+#include "net/base/network_delegate.h"
+#include "net/http/http_util.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_job.h"
+#include "net/url_request/url_request_job_factory.h"
+#include "net/url_request/url_request_test_job.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/page_transition_types.h"
+#include "url/gurl.h"
+#include "url/url_constants.h"
+
+namespace content {
+
+namespace {
+
+// This class is a variation on URLRequestTestJob that
+// returns ERR_IO_PENDING before every read, not just the first one.
+class URLRequestTestDelayedCompletionJob : public net::URLRequestTestJob {
+ public:
+  URLRequestTestDelayedCompletionJob(net::URLRequest* request,
+                                     net::NetworkDelegate* network_delegate,
+                                     const std::string& response_headers,
+                                     const std::string& response_data)
+      : net::URLRequestTestJob(request,
+                               network_delegate,
+                               response_headers,
+                               response_data,
+                               false) {}
+
+ private:
+  bool NextReadAsync() override { return true; }
+};
+
+// A URLRequestJob implementation which sets the |async_revalidation_required|
+// flag on the HttpResponseInfo object to true if the request has the
+// LOAD_SUPPORT_ASYNC_REVALIDATION flag.
+class AsyncRevalidationRequiredURLRequestTestJob
+    : public net::URLRequestTestJob {
+ public:
+  AsyncRevalidationRequiredURLRequestTestJob(
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate)
+      : URLRequestTestJob(request,
+                          network_delegate,
+                          net::URLRequestTestJob::test_headers(),
+                          std::string(),
+                          false) {}
+
+  void GetResponseInfo(net::HttpResponseInfo* info) override {
+    URLRequestTestJob::GetResponseInfo(info);
+    if (request()->load_flags() & net::LOAD_SUPPORT_ASYNC_REVALIDATION)
+      info->async_revalidation_required = true;
+  }
+};
+
+// A URLRequestJob implementation which serves a redirect and sets the
+// |async_revalidation_required| flag on the HttpResponseInfo object to true if
+// the request has the LOAD_SUPPORT_ASYNC_REVALIDATION flag.
+class RedirectAndRevalidateURLRequestTestJob : public net::URLRequestTestJob {
+ public:
+  RedirectAndRevalidateURLRequestTestJob(net::URLRequest* request,
+                                         net::NetworkDelegate* network_delegate)
+      : URLRequestTestJob(request,
+                          network_delegate,
+                          CreateRedirectHeaders(),
+                          std::string(),
+                          false) {}
+
+  void GetResponseInfo(net::HttpResponseInfo* info) override {
+    URLRequestTestJob::GetResponseInfo(info);
+    if (request()->load_flags() & net::LOAD_SUPPORT_ASYNC_REVALIDATION)
+      info->async_revalidation_required = true;
+  }
+
+ private:
+  static std::string CreateRedirectHeaders() {
+    static const char kRedirectHeaders[] =
+        "HTTP/1.1 302 MOVED\n"
+        "Location: http://example.com/async-revalidate/from-redirect\n"
+        "\n";
+    return std::string(kRedirectHeaders, arraysize(kRedirectHeaders) - 1);
+  }
+};
+
+class TestURLRequestJobFactory : public net::URLRequestJobFactory {
+ public:
+  TestURLRequestJobFactory() = default;
+
+  // Sets the contents of the response. |headers| should have "\n" as line
+  // breaks and end in "\n\n".
+  void SetResponse(const std::string& headers, const std::string& data) {
+    response_headers_ = headers;
+    response_data_ = data;
+  }
+
+  net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
+      const std::string& scheme,
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate) const override {
+    std::string path = request->url().path();
+    if (base::StartsWith(path, "/async-revalidate",
+                         base::CompareCase::SENSITIVE)) {
+      return new AsyncRevalidationRequiredURLRequestTestJob(request,
+                                                            network_delegate);
+    }
+    if (base::StartsWith(path, "/redirect", base::CompareCase::SENSITIVE)) {
+      return new RedirectAndRevalidateURLRequestTestJob(request,
+                                                        network_delegate);
+    }
+    return new URLRequestTestDelayedCompletionJob(
+        request, network_delegate, response_headers_, response_data_);
+  }
+
+  net::URLRequestJob* MaybeInterceptRedirect(
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate,
+      const GURL& location) const override {
+    return nullptr;
+  }
+
+  net::URLRequestJob* MaybeInterceptResponse(
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate) const override {
+    return nullptr;
+  }
+
+  bool IsHandledProtocol(const std::string& scheme) const override {
+    // If non-standard schemes need to be tested in future it will be
+    // necessary to call ChildProcessSecurityPolicyImpl::
+    // RegisterWebSafeScheme() for them.
+    return scheme == url::kHttpScheme || scheme == url::kHttpsScheme;
+  }
+
+  bool IsHandledURL(const GURL& url) const override {
+    return IsHandledProtocol(url.scheme());
+  }
+
+  bool IsSafeRedirectTarget(const GURL& location) const override {
+    return false;
+  }
+
+ private:
+  std::string response_headers_;
+  std::string response_data_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestURLRequestJobFactory);
+};
+
+// On Windows, ResourceMsg_SetDataBuffer supplies a HANDLE which is not
+// automatically released.
+//
+// See ResourceDispatcher::ReleaseResourcesInDataMessage.
+//
+// TODO(ricea): Maybe share this implementation with
+// resource_dispatcher_host_unittest.cc.
+void ReleaseHandlesInMessage(const IPC::Message& message) {
+  if (message.type() == ResourceMsg_SetDataBuffer::ID) {
+    base::PickleIterator iter(message);
+    int request_id;
+    CHECK(iter.ReadInt(&request_id));
+    base::SharedMemoryHandle shm_handle;
+    if (IPC::ParamTraits<base::SharedMemoryHandle>::Read(&message, &iter,
+                                                         &shm_handle)) {
+      if (base::SharedMemory::IsHandleValid(shm_handle))
+        base::SharedMemory::CloseHandle(shm_handle);
+    }
+  }
+}
+
+// This filter just deletes any messages that are sent through it.
+class BlackholeFilter : public ResourceMessageFilter {
+ public:
+  explicit BlackholeFilter(ResourceContext* resource_context)
+      : ResourceMessageFilter(
+            ChildProcessHostImpl::GenerateChildProcessUniqueId(),
+            PROCESS_TYPE_RENDERER,
+            nullptr,
+            nullptr,
+            nullptr,
+            nullptr,
+            nullptr,
+            base::Bind(&BlackholeFilter::GetContexts, base::Unretained(this))),
+        resource_context_(resource_context) {
+    ChildProcessSecurityPolicyImpl::GetInstance()->Add(child_id());
+  }
+
+  bool Send(IPC::Message* msg) override {
+    scoped_ptr<IPC::Message> take_ownership(msg);
+    ReleaseHandlesInMessage(*msg);
+    return true;
+  }
+
+ private:
+  ~BlackholeFilter() override {
+    ChildProcessSecurityPolicyImpl::GetInstance()->Remove(child_id());
+  }
+
+  void GetContexts(ResourceType resource_type,
+                   int origin_pid,
+                   ResourceContext** resource_context,
+                   net::URLRequestContext** request_context) {
+    *resource_context = resource_context_;
+    *request_context = resource_context_->GetRequestContext();
+  }
+
+  ResourceContext* resource_context_;
+
+  DISALLOW_COPY_AND_ASSIGN(BlackholeFilter);
+};
+
+ResourceHostMsg_Request CreateResourceRequest(const char* method,
+                                              ResourceType type,
+                                              const GURL& url) {
+  ResourceHostMsg_Request request;
+  request.method = std::string(method);
+  request.url = url;
+  request.first_party_for_cookies = url;  // Bypass third-party cookie blocking.
+  request.referrer_policy = blink::WebReferrerPolicyDefault;
+  request.load_flags = 0;
+  request.origin_pid = 0;
+  request.resource_type = type;
+  request.request_context = 0;
+  request.appcache_host_id = kAppCacheNoHostId;
+  request.download_to_file = false;
+  request.should_reset_appcache = false;
+  request.is_main_frame = true;
+  request.parent_is_main_frame = false;
+  request.parent_render_frame_id = -1;
+  request.transition_type = ui::PAGE_TRANSITION_LINK;
+  request.allow_download = true;
+  return request;
+}
+
+class AsyncRevalidationManagerTest : public ::testing::Test {
+ protected:
+  AsyncRevalidationManagerTest(
+      scoped_ptr<net::TestNetworkDelegate> network_delegate)
+      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
+        network_delegate_(std::move(network_delegate)) {
+    browser_context_.reset(new TestBrowserContext());
+    BrowserContext::EnsureResourceContextInitialized(browser_context_.get());
+    base::RunLoop().RunUntilIdle();
+    ResourceContext* resource_context = browser_context_->GetResourceContext();
+    filter_ = new BlackholeFilter(resource_context);
+    net::URLRequestContext* request_context =
+        resource_context->GetRequestContext();
+    job_factory_.reset(new TestURLRequestJobFactory);
+    request_context->set_job_factory(job_factory_.get());
+    request_context->set_network_delegate(network_delegate_.get());
+    host_.EnableStaleWhileRevalidateForTesting();
+  }
+
+  AsyncRevalidationManagerTest()
+      : AsyncRevalidationManagerTest(
+            make_scoped_ptr(new net::TestNetworkDelegate)) {}
+
+  void TearDown() override {
+    host_.CancelRequestsForProcess(filter_->child_id());
+    host_.Shutdown();
+    host_.CancelRequestsForContext(browser_context_->GetResourceContext());
+    browser_context_.reset();
+    base::RunLoop().RunUntilIdle();
+  }
+
+  void SetResponse(const std::string& headers, const std::string& data) {
+    job_factory_->SetResponse(headers, data);
+  }
+
+  // Creates a request using the current test object as the filter and
+  // SubResource as the resource type.
+  void MakeTestRequest(int render_view_id, int request_id, const GURL& url) {
+    ResourceHostMsg_Request request =
+        CreateResourceRequest("GET", RESOURCE_TYPE_SUB_RESOURCE, url);
+    ResourceHostMsg_RequestResource msg(render_view_id, request_id, request);
+    host_.OnMessageReceived(msg, filter_.get());
+    base::RunLoop().RunUntilIdle();
+  }
+
+  void EnsureSchemeIsAllowed(const std::string& scheme) {
+    ChildProcessSecurityPolicyImpl* policy =
+        ChildProcessSecurityPolicyImpl::GetInstance();
+    if (!policy->IsWebSafeScheme(scheme))
+      policy->RegisterWebSafeScheme(scheme);
+  }
+
+  content::TestBrowserThreadBundle thread_bundle_;
+  scoped_ptr<TestBrowserContext> browser_context_;
+  scoped_ptr<TestURLRequestJobFactory> job_factory_;
+  scoped_refptr<BlackholeFilter> filter_;
+  scoped_ptr<net::TestNetworkDelegate> network_delegate_;
+  ResourceDispatcherHostImpl host_;
+};
+
+TEST_F(AsyncRevalidationManagerTest, SupportsAsyncRevalidation) {
+  SetResponse(net::URLRequestTestJob::test_headers(), "delay complete");
+  MakeTestRequest(0, 1, GURL("http://example.com/baz"));
+
+  net::URLRequest* url_request(
+      host_.GetURLRequest(GlobalRequestID(filter_->child_id(), 1)));
+  ASSERT_TRUE(url_request);
+
+  EXPECT_TRUE(url_request->load_flags() & net::LOAD_SUPPORT_ASYNC_REVALIDATION);
+}
+
+TEST_F(AsyncRevalidationManagerTest, AsyncRevalidationNotSupportedForPOST) {
+  SetResponse(net::URLRequestTestJob::test_headers(), "delay complete");
+  // Create POST request.
+  ResourceHostMsg_Request request = CreateResourceRequest(
+      "POST", RESOURCE_TYPE_SUB_RESOURCE, GURL("http://example.com/baz.php"));
+  ResourceHostMsg_RequestResource msg(0, 1, request);
+  host_.OnMessageReceived(msg, filter_.get());
+  base::RunLoop().RunUntilIdle();
+
+  net::URLRequest* url_request(
+      host_.GetURLRequest(GlobalRequestID(filter_->child_id(), 1)));
+  ASSERT_TRUE(url_request);
+
+  EXPECT_FALSE(url_request->load_flags() &
+               net::LOAD_SUPPORT_ASYNC_REVALIDATION);
+}
+
+TEST_F(AsyncRevalidationManagerTest,
+       AsyncRevalidationNotSupportedAfterRedirect) {
+  static const char kRedirectHeaders[] =
+      "HTTP/1.1 302 MOVED\n"
+      "Location: http://example.com/var\n"
+      "\n";
+  SetResponse(kRedirectHeaders, "");
+
+  MakeTestRequest(0, 1, GURL("http://example.com/baz"));
+
+  net::URLRequest* url_request(
+      host_.GetURLRequest(GlobalRequestID(filter_->child_id(), 1)));
+  ASSERT_TRUE(url_request);
+
+  EXPECT_FALSE(url_request->load_flags() &
+               net::LOAD_SUPPORT_ASYNC_REVALIDATION);
+}
+
+// A NetworkDelegate that records the URLRequests as they are created.
+class URLRequestRecordingNetworkDelegate : public net::TestNetworkDelegate {
+ public:
+  URLRequestRecordingNetworkDelegate() : requests_() {}
+
+  net::URLRequest* NextRequest() {
+    EXPECT_FALSE(requests_.empty());
+    if (requests_.empty())
+      return nullptr;
+    net::URLRequest* request = requests_.front();
+    EXPECT_TRUE(request);
+    requests_.pop_front();
+    return request;
+  }
+
+  bool NextRequestWasDestroyed() {
+    net::URLRequest* request = requests_.front();
+    requests_.pop_front();
+    return request == nullptr;
+  }
+
+  bool IsEmpty() const { return requests_.empty(); }
+
+  int OnBeforeURLRequest(net::URLRequest* request,
+                         const net::CompletionCallback& callback,
+                         GURL* new_url) override {
+    requests_.push_back(request);
+    return TestNetworkDelegate::OnBeforeURLRequest(request, callback, new_url);
+  }
+
+  void OnURLRequestDestroyed(net::URLRequest* request) override {
+    for (auto& recorded_request : requests_) {
+      if (recorded_request == request)
+        recorded_request = nullptr;
+    }
+    net::TestNetworkDelegate::OnURLRequestDestroyed(request);
+  }
+
+ private:
+  std::deque<net::URLRequest*> requests_;
+
+  DISALLOW_COPY_AND_ASSIGN(URLRequestRecordingNetworkDelegate);
+};
+
+class AsyncRevalidationManagerRecordingTest
+    : public AsyncRevalidationManagerTest {
+ public:
+  AsyncRevalidationManagerRecordingTest()
+      : AsyncRevalidationManagerTest(
+            make_scoped_ptr(new URLRequestRecordingNetworkDelegate)) {}
+
+  void TearDown() override {
+    EXPECT_TRUE(IsEmpty());
+    AsyncRevalidationManagerTest::TearDown();
+  }
+
+  URLRequestRecordingNetworkDelegate* recording_network_delegate() const {
+    return static_cast<URLRequestRecordingNetworkDelegate*>(
+        network_delegate_.get());
+  }
+
+  bool NextRequestWasDestroyed() {
+    return recording_network_delegate()->NextRequestWasDestroyed();
+  }
+
+  net::URLRequest* NextRequest() {
+    return recording_network_delegate()->NextRequest();
+  }
+
+  bool IsEmpty() const { return recording_network_delegate()->IsEmpty(); }
+};
+
+// Verify that an async revalidation is actually created when needed.
+TEST_F(AsyncRevalidationManagerRecordingTest, Issued) {
+  // Create the original request.
+  MakeTestRequest(0, 1, GURL("http://example.com/async-revalidate"));
+
+  net::URLRequest* initial_request = NextRequest();
+  ASSERT_TRUE(initial_request);
+  EXPECT_TRUE(initial_request->load_flags() &
+              net::LOAD_SUPPORT_ASYNC_REVALIDATION);
+
+  net::URLRequest* async_request = NextRequest();
+  ASSERT_TRUE(async_request);
+}
+
+// Verify the the URL of the async revalidation matches the original request.
+TEST_F(AsyncRevalidationManagerRecordingTest, URLMatches) {
+  // Create the original request.
+  MakeTestRequest(0, 1, GURL("http://example.com/async-revalidate/u"));
+
+  // Discard the original request.
+  NextRequest();
+
+  net::URLRequest* async_request = NextRequest();
+  ASSERT_TRUE(async_request);
+  EXPECT_EQ(GURL("http://example.com/async-revalidate/u"),
+            async_request->url());
+}
+
+TEST_F(AsyncRevalidationManagerRecordingTest,
+       AsyncRevalidationsDoNotSupportAsyncRevalidation) {
+  // Create the original request.
+  MakeTestRequest(0, 1, GURL("http://example.com/async-revalidate"));
+
+  // Discard the original request.
+  NextRequest();
+
+  // Get the async revalidation request.
+  net::URLRequest* async_request = NextRequest();
+  ASSERT_TRUE(async_request);
+  EXPECT_FALSE(async_request->load_flags() &
+               net::LOAD_SUPPORT_ASYNC_REVALIDATION);
+}
+
+TEST_F(AsyncRevalidationManagerRecordingTest, AsyncRevalidationsNotDuplicated) {
+  // Create the original request.
+  MakeTestRequest(0, 1, GURL("http://example.com/async-revalidate"));
+
+  // Discard the original request.
+  NextRequest();
+
+  // Get the async revalidation request.
+  net::URLRequest* async_request = NextRequest();
+  EXPECT_TRUE(async_request);
+
+  // Start a second request to the same URL.
+  MakeTestRequest(0, 2, GURL("http://example.com/async-revalidate"));
+
+  // Discard the second request.
+  NextRequest();
+
+  // There should not be another async revalidation request.
+  EXPECT_TRUE(IsEmpty());
+}
+
+// Async revalidation to different URLs should not be treated as duplicates.
+TEST_F(AsyncRevalidationManagerRecordingTest,
+       AsyncRevalidationsToSeparateURLsAreSeparate) {
+  // Create two requests to two URLs.
+  MakeTestRequest(0, 1, GURL("http://example.com/async-revalidate"));
+  MakeTestRequest(0, 2, GURL("http://example.com/async-revalidate2"));
+
+  net::URLRequest* initial_request = NextRequest();
+  ASSERT_TRUE(initial_request);
+  net::URLRequest* initial_async_revalidation = NextRequest();
+  ASSERT_TRUE(initial_async_revalidation);
+  net::URLRequest* second_request = NextRequest();
+  ASSERT_TRUE(second_request);
+  net::URLRequest* second_async_revalidation = NextRequest();
+  ASSERT_TRUE(second_async_revalidation);
+
+  EXPECT_EQ("http://example.com/async-revalidate",
+            initial_request->url().spec());
+  EXPECT_EQ("http://example.com/async-revalidate",
+            initial_async_revalidation->url().spec());
+  EXPECT_EQ("http://example.com/async-revalidate2",
+            second_request->url().spec());
+  EXPECT_EQ("http://example.com/async-revalidate2",
+            second_async_revalidation->url().spec());
+}
+
+// Nothing after the first redirect leg has stale-while-revalidate applied.
+// TODO(ricea): s-w-r should work with redirects. Change this test when it does.
+TEST_F(AsyncRevalidationManagerRecordingTest, NoSWRAfterFirstRedirectLeg) {
+  MakeTestRequest(0, 1, GURL("http://example.com/redirect"));
+
+  net::URLRequest* initial_request = NextRequest();
+  EXPECT_TRUE(initial_request);
+
+  EXPECT_FALSE(initial_request->load_flags() &
+               net::LOAD_SUPPORT_ASYNC_REVALIDATION);
+
+  // An async revalidation happens for the redirect. It has no body, so it has
+  // already completed.
+  EXPECT_TRUE(NextRequestWasDestroyed());
+
+  // But no others.
+  EXPECT_TRUE(IsEmpty());
+}
+
+}  // namespace
+
+}  // namespace content
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index c2504a9..ad2d5b4f 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -19,10 +19,12 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/shared_memory.h"
 #include "base/message_loop/message_loop.h"
+#include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/stl_util.h"
+#include "base/strings/string_util.h"
 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "base/time/time.h"
 #include "content/browser/appcache/appcache_interceptor.h"
@@ -37,6 +39,7 @@
 #include "content/browser/frame_host/navigation_request_info.h"
 #include "content/browser/frame_host/navigator.h"
 #include "content/browser/loader/async_resource_handler.h"
+#include "content/browser/loader/async_revalidation_manager.h"
 #include "content/browser/loader/cross_site_resource_handler.h"
 #include "content/browser/loader/detachable_resource_handler.h"
 #include "content/browser/loader/mime_type_resource_handler.h"
@@ -483,6 +486,24 @@
                                      base::Unretained(this)));
 
   update_load_states_timer_.reset(new base::RepeatingTimer());
+
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  // This needs to be called to mark the trial as active, even if the result
+  // isn't used.
+  std::string stale_while_revalidate_trial_group =
+      base::FieldTrialList::FindFullName("StaleWhileRevalidate");
+  // stale-while-revalidate currently doesn't work with browser-side navigation.
+  // Only enable stale-while-revalidate if browser navigation is not enabled.
+  //
+  // TODO(ricea): Make stale-while-revalidate and browser-side navigation work
+  // together. Or disable stale-while-revalidate completely before browser-side
+  // navigation becomes the default. crbug.com/561610
+  if (!command_line->HasSwitch(switches::kEnableBrowserSideNavigation) &&
+      (base::StartsWith(stale_while_revalidate_trial_group, "Enabled",
+                        base::CompareCase::SENSITIVE) ||
+       command_line->HasSwitch(switches::kEnableStaleWhileRevalidate))) {
+    async_revalidation_manager_.reset(new AsyncRevalidationManager);
+  }
 }
 
 ResourceDispatcherHostImpl::~ResourceDispatcherHostImpl() {
@@ -588,6 +609,13 @@
 
   loaders_to_cancel.clear();
 
+  if (async_revalidation_manager_) {
+    // Cancelling async revalidations should not result in the creation of new
+    // requests. Do it before the CHECKs to ensure this does not happen.
+    async_revalidation_manager_->CancelAsyncRevalidationsForResourceContext(
+        context);
+  }
+
   // Validate that no more requests for this context were added.
   for (LoaderMap::const_iterator i = pending_loaders_.begin();
        i != pending_loaders_.end(); ++i) {
@@ -836,6 +864,28 @@
   if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_host))
     return;
 
+  net::URLRequest* request = loader->request();
+  if (request->response_info().async_revalidation_required) {
+    // Async revalidation is only supported for the first redirect leg.
+    DCHECK_EQ(request->url_chain().size(), 1u);
+    DCHECK(async_revalidation_manager_);
+
+    async_revalidation_manager_->BeginAsyncRevalidation(*request,
+                                                        scheduler_.get());
+  }
+
+  // Remove the LOAD_SUPPORT_ASYNC_REVALIDATION flag if it is present.
+  // It is difficult to create a URLRequest with the correct flags and headers
+  // for redirect legs other than the first one. Since stale-while-revalidate in
+  // combination with redirects isn't needed for experimental use, punt on it
+  // for now.
+  // TODO(ricea): Fix this before launching the feature.
+  if (request->load_flags() & net::LOAD_SUPPORT_ASYNC_REVALIDATION) {
+    int new_load_flags =
+        request->load_flags() & ~net::LOAD_SUPPORT_ASYNC_REVALIDATION;
+    request->SetLoadFlags(new_load_flags);
+  }
+
   // Don't notify WebContents observers for requests known to be
   // downloads; they aren't really associated with the Webcontents.
   // Note that not all downloads are known before content sniffing.
@@ -864,6 +914,12 @@
         info->GetChildID(), info->GetRouteID());
   }
 
+  if (request->response_info().async_revalidation_required) {
+    DCHECK(async_revalidation_manager_);
+    async_revalidation_manager_->BeginAsyncRevalidation(*request,
+                                                        scheduler_.get());
+  }
+
   int render_process_id, render_frame_host;
   if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_host))
     return;
@@ -1323,6 +1379,13 @@
     load_flags |= net::LOAD_DO_NOT_USE_EMBEDDED_IDENTITY;
   }
 
+  bool support_async_revalidation =
+      !is_sync_load && async_revalidation_manager_ &&
+      AsyncRevalidationManager::QualifiesForAsyncRevalidation(request_data);
+
+  if (support_async_revalidation)
+    load_flags |= net::LOAD_SUPPORT_ASYNC_REVALIDATION;
+
   // Sync loads should have maximum priority and should be the only
   // requets that have the ignore limits flag set.
   if (is_sync_load) {
@@ -1359,7 +1422,8 @@
       report_raw_headers,
       !is_sync_load,
       IsUsingLoFi(request_data.lofi_state, delegate_,
-                  *new_request, resource_context));
+                  *new_request, resource_context),
+      support_async_revalidation ? request_data.headers : std::string());
   // Request takes ownership.
   extra_info->AssociateWithRequest(new_request.get());
 
@@ -1660,7 +1724,8 @@
       base::WeakPtr<ResourceMessageFilter>(),  // filter
       false,                                   // report_raw_headers
       true,                                    // is_async
-      false);                                  // is_using_lofi
+      false,                                   // is_using_lofi
+      std::string());                          // original_headers
 }
 
 void ResourceDispatcherHostImpl::OnRenderViewHostCreated(int child_id,
@@ -1709,6 +1774,7 @@
 // This function is only used for saving feature.
 void ResourceDispatcherHostImpl::BeginSaveFile(const GURL& url,
                                                const Referrer& referrer,
+                                               int save_item_id,
                                                int save_package_id,
                                                int child_id,
                                                int render_view_route_id,
@@ -1752,8 +1818,8 @@
   extra_info->AssociateWithRequest(request.get());  // Request takes ownership.
 
   scoped_ptr<ResourceHandler> handler(new SaveFileResourceHandler(
-      request.get(), save_package_id, child_id, render_frame_route_id, url,
-      save_file_manager_.get()));
+      request.get(), save_item_id, save_package_id, child_id,
+      render_frame_route_id, url, save_file_manager_.get()));
 
   BeginRequestInternal(request.Pass(), handler.Pass());
 }
@@ -2100,9 +2166,15 @@
       blink::WebPageVisibilityStateVisible, resource_context,
       base::WeakPtr<ResourceMessageFilter>(),  // filter
       false,  // request_data.report_raw_headers
-      true,
+      true,   // is_async
       IsUsingLoFi(info.common_params.lofi_state, delegate_,
-                  *new_request, resource_context));
+                  *new_request, resource_context),
+      // The original_headers field is for stale-while-revalidate but the
+      // feature doesn't work with PlzNavigate, so it's just a placeholder
+      // here.
+      // TODO(ricea): Make the feature work with stale-while-revalidate
+      // and clean this up.
+      std::string());  // original_headers
   // Request takes ownership.
   extra_info->AssociateWithRequest(new_request.get());
 
@@ -2140,6 +2212,11 @@
   BeginRequestInternal(new_request.Pass(), handler.Pass());
 }
 
+void ResourceDispatcherHostImpl::EnableStaleWhileRevalidateForTesting() {
+  if (!async_revalidation_manager_)
+    async_revalidation_manager_.reset(new AsyncRevalidationManager);
+}
+
 // static
 int ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(
     net::URLRequest* request) {
diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h
index d9105fa..cb2e89a 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.h
+++ b/content/browser/loader/resource_dispatcher_host_impl.h
@@ -60,6 +60,7 @@
 
 namespace content {
 class AppCacheService;
+class AsyncRevalidationManager;
 class NavigationURLLoaderImplCore;
 class ResourceContext;
 class ResourceDispatcherHostDelegate;
@@ -128,6 +129,7 @@
   // request from the renderer or another child process).
   void BeginSaveFile(const GURL& url,
                      const Referrer& referrer,
+                     int save_item_id,
                      int save_package_id,
                      int child_id,
                      int render_view_route_id,
@@ -281,6 +283,10 @@
       NavigationURLLoaderImplCore* loader,
       ServiceWorkerNavigationHandleCore* service_worker_handle_core);
 
+  // Turns on stale-while-revalidate support, regardless of command-line flags
+  // or experiment status. For unit tests only.
+  void EnableStaleWhileRevalidateForTesting();
+
  private:
   friend class ResourceDispatcherHostTest;
 
@@ -589,6 +595,10 @@
 
   bool allow_cross_origin_auth_prompt_;
 
+  // AsyncRevalidationManager is non-NULL if and only if
+  // stale-while-revalidate is enabled.
+  scoped_ptr<AsyncRevalidationManager> async_revalidation_manager_;
+
   // http://crbug.com/90971 - Assists in tracking down use-after-frees on
   // shutdown.
   std::set<const ResourceContext*> active_resource_contexts_;
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index 6238b25..e8a404f 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -115,6 +115,9 @@
     GetSSLStatusForRequest(request->url(), request->ssl_info(),
                            info->GetChildID(), &ssl_status);
     response->head.security_info = SerializeSecurityInfo(ssl_status);
+    response->head.has_major_certificate_errors =
+        net::IsCertStatusError(ssl_status.cert_status) &&
+        !net::IsCertStatusMinorError(ssl_status.cert_status);
   } else {
     // We should not have any SSL state.
     DCHECK(!request->ssl_info().cert_status);
diff --git a/content/browser/loader/resource_loader_unittest.cc b/content/browser/loader/resource_loader_unittest.cc
index 9f669e4..1b8bb4538 100644
--- a/content/browser/loader/resource_loader_unittest.cc
+++ b/content/browser/loader/resource_loader_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
@@ -147,7 +148,8 @@
  public:
   MockClientCertURLRequestJob(net::URLRequest* request,
                               net::NetworkDelegate* network_delegate)
-      : net::URLRequestTestJob(request, network_delegate) {}
+      : net::URLRequestTestJob(request, network_delegate),
+        weak_factory_(this) {}
 
   static std::vector<std::string> test_authorities() {
     return std::vector<std::string>(1, "dummy");
@@ -161,7 +163,7 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&MockClientCertURLRequestJob::NotifyCertificateRequested,
-                   this, cert_request_info));
+                   weak_factory_.GetWeakPtr(), cert_request_info));
   }
 
   void ContinueWithCertificate(net::X509Certificate* cert,
@@ -172,6 +174,8 @@
  private:
   ~MockClientCertURLRequestJob() override {}
 
+  base::WeakPtrFactory<MockClientCertURLRequestJob> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(MockClientCertURLRequestJob);
 };
 
diff --git a/content/browser/loader/resource_request_info_impl.cc b/content/browser/loader/resource_request_info_impl.cc
index c2d4477..92a3494 100644
--- a/content/browser/loader/resource_request_info_impl.cc
+++ b/content/browser/loader/resource_request_info_impl.cc
@@ -89,7 +89,8 @@
           base::WeakPtr<ResourceMessageFilter>(),  // filter
           false,                             // report_raw_headers
           is_async,                          // is_async
-          is_using_lofi);                    // is_using_lofi
+          is_using_lofi,                     // is_using_lofi
+          std::string());                    // original_headers
   info->AssociateWithRequest(request);
 }
 
@@ -149,7 +150,8 @@
     base::WeakPtr<ResourceMessageFilter> filter,
     bool report_raw_headers,
     bool is_async,
-    bool is_using_lofi)
+    bool is_using_lofi,
+    const std::string& original_headers)
     : cross_site_handler_(NULL),
       detachable_handler_(NULL),
       process_type_(process_type),
@@ -181,7 +183,8 @@
       filter_(filter),
       report_raw_headers_(report_raw_headers),
       is_async_(is_async),
-      is_using_lofi_(is_using_lofi) {
+      is_using_lofi_(is_using_lofi),
+      original_headers_(original_headers) {
 }
 
 ResourceRequestInfoImpl::~ResourceRequestInfoImpl() {
diff --git a/content/browser/loader/resource_request_info_impl.h b/content/browser/loader/resource_request_info_impl.h
index 114c238..827a3f0a6 100644
--- a/content/browser/loader/resource_request_info_impl.h
+++ b/content/browser/loader/resource_request_info_impl.h
@@ -66,7 +66,8 @@
       base::WeakPtr<ResourceMessageFilter> filter,
       bool report_raw_headers,
       bool is_async,
-      bool is_using_lofi);
+      bool is_using_lofi,
+      const std::string& original_headers);
   ~ResourceRequestInfoImpl() override;
 
   // ResourceRequestInfo implementation:
@@ -183,6 +184,7 @@
   void set_do_not_prompt_for_login(bool do_not_prompt) {
     do_not_prompt_for_login_ = do_not_prompt;
   }
+  const std::string& original_headers() const { return original_headers_; }
 
  private:
   FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
@@ -225,6 +227,7 @@
   bool report_raw_headers_;
   bool is_async_;
   bool is_using_lofi_;
+  const std::string original_headers_;
 
   DISALLOW_COPY_AND_ASSIGN(ResourceRequestInfoImpl);
 };
diff --git a/content/browser/media/capture/web_contents_video_capture_device.cc b/content/browser/media/capture/web_contents_video_capture_device.cc
index 3a432d85..d69a0bc6 100644
--- a/content/browser/media/capture/web_contents_video_capture_device.cc
+++ b/content/browser/media/capture/web_contents_video_capture_device.cc
@@ -68,6 +68,7 @@
 #include "content/browser/media/capture/cursor_renderer.h"
 #include "content/browser/media/capture/web_contents_capture_util.h"
 #include "content/browser/media/capture/web_contents_tracker.h"
+#include "content/browser/media/capture/window_activity_tracker.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
 #include "content/public/browser/browser_thread.h"
@@ -77,6 +78,7 @@
 #include "content/public/browser/web_contents.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/video_capture_types.h"
+#include "media/base/video_frame_metadata.h"
 #include "media/base/video_util.h"
 #include "media/capture/content/screen_capture_device_core.h"
 #include "media/capture/content/thread_safe_capture_oracle.h"
@@ -90,12 +92,21 @@
 
 #if defined(USE_AURA)
 #include "content/browser/media/capture/cursor_renderer_aura.h"
+#include "content/browser/media/capture/window_activity_tracker_aura.h"
 #endif
 
 namespace content {
 
 namespace {
 
+enum InteractiveModeSettings {
+  // Minimum amount of time for which there should be no animation detected
+  // to consider interactive mode being active. This is to prevent very brief
+  // periods of animated content not being detected (due to CPU fluctations for
+  // example) from causing a flip-flop on interactive mode.
+  kMinPeriodNoAnimationMillis = 3000
+};
+
 void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread,
                           const base::Closure& callback) {
   render_thread.reset();
@@ -128,11 +139,13 @@
   FrameSubscriber(media::VideoCaptureOracle::Event event_type,
                   const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle,
                   VideoFrameDeliveryLog* delivery_log,
-                  base::WeakPtr<content::CursorRenderer> cursor_renderer)
+                  base::WeakPtr<content::CursorRenderer> cursor_renderer,
+                  base::WeakPtr<content::WindowActivityTracker> tracker)
       : event_type_(event_type),
         oracle_proxy_(oracle),
         delivery_log_(delivery_log),
         cursor_renderer_(cursor_renderer),
+        window_activity_tracker_(tracker),
         weak_ptr_factory_(this) {}
 
   bool ShouldCaptureFrame(
@@ -151,6 +164,8 @@
       const gfx::Rect& region_in_frame,
       bool success);
 
+  bool IsUserInteractingWithContent();
+
  private:
   const media::VideoCaptureOracle::Event event_type_;
   scoped_refptr<media::ThreadSafeCaptureOracle> oracle_proxy_;
@@ -158,6 +173,9 @@
   // We need a weak pointer since FrameSubscriber is owned externally and
   // may outlive the cursor renderer.
   base::WeakPtr<CursorRenderer> cursor_renderer_;
+  // We need a weak pointer since FrameSubscriber is owned externally and
+  // may outlive the ui activity tracker.
+  base::WeakPtr<WindowActivityTracker> window_activity_tracker_;
   base::WeakPtrFactory<FrameSubscriber> weak_ptr_factory_;
 };
 
@@ -210,6 +228,10 @@
   // capture is completed.
   scoped_ptr<content::CursorRenderer> cursor_renderer_;
 
+  // Responsible for tracking the UI events and making a decision on whether
+  // user is actively interacting with content.
+  scoped_ptr<content::WindowActivityTracker> window_activity_tracker_;
+
   DISALLOW_COPY_AND_ASSIGN(ContentCaptureSubscription);
 };
 
@@ -365,14 +387,38 @@
     // experience in any particular scenarios. Doing it prior to capture may
     // require evaluating region_in_frame in this file.
     if (frame_subscriber_ && frame_subscriber_->cursor_renderer_) {
-      if (frame_subscriber_->cursor_renderer_->SnapshotCursorState(
-              region_in_frame))
-        frame_subscriber_->cursor_renderer_->RenderOnVideoFrame(frame);
+      CursorRenderer* cursor_renderer =
+          frame_subscriber_->cursor_renderer_.get();
+      if (cursor_renderer->SnapshotCursorState(region_in_frame))
+        cursor_renderer->RenderOnVideoFrame(frame);
+      frame->metadata()->SetBoolean(
+          media::VideoFrameMetadata::INTERACTIVE_CONTENT,
+          frame_subscriber_->IsUserInteractingWithContent());
     }
   }
   capture_frame_cb.Run(frame, timestamp, success);
 }
 
+bool FrameSubscriber::IsUserInteractingWithContent() {
+  bool interactive_mode = false;
+  bool ui_activity = false;
+  if (window_activity_tracker_.get()) {
+    ui_activity = window_activity_tracker_->IsUiInteractionActive();
+  }
+  if (cursor_renderer_.get()) {
+    bool animation_active =
+        (base::TimeTicks::Now() -
+         oracle_proxy_->last_time_animation_was_detected()) <
+        base::TimeDelta::FromMilliseconds(kMinPeriodNoAnimationMillis);
+    if (ui_activity && !animation_active) {
+      interactive_mode = true;
+    } else if (animation_active) {
+      window_activity_tracker_->Reset();
+    }
+  }
+  return interactive_mode;
+}
+
 ContentCaptureSubscription::ContentCaptureSubscription(
     const RenderWidgetHost& source,
     const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy,
@@ -387,25 +433,36 @@
   RenderWidgetHostView* const view = source.GetView();
 // TODO(isheriff): Cursor resources currently only available on linux. Remove
 // this once we add the necessary resources for windows.
+// https://crbug.com/554280 https://crbug.com/549182
 #if defined(USE_AURA) && defined(OS_LINUX)
-  if (view)
+  if (view) {
     cursor_renderer_.reset(
         new content::CursorRendererAura(view->GetNativeView()));
+  }
+#endif
+// TODO(isheriff): Needs implementation on non-aura platforms.
+// https://crbug.com/567735
+#if defined(USE_AURA)
+  window_activity_tracker_.reset(
+      new content::WindowActivityTrackerAura(view->GetNativeView()));
 #endif
   timer_subscriber_.reset(new FrameSubscriber(
       media::VideoCaptureOracle::kTimerPoll, oracle_proxy, &delivery_log_,
       cursor_renderer_ ? cursor_renderer_->GetWeakPtr()
-                       : base::WeakPtr<CursorRenderer>()));
+                       : base::WeakPtr<CursorRenderer>(),
+      window_activity_tracker_ ? window_activity_tracker_->GetWeakPtr()
+                               : base::WeakPtr<WindowActivityTracker>()));
 
   // Subscribe to compositor updates. These will be serviced directly by the
   // oracle.
   if (view) {
     scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber(
-        new FrameSubscriber(media::VideoCaptureOracle::kCompositorUpdate,
-                            oracle_proxy, &delivery_log_,
-                            cursor_renderer_
-                                ? cursor_renderer_->GetWeakPtr()
-                                : base::WeakPtr<CursorRenderer>()));
+        new FrameSubscriber(
+            media::VideoCaptureOracle::kCompositorUpdate, oracle_proxy,
+            &delivery_log_, cursor_renderer_ ? cursor_renderer_->GetWeakPtr()
+                                             : base::WeakPtr<CursorRenderer>(),
+            window_activity_tracker_ ? window_activity_tracker_->GetWeakPtr()
+                                     : base::WeakPtr<WindowActivityTracker>()));
     view->BeginFrameSubscription(subscriber.Pass());
   }
 
diff --git a/content/browser/media/capture/window_activity_tracker.h b/content/browser/media/capture/window_activity_tracker.h
new file mode 100644
index 0000000..5fd9f0b
--- /dev/null
+++ b/content/browser/media/capture/window_activity_tracker.h
@@ -0,0 +1,32 @@
+// 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 CONTENT_BROWSER_MEDIA_CAPTURE_WINDOW_ACTIVITY_TRACKER_H_
+#define CONTENT_BROWSER_MEDIA_CAPTURE_WINDOW_ACTIVITY_TRACKER_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+// WindowActivityTracker is an interface that can be implememented to report
+// whether the user is actively interacting with UI.
+class CONTENT_EXPORT WindowActivityTracker {
+ public:
+  virtual ~WindowActivityTracker() {}
+
+  // Returns true if UI interaction is active.
+  virtual bool IsUiInteractionActive() const = 0;
+
+  // Resets any previous UI activity tracked.
+  virtual void Reset() = 0;
+
+  // Returns a weak pointer.
+  virtual base::WeakPtr<WindowActivityTracker> GetWeakPtr() = 0;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_MEDIA_CAPTURE_WINDOW_ACTIVITY_TRACKER_H_
diff --git a/content/browser/media/capture/window_activity_tracker_aura.cc b/content/browser/media/capture/window_activity_tracker_aura.cc
new file mode 100644
index 0000000..e56e4a3f
--- /dev/null
+++ b/content/browser/media/capture/window_activity_tracker_aura.cc
@@ -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.
+
+#include "content/browser/media/capture/window_activity_tracker_aura.h"
+
+#include "base/logging.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/events/event_utils.h"
+
+namespace content {
+
+namespace {
+// The time period within which a triggered UI event is considered
+// currently active.
+const int kTimePeriodUiEventMicros = 100000;  // 100 ms
+
+// Minimum number of user interactions before we consider the user to be in
+// interactive mode. The goal is to prevent user interactions to launch
+// animated content from causing target playout time flip-flop.
+const int kMinUserInteractions = 5;
+}  // namespace
+
+WindowActivityTrackerAura::WindowActivityTrackerAura(aura::Window* window)
+    : window_(window),
+      last_time_ui_event_detected_(base::TimeTicks()),
+      ui_events_count_(0),
+      weak_factory_(this) {
+  if (window_) {
+    window_->AddObserver(this);
+    window_->AddPreTargetHandler(this);
+  }
+}
+
+WindowActivityTrackerAura::~WindowActivityTrackerAura() {
+  if (window_) {
+    window_->RemoveObserver(this);
+    window_->RemovePreTargetHandler(this);
+  }
+}
+
+base::WeakPtr<WindowActivityTracker> WindowActivityTrackerAura::GetWeakPtr() {
+  return weak_factory_.GetWeakPtr();
+}
+
+bool WindowActivityTrackerAura::IsUiInteractionActive() const {
+  return ui_events_count_ > kMinUserInteractions;
+}
+
+void WindowActivityTrackerAura::Reset() {
+  ui_events_count_ = 0;
+  last_time_ui_event_detected_ = base::TimeTicks();
+}
+
+void WindowActivityTrackerAura::OnEvent(ui::Event* event) {
+  if (base::TimeTicks::Now() - last_time_ui_event_detected_ >
+      base::TimeDelta::FromMicroseconds(kTimePeriodUiEventMicros)) {
+    ui_events_count_++;
+  }
+  last_time_ui_event_detected_ = base::TimeTicks::Now();
+}
+
+void WindowActivityTrackerAura::OnWindowDestroying(aura::Window* window) {
+  DCHECK_EQ(window_, window);
+  window_->RemovePreTargetHandler(this);
+  window_->RemoveObserver(this);
+  window_ = nullptr;
+}
+
+}  // namespace content
diff --git a/content/browser/media/capture/window_activity_tracker_aura.h b/content/browser/media/capture/window_activity_tracker_aura.h
new file mode 100644
index 0000000..c382c7a4
--- /dev/null
+++ b/content/browser/media/capture/window_activity_tracker_aura.h
@@ -0,0 +1,56 @@
+// 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 CONTENT_BROWSER_MEDIA_CAPTURE_WINDOW_ACTIVITY_TRACKER_AURA_H_
+#define CONTENT_BROWSER_MEDIA_CAPTURE_WINDOW_ACTIVITY_TRACKER_AURA_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/media/capture/window_activity_tracker.h"
+#include "content/common/content_export.h"
+#include "ui/aura/window.h"
+#include "ui/events/event_handler.h"
+
+namespace content {
+
+// Tracks UI events and makes a decision on whether the user has been
+// actively interacting with a specified window.
+class CONTENT_EXPORT WindowActivityTrackerAura : public WindowActivityTracker,
+                                                 public ui::EventHandler,
+                                                 public aura::WindowObserver {
+ public:
+  explicit WindowActivityTrackerAura(aura::Window* window);
+  ~WindowActivityTrackerAura() final;
+
+  // WindowActivityTracker overrides.
+  bool IsUiInteractionActive() const final;
+  void Reset() final;
+  base::WeakPtr<WindowActivityTracker> GetWeakPtr() final;
+
+ private:
+  // ui::EventHandler overrides.
+  void OnEvent(ui::Event* event) final;
+
+  // aura::WindowObserver overrides.
+  void OnWindowDestroying(aura::Window* window) final;
+
+  aura::Window* window_;
+
+  // The last time a UI event was detected.
+  base::TimeTicks last_time_ui_event_detected_;
+
+  // The number of UI events detected so far. In case of continuous events
+  // such as mouse movement, a single continuous movement is treated
+  // as one event.
+  int ui_events_count_;
+
+  base::WeakPtrFactory<WindowActivityTrackerAura> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowActivityTrackerAura);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_MEDIA_CAPTURE_WINDOW_ACTIVITY_TRACKER_AURA_H_
diff --git a/content/browser/media/media_web_contents_observer.cc b/content/browser/media/media_web_contents_observer.cc
index c17a9ff..dc79efa1 100644
--- a/content/browser/media/media_web_contents_observer.cc
+++ b/content/browser/media/media_web_contents_observer.cc
@@ -8,6 +8,8 @@
 #include "base/stl_util.h"
 #include "content/browser/media/cdm/browser_cdm_manager.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/frame_messages.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "ipc/ipc_message_macros.h"
@@ -20,23 +22,20 @@
 
 namespace content {
 
-MediaWebContentsObserver::MediaWebContentsObserver(
-    WebContents* web_contents)
-    : WebContentsObserver(web_contents)
-{
-}
+MediaWebContentsObserver::MediaWebContentsObserver(WebContents* web_contents)
+    : WebContentsObserver(web_contents) {}
 
-MediaWebContentsObserver::~MediaWebContentsObserver() {
-}
+MediaWebContentsObserver::~MediaWebContentsObserver() {}
 
 void MediaWebContentsObserver::RenderFrameDeleted(
     RenderFrameHost* render_frame_host) {
+  ClearPowerSaveBlockers(render_frame_host);
+
 #if defined(OS_ANDROID)
-  uintptr_t key = reinterpret_cast<uintptr_t>(render_frame_host);
   // Always destroy the media players before CDMs because we do not support
   // detaching CDMs from media players yet. See http://crbug.com/330324
-  media_player_managers_.erase(key);
-#endif
+  media_player_managers_.erase(render_frame_host);
+
   // TODO(xhwang): Currently MediaWebContentsObserver, BrowserMediaPlayerManager
   // and BrowserCdmManager all run on browser UI thread. So this call is okay.
   // In the future we need to support the case where MediaWebContentsObserver
@@ -46,22 +45,212 @@
       BrowserCdmManager::FromProcess(render_frame_host->GetProcess()->GetID());
   if (browser_cdm_manager)
     browser_cdm_manager->RenderFrameDeleted(render_frame_host->GetRoutingID());
+#endif
 }
 
-#if defined(OS_ANDROID)
+void MediaWebContentsObserver::MaybeUpdateAudibleState(bool recently_audible) {
+  if (recently_audible) {
+    if (!audio_power_save_blocker_)
+      CreateAudioPowerSaveBlocker();
+  } else {
+    audio_power_save_blocker_.reset();
+  }
+}
 
 bool MediaWebContentsObserver::OnMessageReceived(
     const IPC::Message& msg,
     RenderFrameHost* render_frame_host) {
+  if (OnMediaPlayerDelegateMessageReceived(msg, render_frame_host))
+    return true;
+
+#if defined(OS_ANDROID)
   if (OnMediaPlayerMessageReceived(msg, render_frame_host))
     return true;
 
   if (OnMediaPlayerSetCdmMessageReceived(msg, render_frame_host))
     return true;
+#endif
 
   return false;
 }
 
+bool MediaWebContentsObserver::OnMediaPlayerDelegateMessageReceived(
+    const IPC::Message& msg,
+    RenderFrameHost* render_frame_host) {
+  bool handled = true;
+  // TODO(dalecurtis): These should no longer be FrameHostMsg.
+  IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MediaWebContentsObserver, msg,
+                                   render_frame_host)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_MediaPlayingNotification,
+                        OnMediaPlayingNotification)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_MediaPausedNotification,
+                        OnMediaPausedNotification)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  return handled;
+}
+
+void MediaWebContentsObserver::OnMediaPlayingNotification(
+    RenderFrameHost* render_frame_host,
+    int64_t player_cookie,
+    bool has_video,
+    bool has_audio,
+    bool is_remote) {
+  // Ignore the videos playing remotely and don't hold the wake lock for the
+  // screen. TODO(dalecurtis): Is this correct? It means observers will not
+  // receive play and pause messages.
+  if (is_remote)
+    return;
+
+  const MediaPlayerId id(render_frame_host, player_cookie);
+  if (has_audio) {
+    AddMediaPlayerEntry(id, &active_audio_players_);
+
+    // If we don't have audio stream monitoring, allocate the audio power save
+    // blocker here instead of during NotifyNavigationStateChanged().
+    if (!audio_power_save_blocker_ &&
+        !AudioStreamMonitor::monitoring_available()) {
+      CreateAudioPowerSaveBlocker();
+    }
+  }
+
+  if (has_video) {
+    AddMediaPlayerEntry(id, &active_video_players_);
+
+    // If we're not hidden and have just created a player, create a blocker.
+    if (!video_power_save_blocker_ &&
+        !static_cast<WebContentsImpl*>(web_contents())->IsHidden()) {
+      CreateVideoPowerSaveBlocker();
+    }
+  }
+
+  // Notify observers of the new player.
+  DCHECK(has_audio || has_video);
+  static_cast<WebContentsImpl*>(web_contents())->MediaStartedPlaying(id);
+}
+
+void MediaWebContentsObserver::OnMediaPausedNotification(
+    RenderFrameHost* render_frame_host,
+    int64_t player_cookie) {
+  const MediaPlayerId id(render_frame_host, player_cookie);
+  const bool removed_audio = RemoveMediaPlayerEntry(id, &active_audio_players_);
+  const bool removed_video = RemoveMediaPlayerEntry(id, &active_video_players_);
+  MaybeReleasePowerSaveBlockers();
+
+  if (removed_audio || removed_video) {
+    // Notify observers the player has been "paused".
+    static_cast<WebContentsImpl*>(web_contents())->MediaStoppedPlaying(id);
+  }
+}
+
+void MediaWebContentsObserver::ClearPowerSaveBlockers(
+    RenderFrameHost* render_frame_host) {
+  std::set<MediaPlayerId> removed_players;
+  RemoveAllMediaPlayerEntries(render_frame_host, &active_audio_players_,
+                              &removed_players);
+  RemoveAllMediaPlayerEntries(render_frame_host, &active_video_players_,
+                              &removed_players);
+  MaybeReleasePowerSaveBlockers();
+
+  // Notify all observers the player has been "paused".
+  WebContentsImpl* wci = static_cast<WebContentsImpl*>(web_contents());
+  for (const auto& id : removed_players)
+    wci->MediaStoppedPlaying(id);
+}
+
+void MediaWebContentsObserver::CreateAudioPowerSaveBlocker() {
+  DCHECK(!audio_power_save_blocker_);
+  audio_power_save_blocker_ = PowerSaveBlocker::Create(
+      PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
+      PowerSaveBlocker::kReasonAudioPlayback, "Playing audio");
+}
+
+void MediaWebContentsObserver::CreateVideoPowerSaveBlocker() {
+  DCHECK(!video_power_save_blocker_);
+  DCHECK(!active_video_players_.empty());
+  video_power_save_blocker_ = PowerSaveBlocker::Create(
+      PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+      PowerSaveBlocker::kReasonVideoPlayback, "Playing video");
+// TODO(mfomitchev): Support PowerSaveBlocker on Aura - crbug.com/546718.
+#if defined(OS_ANDROID) && !defined(USE_AURA)
+  static_cast<PowerSaveBlockerImpl*>(video_power_save_blocker_.get())
+      ->InitDisplaySleepBlocker(web_contents());
+#endif
+}
+
+void MediaWebContentsObserver::WasShown() {
+  // Restore power save blocker if there are active video players running.
+  if (!active_video_players_.empty() && !video_power_save_blocker_)
+    CreateVideoPowerSaveBlocker();
+}
+
+void MediaWebContentsObserver::WasHidden() {
+  // If there are entities capturing screenshots or video (e.g., mirroring),
+  // don't release the power save blocker.
+  if (!web_contents()->GetCapturerCount())
+    video_power_save_blocker_.reset();
+}
+
+void MediaWebContentsObserver::MaybeReleasePowerSaveBlockers() {
+  // If there are no more audio players and we don't have audio stream
+  // monitoring, release the audio power save blocker here instead of during
+  // NotifyNavigationStateChanged().
+  if (active_audio_players_.empty() &&
+      !AudioStreamMonitor::monitoring_available()) {
+    audio_power_save_blocker_.reset();
+  }
+
+  // If there are no more video players, clear the video power save blocker.
+  if (active_video_players_.empty())
+    video_power_save_blocker_.reset();
+}
+
+void MediaWebContentsObserver::AddMediaPlayerEntry(
+    const MediaPlayerId& id,
+    ActiveMediaPlayerMap* player_map) {
+  DCHECK(std::find((*player_map)[id.first].begin(),
+                   (*player_map)[id.first].end(),
+                   id.second) == (*player_map)[id.first].end());
+  (*player_map)[id.first].push_back(id.second);
+}
+
+bool MediaWebContentsObserver::RemoveMediaPlayerEntry(
+    const MediaPlayerId& id,
+    ActiveMediaPlayerMap* player_map) {
+  auto it = player_map->find(id.first);
+  if (it == player_map->end())
+    return false;
+
+  // Remove the player.
+  auto player_for_removal =
+      std::remove(it->second.begin(), it->second.end(), id.second);
+  if (player_for_removal == it->second.end())
+    return false;
+  it->second.erase(player_for_removal);
+
+  // If there are no players left, remove the map entry.
+  if (it->second.empty())
+    player_map->erase(it);
+
+  return true;
+}
+
+void MediaWebContentsObserver::RemoveAllMediaPlayerEntries(
+    RenderFrameHost* render_frame_host,
+    ActiveMediaPlayerMap* player_map,
+    std::set<MediaPlayerId>* removed_players) {
+  auto it = player_map->find(render_frame_host);
+  if (it == player_map->end())
+    return;
+
+  for (int64_t player_cookie : it->second)
+    removed_players->insert(MediaPlayerId(render_frame_host, player_cookie));
+
+  player_map->erase(it);
+}
+
+#if defined(OS_ANDROID)
+
 bool MediaWebContentsObserver::OnMediaPlayerMessageReceived(
     const IPC::Message& msg,
     RenderFrameHost* render_frame_host) {
@@ -155,21 +344,21 @@
 
 BrowserMediaPlayerManager* MediaWebContentsObserver::GetMediaPlayerManager(
     RenderFrameHost* render_frame_host) {
-  uintptr_t key = reinterpret_cast<uintptr_t>(render_frame_host);
-  if (!media_player_managers_.contains(key)) {
-    media_player_managers_.set(
-        key,
-        make_scoped_ptr(BrowserMediaPlayerManager::Create(render_frame_host)));
-  }
-  return media_player_managers_.get(key);
+  auto it = media_player_managers_.find(render_frame_host);
+  if (it != media_player_managers_.end())
+    return it->second;
+
+  BrowserMediaPlayerManager* manager =
+      BrowserMediaPlayerManager::Create(render_frame_host);
+  media_player_managers_.set(render_frame_host, make_scoped_ptr(manager));
+  return manager;
 }
 
 #if defined(VIDEO_HOLE)
 void MediaWebContentsObserver::OnFrameInfoUpdated() {
-  for (MediaPlayerManagerMap::iterator iter = media_player_managers_.begin();
-      iter != media_player_managers_.end(); ++iter) {
-    BrowserMediaPlayerManager* manager = iter->second;
-    manager->OnFrameInfoUpdated();
+  for (auto it = media_player_managers_.begin();
+       it != media_player_managers_.end(); ++it) {
+    it->second->OnFrameInfoUpdated();
   }
 }
 #endif  // defined(VIDEO_HOLE)
diff --git a/content/browser/media/media_web_contents_observer.h b/content/browser/media/media_web_contents_observer.h
index 382dcdf7..0a24913 100644
--- a/content/browser/media/media_web_contents_observer.h
+++ b/content/browser/media/media_web_contents_observer.h
@@ -5,8 +5,13 @@
 #ifndef CONTENT_BROWSER_MEDIA_MEDIA_WEB_CONTENTS_OBSERVER_H_
 #define CONTENT_BROWSER_MEDIA_MEDIA_WEB_CONTENTS_OBSERVER_H_
 
+#include <map>
+#include <set>
+#include <vector>
+
 #include "base/compiler_specific.h"
 #include "base/containers/scoped_ptr_hash_map.h"
+#include "content/browser/power_save_blocker_impl.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/web_contents_observer.h"
 
@@ -24,40 +29,98 @@
   explicit MediaWebContentsObserver(WebContents* web_contents);
   ~MediaWebContentsObserver() override;
 
-  // WebContentsObserver implementations.
-  void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
+  // Called when the audible state has changed.  If inaudible any audio power
+  // save blockers are released.
+  void MaybeUpdateAudibleState(bool recently_audible);
 
-#if defined(OS_ANDROID)
+  // WebContentsObserver implementation.
+  void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
   bool OnMessageReceived(const IPC::Message& message,
                          RenderFrameHost* render_frame_host) override;
+  void WasShown() override;
+  void WasHidden() override;
 
-  // Helper functions to handle media player IPC messages. Returns whether the
-  // |message| is handled in the function.
-  bool OnMediaPlayerMessageReceived(const IPC::Message& message,
-                                    RenderFrameHost* render_frame_host);
-  bool OnMediaPlayerSetCdmMessageReceived(const IPC::Message& message,
-                                          RenderFrameHost* render_frame_host);
-
+#if defined(OS_ANDROID)
   // Gets the media player manager associated with |render_frame_host|. Creates
   // a new one if it doesn't exist. The caller doesn't own the returned pointer.
   BrowserMediaPlayerManager* GetMediaPlayerManager(
       RenderFrameHost* render_frame_host);
 
-  void OnSetCdm(RenderFrameHost* render_frame_host, int player_id, int cdm_id);
-
 #if defined(VIDEO_HOLE)
   void OnFrameInfoUpdated();
 #endif  // defined(VIDEO_HOLE)
+#endif  // defined(OS_ANDROID)
+
+  bool has_audio_power_save_blocker_for_testing() const {
+    return audio_power_save_blocker_;
+  }
+
+  bool has_video_power_save_blocker_for_testing() const {
+    return video_power_save_blocker_;
+  }
 
  private:
+  bool OnMediaPlayerDelegateMessageReceived(const IPC::Message& message,
+                                            RenderFrameHost* render_frame_host);
+
+  void OnMediaPlayingNotification(RenderFrameHost* render_frame_host,
+                                  int64_t player_cookie,
+                                  bool has_video,
+                                  bool has_audio,
+                                  bool is_remote);
+  void OnMediaPausedNotification(RenderFrameHost* render_frame_host,
+                                 int64_t player_cookie);
+
+  // Clear |render_frame_host|'s tracking entry for its power save blockers.
+  void ClearPowerSaveBlockers(RenderFrameHost* render_frame_host);
+
+  // Creates an audio or video power save blocker respectively.
+  void CreateAudioPowerSaveBlocker();
+  void CreateVideoPowerSaveBlocker();
+
+  // Releases the audio power save blockers if |active_audio_players_| is empty.
+  // Likewise, releases the video power save blockers if |active_video_players_|
+  // is empty.
+  void MaybeReleasePowerSaveBlockers();
+
+  // Helper methods for adding or removing player entries in |player_map|.
+  using PlayerList = std::vector<int64_t>;
+  using ActiveMediaPlayerMap = std::map<RenderFrameHost*, PlayerList>;
+  void AddMediaPlayerEntry(const MediaPlayerId& id,
+                           ActiveMediaPlayerMap* player_map);
+  // Returns true if an entry is actually removed.
+  bool RemoveMediaPlayerEntry(const MediaPlayerId& id,
+                              ActiveMediaPlayerMap* player_map);
+  // Removes all entries from |player_map| for |render_frame_host|. Removed
+  // entries are added to |removed_players|.
+  void RemoveAllMediaPlayerEntries(RenderFrameHost* render_frame_host,
+                                   ActiveMediaPlayerMap* player_map,
+                                   std::set<MediaPlayerId>* removed_players);
+
+#if defined(OS_ANDROID)
+  // Helper functions to handle media player IPC messages. Returns whether the
+  // |message| is handled in the function.
+  bool OnMediaPlayerMessageReceived(const IPC::Message& message,
+                                    RenderFrameHost* render_frame_host);
+
+  bool OnMediaPlayerSetCdmMessageReceived(const IPC::Message& message,
+                                          RenderFrameHost* render_frame_host);
+
+  void OnSetCdm(RenderFrameHost* render_frame_host, int player_id, int cdm_id);
+
   // Map from RenderFrameHost* to BrowserMediaPlayerManager.
-  typedef base::ScopedPtrHashMap<uintptr_t,
-                                 scoped_ptr<BrowserMediaPlayerManager>>
-      MediaPlayerManagerMap;
+  using MediaPlayerManagerMap =
+      base::ScopedPtrHashMap<RenderFrameHost*,
+                             scoped_ptr<BrowserMediaPlayerManager>>;
   MediaPlayerManagerMap media_player_managers_;
 #endif  // defined(OS_ANDROID)
 
- private:
+  // Tracking variables and associated power save blockers for media playback.
+  ActiveMediaPlayerMap active_audio_players_;
+  ActiveMediaPlayerMap active_video_players_;
+  scoped_ptr<PowerSaveBlocker> audio_power_save_blocker_;
+  scoped_ptr<PowerSaveBlocker> video_power_save_blocker_;
+
   DISALLOW_COPY_AND_ASSIGN(MediaWebContentsObserver);
 };
 
diff --git a/content/browser/mojo/mojo_shell_client_host.cc b/content/browser/mojo/mojo_shell_client_host.cc
index 53be44dd1..871cd5b 100644
--- a/content/browser/mojo/mojo_shell_client_host.cc
+++ b/content/browser/mojo/mojo_shell_client_host.cc
@@ -6,6 +6,7 @@
 #include "base/thread_task_runner_handle.h"
 #include "content/browser/mojo/mojo_shell_client_host.h"
 #include "content/common/mojo/mojo_messages.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/common/mojo_shell_connection.h"
 #include "ipc/ipc_sender.h"
@@ -72,6 +73,16 @@
                                    new InstanceShellHandle(platform_file));
 }
 
+void CallRegisterProcessWithBroker(base::ProcessId pid,
+                                   MojoHandle client_pipe) {
+  mojo::shell::mojom::ApplicationManagerPtr application_manager;
+  MojoShellConnection::Get()->GetApplication()->ConnectToService(
+      "mojo:shell", &application_manager);
+  application_manager->RegisterProcessWithBroker(
+      static_cast<uint32_t>(pid),
+      mojo::ScopedHandle(mojo::Handle(client_pipe)));
+}
+
 }  // namespace
 
 void RegisterChildWithExternalShell(int child_process_id,
@@ -136,4 +147,26 @@
       IPC::GetFileHandleForProcess(client_file->get(), process_handle, true)));
 }
 
+mojo::embedder::ScopedPlatformHandle RegisterProcessWithBroker(
+    base::ProcessId pid) {
+  mojo::embedder::PlatformChannelPair platform_channel_pair;
+
+  MojoHandle platform_handle_wrapper;
+  MojoResult rv = mojo::embedder::CreatePlatformHandleWrapper(
+      platform_channel_pair.PassServerHandle(), &platform_handle_wrapper);
+  CHECK_EQ(rv, MOJO_RESULT_OK);
+
+  if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+    CallRegisterProcessWithBroker(pid, platform_handle_wrapper);
+  } else {
+    BrowserThread::PostTask(
+        BrowserThread::UI,
+        FROM_HERE,
+        base::Bind(CallRegisterProcessWithBroker, pid,
+                   platform_handle_wrapper));
+  }
+
+  return platform_channel_pair.PassClientHandle();
+}
+
 }  // namespace content
diff --git a/content/browser/mojo/mojo_shell_client_host.h b/content/browser/mojo/mojo_shell_client_host.h
index 53f5a1e86..8566af1 100644
--- a/content/browser/mojo/mojo_shell_client_host.h
+++ b/content/browser/mojo/mojo_shell_client_host.h
@@ -9,6 +9,7 @@
 
 #include "base/process/process_handle.h"
 #include "mojo/application/public/interfaces/shell.mojom.h"
+#include "third_party/mojo/src/mojo/edk/embedder/scoped_platform_handle.h"
 
 namespace content {
 
@@ -38,6 +39,10 @@
 // review.
 mojo::CapabilityFilterPtr CreateCapabilityFilterForRenderer();
 
+// Used for the broker in the new EDK.
+mojo::embedder::ScopedPlatformHandle RegisterProcessWithBroker(
+    base::ProcessId pid);
+
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_MOJO_MOJO_SHELL_CLIENT_HOST_H_
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..ba480745 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.
@@ -86,6 +93,9 @@
   // enqueue_apply_ below.
   void InitOnUIThread();
 
+  // Returns true if ApplyBlock() / RemoveBlock() should be called.
+  bool ShouldBlock() const;
+
   // Apply or remove the power save block, respectively. These methods should be
   // called once each, on the same thread, per instance. They block waiting for
   // the action to complete (with a timeout); the thread must thus allow I/O.
@@ -109,6 +119,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 +149,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) {
@@ -166,7 +179,7 @@
     // initializing on the UI thread, then just cancel it. We don't need to
     // remove the block because we haven't even applied it yet.
     enqueue_apply_ = false;
-  } else if (api_ != NO_API) {
+  } else if (ShouldBlock()) {
     BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
                             base::Bind(&Delegate::RemoveBlock, this));
   }
@@ -176,7 +189,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   base::AutoLock lock(lock_);
   api_ = SelectAPI();
-  if (enqueue_apply_ && api_ != NO_API) {
+  if (enqueue_apply_ && ShouldBlock()) {
     // 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.
@@ -186,6 +199,10 @@
   enqueue_apply_ = false;
 }
 
+bool PowerSaveBlockerImpl::Delegate::ShouldBlock() const {
+  return freedesktop_only_ ? api_ == FREEDESKTOP_API : api_ != NO_API;
+}
+
 void PowerSaveBlockerImpl::Delegate::ApplyBlock() {
   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
   DCHECK(!bus_);  // ApplyBlock() should only be called once.
@@ -235,11 +252,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 +339,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 +422,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/quota/mock_quota_manager.cc b/content/browser/quota/mock_quota_manager.cc
index 47bc304..9067408 100644
--- a/content/browser/quota/mock_quota_manager.cc
+++ b/content/browser/quota/mock_quota_manager.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/quota/mock_quota_manager.h"
 
+#include <limits>
+
 #include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
@@ -28,7 +30,8 @@
 
 MockQuotaManager::OriginInfo::~OriginInfo() {}
 
-MockQuotaManager::StorageInfo::StorageInfo() : usage(0), quota(kint64max) {}
+MockQuotaManager::StorageInfo::StorageInfo()
+    : usage(0), quota(std::numeric_limits<int64_t>::max()) {}
 MockQuotaManager::StorageInfo::~StorageInfo() {}
 
 MockQuotaManager::MockQuotaManager(
@@ -53,8 +56,9 @@
   callback.Run(storage::kQuotaStatusOk, info.usage, info.quota);
 }
 
-void MockQuotaManager::SetQuota(const GURL& origin, StorageType type,
-                                int64 quota) {
+void MockQuotaManager::SetQuota(const GURL& origin,
+                                StorageType type,
+                                int64_t quota) {
   usage_and_quota_map_[std::make_pair(origin, type)].quota = quota;
 }
 
@@ -125,8 +129,9 @@
 
 MockQuotaManager::~MockQuotaManager() {}
 
-void MockQuotaManager::UpdateUsage(
-    const GURL& origin, StorageType type, int64 delta) {
+void MockQuotaManager::UpdateUsage(const GURL& origin,
+                                   StorageType type,
+                                   int64_t delta) {
   usage_and_quota_map_[std::make_pair(origin, type)].usage += delta;
 }
 
diff --git a/content/browser/quota/mock_quota_manager.h b/content/browser/quota/mock_quota_manager.h
index a6bba10e..ecb0d72 100644
--- a/content/browser/quota/mock_quota_manager.h
+++ b/content/browser/quota/mock_quota_manager.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_BROWSER_QUOTA_MOCK_QUOTA_MANAGER_H_
 #define CONTENT_BROWSER_QUOTA_MOCK_QUOTA_MANAGER_H_
 
+#include <stdint.h>
+
 #include <map>
 #include <set>
 #include <utility>
@@ -74,7 +76,7 @@
                         const StatusCallback& callback) override;
 
   // Helper method for updating internal quota info.
-  void SetQuota(const GURL& origin, StorageType type, int64 quota);
+  void SetQuota(const GURL& origin, StorageType type, int64_t quota);
 
   // Helper methods for timed-deletion testing:
   // Adds an origin to the canned list that will be searched through via
@@ -123,15 +125,15 @@
   struct StorageInfo {
     StorageInfo();
     ~StorageInfo();
-    int64 usage;
-    int64 quota;
+    int64_t usage;
+    int64_t quota;
   };
 
   typedef std::pair<GURL, StorageType> OriginAndType;
   typedef std::map<OriginAndType, StorageInfo> UsageAndQuotaMap;
 
   // This must be called via MockQuotaManagerProxy.
-  void UpdateUsage(const GURL& origin, StorageType type, int64 delta);
+  void UpdateUsage(const GURL& origin, StorageType type, int64_t delta);
   void DidGetModifiedSince(const GetOriginsCallback& callback,
                            std::set<GURL>* origins,
                            StorageType storage_type);
diff --git a/content/browser/quota/mock_quota_manager_proxy.cc b/content/browser/quota/mock_quota_manager_proxy.cc
index 2e26e32c..a8b955d8 100644
--- a/content/browser/quota/mock_quota_manager_proxy.cc
+++ b/content/browser/quota/mock_quota_manager_proxy.cc
@@ -43,9 +43,10 @@
   last_notified_type_ = type;
 }
 
-void MockQuotaManagerProxy::NotifyStorageModified(
-    QuotaClient::ID client_id, const GURL& origin,
-    StorageType type, int64 delta) {
+void MockQuotaManagerProxy::NotifyStorageModified(QuotaClient::ID client_id,
+                                                  const GURL& origin,
+                                                  StorageType type,
+                                                  int64_t delta) {
   ++storage_modified_count_;
   last_notified_origin_ = origin;
   last_notified_type_ = type;
diff --git a/content/browser/quota/mock_quota_manager_proxy.h b/content/browser/quota/mock_quota_manager_proxy.h
index 0f52f6d..3ba9810e 100644
--- a/content/browser/quota/mock_quota_manager_proxy.h
+++ b/content/browser/quota/mock_quota_manager_proxy.h
@@ -55,13 +55,13 @@
   void NotifyStorageModified(QuotaClient::ID client_id,
                              const GURL& origin,
                              StorageType type,
-                             int64 delta) override;
+                             int64_t delta) override;
 
   int notify_storage_accessed_count() const { return storage_accessed_count_; }
   int notify_storage_modified_count() const { return storage_modified_count_; }
   GURL last_notified_origin() const { return last_notified_origin_; }
   StorageType last_notified_type() const { return last_notified_type_; }
-  int64 last_notified_delta() const { return last_notified_delta_; }
+  int64_t last_notified_delta() const { return last_notified_delta_; }
 
  protected:
   ~MockQuotaManagerProxy() override;
@@ -75,7 +75,7 @@
   int storage_modified_count_;
   GURL last_notified_origin_;
   StorageType last_notified_type_;
-  int64 last_notified_delta_;
+  int64_t last_notified_delta_;
 
   QuotaClient* registered_client_;
 
diff --git a/content/browser/renderer_host/input/composited_scrolling_browsertest.cc b/content/browser/renderer_host/input/composited_scrolling_browsertest.cc
new file mode 100644
index 0000000..e776a8e
--- /dev/null
+++ b/content/browser/renderer_host/input/composited_scrolling_browsertest.cc
@@ -0,0 +1,167 @@
+// 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/bind.h"
+#include "base/command_line.h"
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "cc/base/math_util.h"
+#include "content/browser/renderer_host/input/synthetic_gesture.h"
+#include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/input/synthetic_gesture_params.h"
+#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/test_utils.h"
+#include "content/shell/browser/shell.h"
+
+namespace {
+
+const char kCompositedScrollingDataURL[] =
+    "data:text/html;charset=utf-8,"
+    "<!DOCTYPE html>"
+    "<meta name='viewport' content='width=device-width'/>"
+    "<style>"
+    "#scroller {"
+    "  width:500px;"
+    "  height:500px;"
+    "  overflow:scroll;"
+    "  transform: rotateX(-30deg);"
+    "}"
+
+    "#content {"
+    "  background-color:red;"
+    "  width:1000px;"
+    "  height:1000px;"
+    "}"
+    "</style>"
+    "<div id='scroller'>"
+    "  <div id='content'>"
+    "  </div>"
+    "</div>"
+    "<script>"
+    "  document.title='ready';"
+    "</script>";
+
+}  // namespace
+
+namespace content {
+
+
+class CompositedScrollingBrowserTest : public ContentBrowserTest {
+ public:
+  CompositedScrollingBrowserTest() {}
+  ~CompositedScrollingBrowserTest() override {}
+
+  void SetUpCommandLine(base::CommandLine* cmd) override {
+    cmd->AppendSwitch(switches::kEnablePreferCompositingToLCDText);
+  }
+
+  RenderWidgetHostImpl* GetWidgetHost() {
+    return RenderWidgetHostImpl::From(
+        shell()->web_contents()->GetRenderViewHost()->GetWidget());
+  }
+
+  void OnSyntheticGestureCompleted(SyntheticGesture::Result result) {
+    EXPECT_EQ(SyntheticGesture::GESTURE_FINISHED, result);
+    runner_->Quit();
+  }
+
+ protected:
+  void LoadURL() {
+    const GURL data_url(kCompositedScrollingDataURL);
+    NavigateToURL(shell(), data_url);
+
+    RenderWidgetHostImpl* host = GetWidgetHost();
+    scoped_refptr<FrameWatcher> frame_watcher(new FrameWatcher());
+    host->GetProcess()->AddFilter(frame_watcher.get());
+    host->GetView()->SetSize(gfx::Size(400, 400));
+
+    base::string16 ready_title(base::ASCIIToUTF16("ready"));
+    TitleWatcher watcher(shell()->web_contents(), ready_title);
+    ignore_result(watcher.WaitAndGetTitle());
+
+    // We need to wait until at least one frame has been composited
+    // otherwise the injection of the synthetic gestures may get
+    // dropped because of MainThread/Impl thread sync of touch event
+    // regions.
+    frame_watcher->WaitFrames(1);
+  }
+
+  // ContentBrowserTest:
+  int ExecuteScriptAndExtractInt(const std::string& script) {
+    int value = 0;
+    EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
+        shell()->web_contents(),
+        "domAutomationController.send(" + script + ")",
+        &value));
+    return value;
+  }
+
+  int GetScrollTop() {
+    return ExecuteScriptAndExtractInt(
+        "document.getElementById(\"scroller\").scrollTop");
+  }
+
+  // Generate touch events for a synthetic scroll from |point| for |distance|.
+  // Returns the distance scrolled.
+  int DoTouchScroll(const gfx::Point& point, const gfx::Vector2d& distance) {
+    EXPECT_EQ(0, GetScrollTop());
+
+    int scrollHeight = ExecuteScriptAndExtractInt(
+        "document.getElementById('scroller').scrollHeight");
+    EXPECT_EQ(1000, scrollHeight);
+
+    SyntheticSmoothScrollGestureParams params;
+    params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
+    params.anchor = gfx::PointF(point);
+    params.distances.push_back(-distance);
+
+    runner_ = new MessageLoopRunner();
+
+    scoped_ptr<SyntheticSmoothScrollGesture> gesture(
+        new SyntheticSmoothScrollGesture(params));
+    GetWidgetHost()->QueueSyntheticGesture(
+        gesture.Pass(),
+        base::Bind(&CompositedScrollingBrowserTest::OnSyntheticGestureCompleted,
+                   base::Unretained(this)));
+
+    // Runs until we get the OnSyntheticGestureCompleted callback
+    runner_->Run();
+    runner_ = NULL;
+
+    return GetScrollTop();
+  }
+
+ private:
+  scoped_refptr<MessageLoopRunner> runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompositedScrollingBrowserTest);
+};
+
+// Verify transforming a scroller doesn't prevent it from scrolling. See
+// crbug.com/543655 for a case where this was broken.
+// Disabled on MacOS because it doesn't support touch input.
+// Disabled on Android due to flakiness, see https://crbug.com/376668.
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+#define MAYBE_Scroll3DTransformedScroller DISABLED_Scroll3DTransformedScroller
+#else
+#define MAYBE_Scroll3DTransformedScroller Scroll3DTransformedScroller
+#endif
+IN_PROC_BROWSER_TEST_F(CompositedScrollingBrowserTest,
+                       MAYBE_Scroll3DTransformedScroller) {
+  LoadURL();
+  int scrollDistance =
+      DoTouchScroll(gfx::Point(50, 150), gfx::Vector2d(0, 100));
+  // The scroll distance is increased due to the rotation of the scroller.
+  EXPECT_EQ(std::floor(100 / std::cos(cc::MathUtil::Deg2Rad(30.f))) - 1,
+            scrollDistance);
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.cc b/content/browser/renderer_host/legacy_render_widget_host_win.cc
index bd0101d1..9e230574 100644
--- a/content/browser/renderer_host/legacy_render_widget_host_win.cc
+++ b/content/browser/renderer_host/legacy_render_widget_host_win.cc
@@ -166,7 +166,7 @@
     return static_cast<LRESULT>(0L);
   }
 
-  if (OBJID_CLIENT != obj_id || !host_)
+  if (static_cast<DWORD>(OBJID_CLIENT) != obj_id || !host_)
     return static_cast<LRESULT>(0L);
 
   RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(
diff --git a/content/browser/renderer_host/media/audio_renderer_host.cc b/content/browser/renderer_host/media/audio_renderer_host.cc
index 40d1adac..86df996 100644
--- a/content/browser/renderer_host/media/audio_renderer_host.cc
+++ b/content/browser/renderer_host/media/audio_renderer_host.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/shared_memory.h"
 #include "base/metrics/histogram.h"
@@ -31,6 +32,7 @@
 #include "content/public/common/content_switches.h"
 #include "media/audio/audio_device_name.h"
 #include "media/audio/audio_manager_base.h"
+#include "media/audio/audio_streams_tracker.h"
 #include "media/base/audio_bus.h"
 #include "media/base/limits.h"
 
@@ -40,6 +42,12 @@
 namespace content {
 
 namespace {
+
+// Tracks the maximum number of simultaneous output streams browser-wide.
+// Accessed on IO thread.
+base::LazyInstance<media::AudioStreamsTracker> g_audio_streams_tracker =
+    LAZY_INSTANCE_INITIALIZER;
+
 // TODO(aiolos): This is a temporary hack until the resource scheduler is
 // migrated to RenderFrames for the Site Isolation project. It's called in
 // response to low frequency playback state changes. http://crbug.com/472869
@@ -216,13 +224,20 @@
 }
 
 AudioRendererHost::~AudioRendererHost() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(audio_entries_.empty());
 
-  // If we had any streams, report the maximum number of simultaneous streams as
-  // UMA stat.
+  // If we had any streams, report UMA stats for the maximum number of
+  // simultaneous streams for this render process and for the whole browser
+  // process since last reported.
   if (max_simultaneous_streams_ > 0) {
     UMA_HISTOGRAM_CUSTOM_COUNTS("Media.AudioRendererIpcStreams",
                                 max_simultaneous_streams_, 1, 50, 51);
+    UMA_HISTOGRAM_CUSTOM_COUNTS(
+        "Media.AudioRendererIpcStreamsTotal",
+        g_audio_streams_tracker.Get().max_stream_count(),
+        1, 100, 101);
+    g_audio_streams_tracker.Get().ResetMaxStreamCount();
   }
 }
 
@@ -550,6 +565,7 @@
         render_process_id_, entry->render_frame_id(), entry->controller());
   }
   audio_entries_.insert(std::make_pair(stream_id, entry.release()));
+  g_audio_streams_tracker.Get().IncreaseStreamCount();
 
   audio_log_->OnCreated(stream_id, params, device_unique_id);
   MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry(
@@ -617,6 +633,7 @@
     return;
   scoped_ptr<AudioEntry> entry(i->second);
   audio_entries_.erase(i);
+  g_audio_streams_tracker.Get().DecreaseStreamCount();
 
   media::AudioOutputController* const controller = entry->controller();
   controller->Close(
diff --git a/content/browser/renderer_host/media/audio_renderer_host_unittest.cc b/content/browser/renderer_host/media/audio_renderer_host_unittest.cc
index 656e6cf..cedd48d 100644
--- a/content/browser/renderer_host/media/audio_renderer_host_unittest.cc
+++ b/content/browser/renderer_host/media/audio_renderer_host_unittest.cc
@@ -31,12 +31,11 @@
 const int kRenderProcessId = 1;
 const int kRenderFrameId = 5;
 const int kStreamId = 50;
-const url::Origin kSecurityOrigin(GURL("http://localhost"));
-const url::Origin kDefaultSecurityOrigin;
-const std::string kDefaultDeviceId;
-const std::string kBadDeviceId =
+const char kSecurityOrigin[] = "http://localhost";
+const char kDefaultDeviceId[] = "";
+const char kBadDeviceId[] =
     "badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad1";
-const std::string kInvalidDeviceId = "invalid-device-id";
+const char kInvalidDeviceId[] = "invalid-device-id";
 }  // namespace
 
 namespace content {
@@ -213,7 +212,7 @@
   }
 
  protected:
-  void Create() { Create(false, kDefaultDeviceId, kDefaultSecurityOrigin); }
+  void Create() { Create(false, kDefaultDeviceId, url::Origin()); }
 
   void Create(bool unified_stream,
               const std::string& device_id,
@@ -385,17 +384,17 @@
 }
 
 TEST_F(AudioRendererHostTest, CreateUnifiedStreamAndClose) {
-  Create(true, kDefaultDeviceId, kDefaultSecurityOrigin);
+  Create(true, kDefaultDeviceId, url::Origin());
   Close();
 }
 
 TEST_F(AudioRendererHostTest, CreateUnauthorizedDevice) {
-  Create(false, kBadDeviceId, kSecurityOrigin);
+  Create(false, kBadDeviceId, url::Origin(GURL(kSecurityOrigin)));
   Close();
 }
 
 TEST_F(AudioRendererHostTest, CreateInvalidDevice) {
-  Create(false, kInvalidDeviceId, kSecurityOrigin);
+  Create(false, kInvalidDeviceId, url::Origin(GURL(kSecurityOrigin)));
   Close();
 }
 
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
index 2b0a385..033dbb65 100644
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
@@ -121,27 +121,23 @@
 MediaStreamDispatcherHost::~MediaStreamDispatcherHost() {
 }
 
-void MediaStreamDispatcherHost::OnGenerateStream(
-    int render_frame_id,
-    int page_request_id,
-    const StreamOptions& components,
-    const GURL& security_origin,
-    bool user_gesture) {
-  DVLOG(1) << "MediaStreamDispatcherHost::OnGenerateStream("
-           << render_frame_id << ", "
-           << page_request_id << ", ["
-           << " audio:" << components.audio_requested
-           << " video:" << components.video_requested
-           << " ], "
-           << security_origin.spec()
-           << ", " << user_gesture << ")";
+void MediaStreamDispatcherHost::OnGenerateStream(int render_frame_id,
+                                                 int page_request_id,
+                                                 const StreamControls& controls,
+                                                 const GURL& security_origin,
+                                                 bool user_gesture) {
+  DVLOG(1) << "MediaStreamDispatcherHost::OnGenerateStream(" << render_frame_id
+           << ", " << page_request_id << ", ["
+           << " audio:" << controls.audio.requested
+           << " video:" << controls.video.requested << " ], "
+           << security_origin.spec() << ", " << user_gesture << ")";
 
   if (!IsURLAllowed(security_origin))
     return;
 
   media_stream_manager_->GenerateStream(
       this, render_process_id_, render_frame_id, salt_callback_,
-      page_request_id, components, security_origin, user_gesture);
+      page_request_id, controls, security_origin, user_gesture);
 }
 
 void MediaStreamDispatcherHost::OnCancelGenerateStream(int render_frame_id,
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host.h b/content/browser/renderer_host/media/media_stream_dispatcher_host.h
index f35ae26e..697fbaee 100644
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host.h
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host.h
@@ -66,7 +66,7 @@
 
   void OnGenerateStream(int render_frame_id,
                         int page_request_id,
-                        const StreamOptions& components,
+                        const StreamControls& controls,
                         const GURL& security_origin,
                         bool user_gesture);
   void OnCancelGenerateStream(int render_frame_id,
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
index 22f000e..db4edad 100644
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
@@ -76,12 +76,12 @@
   // Accessor to private functions.
   void OnGenerateStream(int render_frame_id,
                         int page_request_id,
-                        const StreamOptions& components,
+                        const StreamControls& controls,
                         const GURL& security_origin,
                         const base::Closure& quit_closure) {
     quit_closures_.push(quit_closure);
     MediaStreamDispatcherHost::OnGenerateStream(
-        render_frame_id, page_request_id, components, security_origin, false);
+        render_frame_id, page_request_id, controls, security_origin, false);
   }
 
   void OnStopStreamDevice(int render_frame_id,
@@ -289,19 +289,17 @@
 
   void GenerateStreamAndWaitForResult(int render_frame_id,
                                       int page_request_id,
-                                      const StreamOptions& options) {
+                                      const StreamControls& controls) {
     base::RunLoop run_loop;
     int expected_audio_array_size =
-        (options.audio_requested &&
-         physical_audio_devices_.size() > 0) ? 1 : 0;
+        (controls.audio.requested && !physical_audio_devices_.empty()) ? 1 : 0;
     int expected_video_array_size =
-        (options.video_requested &&
-         physical_video_devices_.size() > 0) ? 1 : 0;
+        (controls.video.requested && !physical_video_devices_.empty()) ? 1 : 0;
     EXPECT_CALL(*host_.get(), OnStreamGenerated(render_frame_id,
                                                 page_request_id,
                                                 expected_audio_array_size,
                                                 expected_video_array_size));
-    host_->OnGenerateStream(render_frame_id, page_request_id, options, origin_,
+    host_->OnGenerateStream(render_frame_id, page_request_id, controls, origin_,
                             run_loop.QuitClosure());
     run_loop.Run();
     EXPECT_FALSE(DoesContainRawIds(host_->audio_devices_));
@@ -311,16 +309,16 @@
   }
 
   void GenerateStreamAndWaitForFailure(
-    int render_frame_id,
-    int page_request_id,
-    const StreamOptions& options,
-    MediaStreamRequestResult expected_result) {
+      int render_frame_id,
+      int page_request_id,
+      const StreamControls& controls,
+      MediaStreamRequestResult expected_result) {
       base::RunLoop run_loop;
       EXPECT_CALL(*host_.get(),
                   OnStreamGenerationFailed(render_frame_id,
                                            page_request_id,
                                            expected_result));
-      host_->OnGenerateStream(render_frame_id, page_request_id, options,
+      host_->OnGenerateStream(render_frame_id, page_request_id, controls,
                               origin_, run_loop.QuitClosure());
       run_loop.Run();
   }
@@ -419,12 +417,6 @@
     return true;
   }
 
-  void AddSourceIdConstraint(const std::string& source_id,
-                             StreamOptions::Constraints* constraints) {
-    constraints->push_back(StreamOptions::Constraint(kMediaStreamSourceInfoId,
-                                                     source_id));
-  }
-
   scoped_refptr<MockMediaStreamDispatcherHost> host_;
   scoped_ptr<media::AudioManager> audio_manager_;
   scoped_ptr<MediaStreamManager> media_stream_manager_;
@@ -440,20 +432,20 @@
 };
 
 TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithVideoOnly) {
-  StreamOptions options(false, true);
+  StreamControls controls(false, true);
 
   SetupFakeUI(true);
-  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
 
   EXPECT_EQ(host_->audio_devices_.size(), 0u);
   EXPECT_EQ(host_->video_devices_.size(), 1u);
 }
 
 TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithAudioOnly) {
-  StreamOptions options(true, false);
+  StreamControls controls(true, false);
 
   SetupFakeUI(true);
-  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
 
   EXPECT_EQ(host_->audio_devices_.size(), 1u);
   EXPECT_EQ(host_->video_devices_.size(), 0u);
@@ -463,20 +455,17 @@
 // MediaStreamManager, so it will create an ordinary one which will not find
 // a RenderFrameHostDelegate. This normally should only be the case at shutdown.
 TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithNothing) {
-  StreamOptions options(false, false);
+  StreamControls controls(false, false);
 
-  GenerateStreamAndWaitForFailure(
-      kRenderId,
-      kPageRequestId,
-      options,
-      MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN);
+  GenerateStreamAndWaitForFailure(kRenderId, kPageRequestId, controls,
+                                  MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN);
 }
 
 TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithAudioAndVideo) {
-  StreamOptions options(true, true);
+  StreamControls controls(true, true);
 
   SetupFakeUI(true);
-  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
 
   EXPECT_EQ(host_->audio_devices_.size(), 1u);
   EXPECT_EQ(host_->video_devices_.size(), 1u);
@@ -486,11 +475,11 @@
 // id. The same capture device with the same device and session id is expected
 // to be used.
 TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsFromSameRenderId) {
-  StreamOptions options(false, true);
+  StreamControls controls(false, true);
 
   // Generate first stream.
   SetupFakeUI(true);
-  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
 
   // Check the latest generated stream.
   EXPECT_EQ(host_->audio_devices_.size(), 0u);
@@ -501,7 +490,7 @@
 
   // Generate second stream.
   SetupFakeUI(true);
-  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId + 1, options);
+  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId + 1, controls);
 
   // Check the latest generated stream.
   EXPECT_EQ(host_->audio_devices_.size(), 0u);
@@ -516,11 +505,11 @@
 
 TEST_F(MediaStreamDispatcherHostTest,
        GenerateStreamAndOpenDeviceFromSameRenderId) {
-  StreamOptions options(false, true);
+  StreamControls controls(false, true);
 
   // Generate first stream.
   SetupFakeUI(true);
-  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
 
   EXPECT_EQ(host_->audio_devices_.size(), 0u);
   EXPECT_EQ(host_->video_devices_.size(), 1u);
@@ -544,11 +533,11 @@
 // This test generates two streams with video only using two separate render
 // frame ids. The same device id but different session ids are expected.
 TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsDifferentRenderId) {
-  StreamOptions options(false, true);
+  StreamControls controls(false, true);
 
   // Generate first stream.
   SetupFakeUI(true);
-  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
 
   // Check the latest generated stream.
   EXPECT_EQ(host_->audio_devices_.size(), 0u);
@@ -559,7 +548,7 @@
 
   // Generate second stream from another render frame.
   SetupFakeUI(true);
-  GenerateStreamAndWaitForResult(kRenderId+1, kPageRequestId + 1, options);
+  GenerateStreamAndWaitForResult(kRenderId + 1, kPageRequestId + 1, controls);
 
   // Check the latest generated stream.
   EXPECT_EQ(host_->audio_devices_.size(), 0u);
@@ -576,7 +565,7 @@
 // stream to be generated before requesting the second.
 // The same device id and session ids are expected.
 TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsWithoutWaiting) {
-  StreamOptions options(false, true);
+  StreamControls controls(false, true);
 
   // Generate first stream.
   SetupFakeUI(true);
@@ -591,9 +580,9 @@
   }
   base::RunLoop run_loop1;
   base::RunLoop run_loop2;
-  host_->OnGenerateStream(kRenderId, kPageRequestId, options, origin_,
+  host_->OnGenerateStream(kRenderId, kPageRequestId, controls, origin_,
                           run_loop1.QuitClosure());
-  host_->OnGenerateStream(kRenderId, kPageRequestId + 1, options, origin_,
+  host_->OnGenerateStream(kRenderId, kPageRequestId + 1, controls, origin_,
                           run_loop2.QuitClosure());
 
   run_loop1.Run();
@@ -614,11 +603,11 @@
         origin_,
         audio_it->unique_id);
     ASSERT_FALSE(source_id.empty());
-    StreamOptions options(true, true);
-    AddSourceIdConstraint(source_id, &options.mandatory_audio);
+    StreamControls controls(true, true);
+    controls.audio.device_ids.push_back(source_id);
 
     SetupFakeUI(true);
-    GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+    GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
     EXPECT_EQ(host_->audio_devices_[0].device.id, source_id);
   }
 
@@ -630,11 +619,11 @@
         origin_,
         video_it->id());
     ASSERT_FALSE(source_id.empty());
-    StreamOptions options(true, true);
-    AddSourceIdConstraint(source_id, &options.mandatory_video);
+    StreamControls controls(true, true);
+    controls.video.device_ids.push_back(source_id);
 
     SetupFakeUI(true);
-    GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+    GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
     EXPECT_EQ(host_->video_devices_[0].device.id, source_id);
   }
 }
@@ -653,11 +642,11 @@
         origin_,
         audio_it->unique_id);
     ASSERT_FALSE(source_id.empty());
-    StreamOptions options(true, true);
-    AddSourceIdConstraint(source_id, &options.optional_audio);
+    StreamControls controls(true, true);
+    controls.audio.device_ids.push_back(source_id);
 
     SetupFakeUI(true);
-    GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+    GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
     EXPECT_EQ(host_->audio_devices_[0].device.id, source_id);
   }
 
@@ -669,11 +658,11 @@
         origin_,
         video_it->id());
     ASSERT_FALSE(source_id.empty());
-    StreamOptions options(true, true);
-    AddSourceIdConstraint(source_id, &options.optional_video);
+    StreamControls controls(true, true);
+    controls.video.device_ids.push_back(source_id);
 
     SetupFakeUI(true);
-    GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+    GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
     EXPECT_EQ(host_->video_devices_[0].device.id, source_id);
   }
 }
@@ -681,59 +670,53 @@
 // Test that generating a stream with an invalid mandatory video source id fail.
 TEST_F(MediaStreamDispatcherHostTest,
        GenerateStreamsWithInvalidMandatoryVideoSourceId) {
-  StreamOptions options(true, true);
-  AddSourceIdConstraint("invalid source id", &options.mandatory_video);
+  StreamControls controls(true, true);
+  controls.video.device_ids.push_back("invalid source id");
 
-  GenerateStreamAndWaitForFailure(
-      kRenderId,
-      kPageRequestId,
-      options,
-      MEDIA_DEVICE_NO_HARDWARE);
+  GenerateStreamAndWaitForFailure(kRenderId, kPageRequestId, controls,
+                                  MEDIA_DEVICE_NO_HARDWARE);
 }
 
 // Test that generating a stream with an invalid mandatory audio source id fail.
 TEST_F(MediaStreamDispatcherHostTest,
        GenerateStreamsWithInvalidMandatoryAudioSourceId) {
-  StreamOptions options(true, true);
-  AddSourceIdConstraint("invalid source id", &options.mandatory_audio);
+  StreamControls controls(true, true);
+  controls.audio.device_ids.push_back("invalid source id");
 
-  GenerateStreamAndWaitForFailure(
-      kRenderId,
-      kPageRequestId,
-      options,
-      MEDIA_DEVICE_NO_HARDWARE);
+  GenerateStreamAndWaitForFailure(kRenderId, kPageRequestId, controls,
+                                  MEDIA_DEVICE_NO_HARDWARE);
 }
 
 // Test that generating a stream with an invalid optional video source id
 // succeed.
 TEST_F(MediaStreamDispatcherHostTest,
        GenerateStreamsWithInvalidOptionalVideoSourceId) {
-  StreamOptions options(true, true);
-  AddSourceIdConstraint("invalid source id", &options.optional_video);
+  StreamControls controls(true, true);
+  controls.video.alternate_device_ids.push_back("invalid source id");
 
   SetupFakeUI(true);
-  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
 }
 
 // Test that generating a stream with an invalid optional audio source id
 // succeed.
 TEST_F(MediaStreamDispatcherHostTest,
        GenerateStreamsWithInvalidOptionalAudioSourceId) {
-  StreamOptions options(true, true);
-  AddSourceIdConstraint("invalid source id", &options.optional_audio);
+  StreamControls controls(true, true);
+  controls.video.alternate_device_ids.push_back("invalid source id");
 
   SetupFakeUI(true);
-  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
 }
 
 TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsNoAvailableVideoDevice) {
   physical_video_devices_.clear();
   video_capture_device_factory_->set_number_of_devices(0);
   video_capture_device_factory_->GetDeviceNames(&physical_video_devices_);
-  StreamOptions options(true, true);
+  StreamControls controls(true, true);
 
   SetupFakeUI(false);
-  GenerateStreamAndWaitForFailure(kRenderId, kPageRequestId, options,
+  GenerateStreamAndWaitForFailure(kRenderId, kPageRequestId, controls,
                                   MEDIA_DEVICE_NO_HARDWARE);
 }
 
@@ -741,10 +724,10 @@
 // been opened in a MediaStream and by pepper, the device is only stopped for
 // the MediaStream.
 TEST_F(MediaStreamDispatcherHostTest, StopDeviceInStream) {
-  StreamOptions options(false, true);
+  StreamControls controls(false, true);
 
   SetupFakeUI(true);
-  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
 
   std::string stream_request_label = host_->label_;
   StreamDeviceInfo video_device_info = host_->video_devices_.front();
@@ -766,10 +749,10 @@
 }
 
 TEST_F(MediaStreamDispatcherHostTest, StopDeviceInStreamAndRestart) {
-  StreamOptions options(true, true);
+  StreamControls controls(true, true);
 
   SetupFakeUI(true);
-  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
 
   std::string request_label1 = host_->label_;
   StreamDeviceInfo video_device_info = host_->video_devices_.front();
@@ -781,7 +764,7 @@
   EXPECT_EQ(1u, media_stream_manager_->GetDevicesOpenedByRequest(
       request_label1).size());
 
-  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
   std::string request_label2 = host_->label_;
 
   StreamDeviceInfoArray request1_devices =
@@ -801,10 +784,10 @@
 
 TEST_F(MediaStreamDispatcherHostTest,
        GenerateTwoStreamsAndStopDeviceWhileWaitingForSecondStream) {
-  StreamOptions options(false, true);
+  StreamControls controls(false, true);
 
   SetupFakeUI(true);
-  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
   EXPECT_EQ(host_->video_devices_.size(), 1u);
 
   // Generate a second stream.
@@ -812,7 +795,7 @@
               OnStreamGenerated(kRenderId, kPageRequestId + 1, 0, 1));
 
   base::RunLoop run_loop1;
-  host_->OnGenerateStream(kRenderId, kPageRequestId + 1, options, origin_,
+  host_->OnGenerateStream(kRenderId, kPageRequestId + 1, controls, origin_,
                           run_loop1.QuitClosure());
 
   // Stop the video stream device from stream 1 while waiting for the
@@ -824,14 +807,14 @@
 }
 
 TEST_F(MediaStreamDispatcherHostTest, CancelPendingStreamsOnChannelClosing) {
-  StreamOptions options(false, true);
+  StreamControls controls(false, true);
 
   base::RunLoop run_loop;
 
   // Create multiple GenerateStream requests.
   size_t streams = 5;
   for (size_t i = 1; i <= streams; ++i) {
-    host_->OnGenerateStream(kRenderId, kPageRequestId + i, options, origin_,
+    host_->OnGenerateStream(kRenderId, kPageRequestId + i, controls, origin_,
                             run_loop.QuitClosure());
   }
 
@@ -841,13 +824,13 @@
 }
 
 TEST_F(MediaStreamDispatcherHostTest, StopGeneratedStreamsOnChannelClosing) {
-  StreamOptions options(false, true);
+  StreamControls controls(false, true);
 
   // Create first group of streams.
   size_t generated_streams = 3;
   for (size_t i = 0; i < generated_streams; ++i) {
     SetupFakeUI(true);
-    GenerateStreamAndWaitForResult(kRenderId, kPageRequestId + i, options);
+    GenerateStreamAndWaitForResult(kRenderId, kPageRequestId + i, controls);
   }
 
   // Calling OnChannelClosing() to cancel all the pending/generated streams.
@@ -856,7 +839,7 @@
 }
 
 TEST_F(MediaStreamDispatcherHostTest, CloseFromUI) {
-  StreamOptions options(false, true);
+  StreamControls controls(false, true);
 
   base::Closure close_callback;
   scoped_ptr<MockMediaStreamUIProxy> stream_ui(new MockMediaStreamUIProxy());
@@ -864,7 +847,7 @@
       .WillOnce(SaveArg<0>(&close_callback));
   media_stream_manager_->UseFakeUIForTests(stream_ui.Pass());
 
-  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
 
   EXPECT_EQ(host_->audio_devices_.size(), 0u);
   EXPECT_EQ(host_->video_devices_.size(), 1u);
@@ -878,9 +861,9 @@
 // Test that the dispatcher is notified if a video device that is in use is
 // being unplugged.
 TEST_F(MediaStreamDispatcherHostTest, VideoDeviceUnplugged) {
-  StreamOptions options(true, true);
+  StreamControls controls(true, true);
   SetupFakeUI(true);
-  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
   EXPECT_EQ(host_->audio_devices_.size(), 1u);
   EXPECT_EQ(host_->video_devices_.size(), 1u);
 
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index f35c8dc..3c2bd841 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -88,22 +88,17 @@
   return label;
 }
 
-void ParseStreamType(const StreamOptions& options,
+void ParseStreamType(const StreamControls& controls,
                      MediaStreamType* audio_type,
                      MediaStreamType* video_type) {
   *audio_type = MEDIA_NO_SERVICE;
   *video_type = MEDIA_NO_SERVICE;
-  if (options.audio_requested) {
-     std::string audio_stream_source;
-     bool mandatory = false;
-     if (options.GetFirstAudioConstraintByName(kMediaStreamSource,
-                                               &audio_stream_source,
-                                               &mandatory)) {
-       DCHECK(mandatory);
+  if (controls.audio.requested) {
+    if (!controls.audio.stream_source.empty()) {
        // This is tab or screen capture.
-       if (audio_stream_source == kMediaStreamSourceTab) {
+       if (controls.audio.stream_source == kMediaStreamSourceTab) {
          *audio_type = content::MEDIA_TAB_AUDIO_CAPTURE;
-       } else if (audio_stream_source == kMediaStreamSourceSystem) {
+       } else if (controls.audio.stream_source == kMediaStreamSourceSystem) {
          *audio_type = content::MEDIA_DESKTOP_AUDIO_CAPTURE;
        }
      } else {
@@ -111,43 +106,36 @@
        *audio_type = MEDIA_DEVICE_AUDIO_CAPTURE;
      }
   }
-  if (options.video_requested) {
-     std::string video_stream_source;
-     bool mandatory = false;
-     if (options.GetFirstVideoConstraintByName(kMediaStreamSource,
-                                               &video_stream_source,
-                                               &mandatory)) {
-       DCHECK(mandatory);
-       // This is tab or screen capture.
-       if (video_stream_source == kMediaStreamSourceTab) {
-         *video_type = content::MEDIA_TAB_VIDEO_CAPTURE;
-       } else if (video_stream_source == kMediaStreamSourceScreen) {
-         *video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE;
-       } else if (video_stream_source == kMediaStreamSourceDesktop) {
-         *video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE;
-       }
-     } else {
-       // This is normal video device capture.
-       *video_type = MEDIA_DEVICE_VIDEO_CAPTURE;
-     }
+  if (controls.video.requested) {
+    if (!controls.video.stream_source.empty()) {
+      // This is tab or screen capture.
+      if (controls.video.stream_source == kMediaStreamSourceTab) {
+        *video_type = content::MEDIA_TAB_VIDEO_CAPTURE;
+      } else if (controls.video.stream_source == kMediaStreamSourceScreen) {
+        *video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE;
+      } else if (controls.video.stream_source == kMediaStreamSourceDesktop) {
+        *video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE;
+      }
+    } else {
+      // This is normal video device capture.
+      *video_type = MEDIA_DEVICE_VIDEO_CAPTURE;
+    }
   }
 }
 
 // Turns off available audio effects (removes the flag) if the options
 // explicitly turn them off.
-void FilterAudioEffects(const StreamOptions& options, int* effects) {
+void FilterAudioEffects(const StreamControls& controls, int* effects) {
   DCHECK(effects);
   // TODO(ajm): Should we handle ECHO_CANCELLER here?
 }
 
 // Unlike other effects, hotword is off by default, so turn it on if it's
 // requested and available.
-void EnableHotwordEffect(const StreamOptions& options, int* effects) {
+void EnableHotwordEffect(const StreamControls& controls, int* effects) {
   DCHECK(effects);
+  if (controls.hotword_enabled) {
 #if defined(OS_CHROMEOS)
-  std::string value;
-  if (options.GetFirstAudioConstraintByName(
-          kMediaStreamAudioHotword, &value, NULL) && value == "true") {
     chromeos::AudioDeviceList devices;
     chromeos::CrasAudioHandler::Get()->GetAudioDevices(&devices);
     // Only enable if a hotword device exists.
@@ -157,8 +145,8 @@
         *effects |= media::AudioParameters::HOTWORD;
       }
     }
-  }
 #endif
+  }
 }
 
 // Private helper method to generate a string for the log message that lists the
@@ -212,7 +200,7 @@
                 const GURL& security_origin,
                 bool user_gesture,
                 MediaStreamRequestType request_type,
-                const StreamOptions& options,
+                const StreamControls& controls,
                 const ResourceContext::SaltCallback& salt_callback)
       : requester(requester),
         requesting_process_id(requesting_process_id),
@@ -221,14 +209,13 @@
         security_origin(security_origin),
         user_gesture(user_gesture),
         request_type(request_type),
-        options(options),
+        controls(controls),
         salt_callback(salt_callback),
         state_(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_NOT_REQUESTED),
         audio_type_(MEDIA_NO_SERVICE),
         video_type_(MEDIA_NO_SERVICE),
         target_process_id_(-1),
-        target_frame_id_(-1) {
-  }
+        target_frame_id_(-1) {}
 
   ~DeviceRequest() {}
 
@@ -340,7 +327,7 @@
 
   const MediaStreamRequestType request_type;
 
-  const StreamOptions options;
+  const StreamControls controls;
 
   ResourceContext::SaltCallback salt_callback;
 
@@ -457,22 +444,18 @@
     int render_process_id,
     int render_frame_id,
     int page_request_id,
-    const StreamOptions& options,
+    const StreamControls& controls,
     const GURL& security_origin,
     const MediaRequestResponseCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   // TODO(perkj): The argument list with NULL parameters to DeviceRequest
   // suggests that this is the wrong design. Can this be refactored?
-  DeviceRequest* request = new DeviceRequest(NULL,
-                                             render_process_id,
-                                             render_frame_id,
-                                             page_request_id,
-                                             security_origin,
-                                             false,  // user gesture
-                                             MEDIA_DEVICE_ACCESS,
-                                             options,
-                                             base::Bind(&ReturnEmptySalt));
+  DeviceRequest* request = new DeviceRequest(
+      NULL, render_process_id, render_frame_id, page_request_id,
+      security_origin,
+      false,  // user gesture
+      MEDIA_DEVICE_ACCESS, controls, base::Bind(&ReturnEmptySalt));
 
   const std::string& label = AddRequest(request);
 
@@ -494,21 +477,15 @@
                                         int render_frame_id,
                                         const ResourceContext::SaltCallback& sc,
                                         int page_request_id,
-                                        const StreamOptions& options,
+                                        const StreamControls& controls,
                                         const GURL& security_origin,
                                         bool user_gesture) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DVLOG(1) << "GenerateStream()";
 
-  DeviceRequest* request = new DeviceRequest(requester,
-                                             render_process_id,
-                                             render_frame_id,
-                                             page_request_id,
-                                             security_origin,
-                                             user_gesture,
-                                             MEDIA_GENERATE_STREAM,
-                                             options,
-                                             sc);
+  DeviceRequest* request = new DeviceRequest(
+      requester, render_process_id, render_frame_id, page_request_id,
+      security_origin, user_gesture, MEDIA_GENERATE_STREAM, controls, sc);
 
   const std::string& label = AddRequest(request);
 
@@ -688,15 +665,11 @@
          type == MEDIA_DEVICE_VIDEO_CAPTURE ||
          type == MEDIA_DEVICE_AUDIO_OUTPUT);
 
-  DeviceRequest* request = new DeviceRequest(requester,
-                                             render_process_id,
-                                             render_frame_id,
-                                             page_request_id,
-                                             security_origin,
-                                             false,  // user gesture
-                                             MEDIA_ENUMERATE_DEVICES,
-                                             StreamOptions(),
-                                             sc);
+  DeviceRequest* request =
+      new DeviceRequest(requester, render_process_id, render_frame_id,
+                        page_request_id, security_origin,
+                        false,  // user gesture
+                        MEDIA_ENUMERATE_DEVICES, StreamControls(), sc);
   if (IsAudioInputMediaType(type) || type == MEDIA_DEVICE_AUDIO_OUTPUT)
     request->SetAudioType(type);
   else if (IsVideoMediaType(type))
@@ -809,15 +782,13 @@
   DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
          type == MEDIA_DEVICE_VIDEO_CAPTURE);
   DVLOG(1) << "OpenDevice ({page_request_id = " << page_request_id <<  "})";
-  StreamOptions options;
+  StreamControls controls;
   if (IsAudioInputMediaType(type)) {
-    options.audio_requested = true;
-    options.mandatory_audio.push_back(
-        StreamOptions::Constraint(kMediaStreamSourceInfoId, device_id));
+    controls.audio.requested = true;
+    controls.audio.device_ids.push_back(device_id);
   } else if (IsVideoMediaType(type)) {
-    options.video_requested = true;
-    options.mandatory_video.push_back(
-        StreamOptions::Constraint(kMediaStreamSourceInfoId, device_id));
+    controls.video.requested = true;
+    controls.video.device_ids.push_back(device_id);
   } else {
     NOTREACHED();
   }
@@ -825,7 +796,7 @@
       new DeviceRequest(requester, render_process_id, render_frame_id,
                         page_request_id, security_origin,
                         false,  // user gesture
-                        MEDIA_OPEN_DEVICE_PEPPER_ONLY, options, sc);
+                        MEDIA_OPEN_DEVICE_PEPPER_ONLY, controls, sc);
 
   const std::string& label = AddRequest(request);
   // Post a task and handle the request asynchronously. The reason is that the
@@ -997,56 +968,55 @@
 }
 #endif
 
+// Pick the first valid (translatable) device ID from lists of required
+// and optional IDs.
+bool MediaStreamManager::PickDeviceId(
+    MediaStreamType type,
+    const ResourceContext::SaltCallback& salt_callback,
+    const GURL& security_origin,
+    const TrackControls& controls,
+    std::string* device_id) const {
+  if (!controls.device_ids.empty()) {
+    if (controls.device_ids.size() > 1) {
+      LOG(ERROR) << "Only one required device ID is supported";
+      return false;
+    }
+    const std::string& candidate_id = controls.device_ids[0];
+    if (!TranslateSourceIdToDeviceId(type, salt_callback, security_origin,
+                                     candidate_id, device_id)) {
+      LOG(WARNING) << "Invalid mandatory capture ID = " << candidate_id;
+      return false;
+    }
+    return true;
+  }
+  // We don't have a required ID. Look at the alternates.
+  for (const std::string& candidate_id : controls.alternate_device_ids) {
+    if (TranslateSourceIdToDeviceId(type, salt_callback, security_origin,
+                                    candidate_id, device_id)) {
+      return true;
+    } else {
+      LOG(WARNING) << "Invalid optional capture ID = " << candidate_id;
+    }
+  }
+  return true;  // If we get here, device_id is empty.
+}
+
 bool MediaStreamManager::GetRequestedDeviceCaptureId(
     const DeviceRequest* request,
     MediaStreamType type,
     std::string* device_id) const {
-  DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
-         type == MEDIA_DEVICE_VIDEO_CAPTURE);
-  const StreamOptions::Constraints* mandatory =
-      (type == MEDIA_DEVICE_AUDIO_CAPTURE) ?
-          &request->options.mandatory_audio : &request->options.mandatory_video;
-  const StreamOptions::Constraints* optional =
-      (type == MEDIA_DEVICE_AUDIO_CAPTURE) ?
-          &request->options.optional_audio : &request->options.optional_video;
-
-  std::vector<std::string> source_ids;
-  StreamOptions::GetConstraintsByName(*mandatory,
-                                      kMediaStreamSourceInfoId, &source_ids);
-  if (source_ids.size() > 1) {
-    LOG(ERROR) << "Only one mandatory " << kMediaStreamSourceInfoId
-        << " is supported.";
-    return false;
+  if (type == MEDIA_DEVICE_AUDIO_CAPTURE) {
+    return PickDeviceId(type, request->salt_callback, request->security_origin,
+                        request->controls.audio,
+                        device_id);
+  } else if (type == MEDIA_DEVICE_VIDEO_CAPTURE) {
+    return PickDeviceId(type, request->salt_callback, request->security_origin,
+                        request->controls.video,
+                        device_id);
+  } else {
+    NOTREACHED();
   }
-  // If a specific device has been requested we need to find the real device
-  // id.
-  if (source_ids.size() == 1 &&
-      !TranslateSourceIdToDeviceId(type,
-                                   request->salt_callback,
-                                   request->security_origin,
-                                   source_ids[0], device_id)) {
-    LOG(WARNING) << "Invalid mandatory " << kMediaStreamSourceInfoId
-                 << " = " << source_ids[0] << ".";
-    return false;
-  }
-  // Check for optional audio sourceIDs.
-  if (device_id->empty()) {
-    StreamOptions::GetConstraintsByName(*optional,
-                                        kMediaStreamSourceInfoId,
-                                        &source_ids);
-    // Find the first sourceID that translates to device. Note that only one
-    // device per type can call to GenerateStream is ever opened.
-    for (const std::string& source_id : source_ids) {
-      if (TranslateSourceIdToDeviceId(type,
-                                      request->salt_callback,
-                                      request->security_origin,
-                                      source_id,
-                                      device_id)) {
-        break;
-      }
-    }
-  }
-  return true;
+  return false;
 }
 
 void MediaStreamManager::TranslateDeviceIdToSourceId(
@@ -1211,7 +1181,7 @@
 
   MediaStreamType audio_type = MEDIA_NO_SERVICE;
   MediaStreamType video_type = MEDIA_NO_SERVICE;
-  ParseStreamType(request->options, &audio_type, &video_type);
+  ParseStreamType(request->controls, &audio_type, &video_type);
   request->SetAudioType(audio_type);
   request->SetVideoType(video_type);
 
@@ -1272,22 +1242,22 @@
          (request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE ||
           request->video_type() == MEDIA_NO_SERVICE));
   std::string audio_device_id;
-  if (request->options.audio_requested &&
+  if (request->controls.audio.requested &&
       !GetRequestedDeviceCaptureId(request, request->audio_type(),
-                                     &audio_device_id)) {
+                                   &audio_device_id)) {
     return false;
   }
 
   std::string video_device_id;
-  if (request->options.video_requested &&
+  if (request->controls.video.requested &&
       !GetRequestedDeviceCaptureId(request, request->video_type(),
                                    &video_device_id)) {
     return false;
   }
   request->CreateUIRequest(audio_device_id, video_device_id);
-  DVLOG(3) << "Audio requested " << request->options.audio_requested
-           << " device id = " << audio_device_id
-           << "Video requested " << request->options.video_requested
+  DVLOG(3) << "Audio requested " << request->controls.audio.requested
+           << " device id = " << audio_device_id << "Video requested "
+           << request->controls.video.requested
            << " device id = " << video_device_id;
   return true;
 }
@@ -1297,19 +1267,15 @@
          request->video_type() == MEDIA_TAB_VIDEO_CAPTURE);
 
   std::string capture_device_id;
-  bool mandatory_audio = false;
-  bool mandatory_video = false;
-  if (!request->options.GetFirstAudioConstraintByName(kMediaStreamSourceId,
-                                                      &capture_device_id,
-                                                      &mandatory_audio) &&
-      !request->options.GetFirstVideoConstraintByName(kMediaStreamSourceId,
-                                                      &capture_device_id,
-                                                      &mandatory_video)) {
+  if (!request->controls.audio.device_ids.empty()) {
+    capture_device_id = request->controls.audio.device_ids[0];
+  } else if (!request->controls.video.device_ids.empty()) {
+    capture_device_id = request->controls.video.device_ids[0];
+  } else {
     return false;
   }
-  DCHECK(mandatory_audio || mandatory_video);
 
-  // Customize options for a WebContents based capture.
+  // Customize controls for a WebContents based capture.
   int target_render_process_id = 0;
   int target_render_frame_id = 0;
 
@@ -1351,26 +1317,12 @@
 
   std::string video_device_id;
   if (request->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE) {
-    std::string video_stream_source;
-    bool mandatory = false;
-    if (!request->options.GetFirstVideoConstraintByName(
-        kMediaStreamSource,
-        &video_stream_source,
-        &mandatory)) {
-      LOG(ERROR) << kMediaStreamSource << " not found.";
-      return false;
-    }
-    DCHECK(mandatory);
+    const std::string& video_stream_source =
+        request->controls.video.stream_source;
 
-    if (video_stream_source == kMediaStreamSourceDesktop) {
-      if (!request->options.GetFirstVideoConstraintByName(
-          kMediaStreamSourceId,
-          &video_device_id,
-          &mandatory)) {
-        LOG(ERROR) << kMediaStreamSourceId << " not found.";
-        return false;
-      }
-      DCHECK(mandatory);
+    if (video_stream_source == kMediaStreamSourceDesktop &&
+        !request->controls.video.device_ids.empty()) {
+      video_device_id = request->controls.video.device_ids[0];
     }
   }
 
@@ -1409,9 +1361,9 @@
           *existing_device_info = device_info;
           // Make sure that the audio |effects| reflect what the request
           // is set to and not what the capabilities are.
-          FilterAudioEffects(request->options,
-              &existing_device_info->device.input.effects);
-          EnableHotwordEffect(request->options,
+          FilterAudioEffects(request->controls,
+                             &existing_device_info->device.input.effects);
+          EnableHotwordEffect(request->controls,
                               &existing_device_info->device.input.effects);
           *existing_request_state = request->state(device_info.device.type);
           return true;
@@ -1666,9 +1618,9 @@
             // parameters to the default settings (including supported effects),
             // we need to adjust those settings here according to what the
             // request asks for.
-            FilterAudioEffects(request->options,
+            FilterAudioEffects(request->controls,
                                &device_info.device.input.effects);
-            EnableHotwordEffect(request->options,
+            EnableHotwordEffect(request->controls,
                                 &device_info.device.input.effects);
 
             device_info.device.matched_output = info->device.matched_output;
diff --git a/content/browser/renderer_host/media/media_stream_manager.h b/content/browser/renderer_host/media/media_stream_manager.h
index 9b5ef12f..b5bde44 100644
--- a/content/browser/renderer_host/media/media_stream_manager.h
+++ b/content/browser/renderer_host/media/media_stream_manager.h
@@ -102,7 +102,7 @@
       int render_process_id,
       int render_frame_id,
       int page_request_id,
-      const StreamOptions& options,
+      const StreamControls& controls,
       const GURL& security_origin,
       const MediaRequestResponseCallback& callback);
 
@@ -115,7 +115,7 @@
                       int render_frame_id,
                       const ResourceContext::SaltCallback& sc,
                       int page_request_id,
-                      const StreamOptions& components,
+                      const StreamControls& controls,
                       const GURL& security_origin,
                       bool user_gesture);
 
@@ -306,15 +306,15 @@
   void SetupRequest(const std::string& label);
   // Prepare |request| of type MEDIA_DEVICE_AUDIO_CAPTURE and/or
   // MEDIA_DEVICE_VIDEO_CAPTURE for being posted to the UI by parsing
-  // StreamOptions::Constraints for requested device IDs.
+  // StreamControls for requested device IDs.
   bool SetupDeviceCaptureRequest(DeviceRequest* request);
   // Prepare |request| of type MEDIA_TAB_AUDIO_CAPTURE and/or
   // MEDIA_TAB_VIDEO_CAPTURE for being posted to the UI by parsing
-  // StreamOptions::Constraints for requested tab capture IDs.
+  // StreamControls for requested tab capture IDs.
   bool SetupTabCaptureRequest(DeviceRequest* request);
   // Prepare |request| of type MEDIA_DESKTOP_AUDIO_CAPTURE and/or
   // MEDIA_DESKTOP_VIDEO_CAPTURE for being posted to the UI by parsing
-  // StreamOptions::Constraints for the requested desktop ID.
+  // StreamControls for the requested desktop ID.
   bool SetupScreenCaptureRequest(DeviceRequest* request);
   // Called when a request has been setup and devices have been enumerated if
   // needed.
@@ -360,7 +360,19 @@
   void StartMonitoringOnUIThread();
 #endif
 
-  // Finds the requested device id from constraints. The requested device type
+  // Picks a device ID from a list of required and alternate device IDs,
+  // presented as part of a TrackControls structure.
+  // Either the required device ID is picked (if present), or the first
+  // valid alternate device ID.
+  // Returns false if the required device ID is present and invalid.
+  // Otherwise, if no valid device is found, device_id is unchanged.
+  bool PickDeviceId(MediaStreamType type,
+                    const ResourceContext::SaltCallback& salt_callback,
+                    const GURL& security_origin,
+                    const TrackControls& controls,
+                    std::string* device_id) const;
+
+  // Finds the requested device id from request. The requested device type
   // must be MEDIA_DEVICE_AUDIO_CAPTURE or MEDIA_DEVICE_VIDEO_CAPTURE.
   bool GetRequestedDeviceCaptureId(const DeviceRequest* request,
                                    MediaStreamType type,
diff --git a/content/browser/renderer_host/media/media_stream_manager_unittest.cc b/content/browser/renderer_host/media/media_stream_manager_unittest.cc
index cdf857a..0be6883 100644
--- a/content/browser/renderer_host/media/media_stream_manager_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_manager_unittest.cc
@@ -190,13 +190,10 @@
     MediaStreamManager::MediaRequestResponseCallback callback =
         base::Bind(&MediaStreamManagerTest::ResponseCallback,
                    base::Unretained(this), index);
-    StreamOptions options(true, true);
-    return media_stream_manager_->MakeMediaAccessRequest(render_process_id,
-                                                         render_frame_id,
-                                                         page_request_id,
-                                                         options,
-                                                         security_origin,
-                                                         callback);
+    StreamControls controls(true, true);
+    return media_stream_manager_->MakeMediaAccessRequest(
+        render_process_id, render_frame_id, page_request_id, controls,
+        security_origin, callback);
   }
 
   scoped_ptr<MockAudioManager> audio_manager_;
@@ -234,17 +231,13 @@
   int render_frame_id = 2;
   int page_request_id = 2;
   GURL security_origin;
-  StreamOptions options(true, true);
+  StreamControls controls(true, true);
   MediaStreamManager::MediaRequestResponseCallback callback =
       base::Bind(&MediaStreamManagerTest::ResponseCallback,
                  base::Unretained(this), 1);
   std::string label2 = media_stream_manager_->MakeMediaAccessRequest(
-      render_process_id,
-      render_frame_id,
-      page_request_id,
-      options,
-      security_origin,
-      callback);
+      render_process_id, render_frame_id, page_request_id, controls,
+      security_origin, callback);
 
   // Expecting the callbackS from requests will be triggered and quit the test.
   // Note, the callbacks might come in a different order depending on the
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index bc4737e4..14c9458 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1130,6 +1130,10 @@
 }
 #endif
 
+bool RenderProcessHostImpl::IsProcessBackgrounded() const {
+  return is_process_backgrounded_;
+}
+
 void RenderProcessHostImpl::AddRoute(int32 routing_id,
                                      IPC::Listener* listener) {
   CHECK(!listeners_.Lookup(routing_id)) << "Found Routing ID Conflict: "
@@ -2472,17 +2476,20 @@
                                          Source<RenderProcessHost>(this),
                                          NotificationService::NoDetails());
 
-#if defined(MOJO_SHELL_CLIENT)
-  // Send the mojo shell handle to the renderer.
-  SendExternalMojoShellHandleToChild(GetHandle(), this);
-#endif
-
   if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk") &&
       child_process_launcher_.get()) {
     base::ProcessHandle process_handle =
         child_process_launcher_->GetProcess().Handle();
-    mojo::embedder::ScopedPlatformHandle client_pipe =
-        mojo::embedder::ChildProcessLaunched(process_handle);
+    mojo::embedder::ScopedPlatformHandle client_pipe;
+#if defined(MOJO_SHELL_CLIENT)
+    if (IsRunningInMojoShell()) {
+      client_pipe = RegisterProcessWithBroker(
+          child_process_launcher_->GetProcess().Pid());
+    } else
+#endif
+    {
+      client_pipe = mojo::embedder::ChildProcessLaunched(process_handle);
+    }
     Send(new ChildProcessMsg_SetMojoParentPipeHandle(
         IPC::GetFileHandleForProcess(
 #if defined(OS_WIN)
@@ -2493,6 +2500,11 @@
                                      process_handle, true)));
   }
 
+#if defined(MOJO_SHELL_CLIENT)
+  // Send the mojo shell handle to the renderer.
+  SendExternalMojoShellHandleToChild(GetHandle(), this);
+#endif
+
   // Allow Mojo to be setup before the renderer sees any Chrome IPC messages.
   // This way, Mojo can be safely used from the renderer in response to any
   // Chrome IPC message.
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index f3050d9..635332d 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -162,6 +162,7 @@
   scoped_refptr<media::MediaKeys> GetCdm(int render_frame_id,
                                          int cdm_id) const override;
 #endif
+  bool IsProcessBackgrounded() const override;
 
   // IPC::Sender via RenderProcessHost.
   bool Send(IPC::Message* msg) override;
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 051a7bc..846b49e 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -985,7 +985,7 @@
       return;
   }
 
-  if (IgnoreInputEvents())
+  if (ShouldDropInputEvents())
     return;
 
   if (touch_emulator_ && touch_emulator_->HandleMouseEvent(mouse_event))
@@ -1018,7 +1018,7 @@
   TRACE_EVENT2("input", "RenderWidgetHostImpl::ForwardWheelEvent",
                "dx", wheel_event.deltaX, "dy", wheel_event.deltaY);
 
-  if (IgnoreInputEvents())
+  if (ShouldDropInputEvents())
     return;
 
   if (touch_emulator_ && touch_emulator_->HandleMouseWheelEvent(wheel_event))
@@ -1039,7 +1039,7 @@
     const ui::LatencyInfo& ui_latency) {
   TRACE_EVENT0("input", "RenderWidgetHostImpl::ForwardGestureEvent");
   // Early out if necessary, prior to performing latency logic.
-  if (IgnoreInputEvents())
+  if (ShouldDropInputEvents())
     return;
 
   // TODO(wjmaclean) Remove the code for supporting resending gesture events
@@ -1066,6 +1066,7 @@
         CreateScrollBeginForWrapping(gesture_event), ui::LatencyInfo());
   }
 
+  // Delegate must be non-null, due to |ShouldDropInputEvents()| test.
   if (delegate_->PreHandleGestureEvent(gesture_event))
     return;
 
@@ -1118,7 +1119,7 @@
     return;
   }
 
-  if (IgnoreInputEvents())
+  if (ShouldDropInputEvents())
     return;
 
   if (!process_->HasConnection())
@@ -1889,7 +1890,7 @@
   // Don't ignore touch cancel events, since they may be sent while input
   // events are being ignored in order to keep the renderer from getting
   // confused about how many touches are active.
-  if (IgnoreInputEvents() && event.type != WebInputEvent::TouchCancel)
+  if (ShouldDropInputEvents() && event.type != WebInputEvent::TouchCancel)
     return INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
 
   if (!process_->HasConnection())
@@ -1992,7 +1993,7 @@
 
   if (!is_hidden() && view_) {
     if (ack_result != INPUT_EVENT_ACK_STATE_CONSUMED &&
-        delegate_->HandleWheelEvent(wheel_event.event)) {
+        delegate_ && delegate_->HandleWheelEvent(wheel_event.event)) {
       ack_result = INPUT_EVENT_ACK_STATE_CONSUMED;
     }
     view_->WheelEventAck(wheel_event.event, ack_result);
@@ -2035,8 +2036,8 @@
   Send(new InputMsg_SyntheticGestureCompleted(GetRoutingID()));
 }
 
-bool RenderWidgetHostImpl::IgnoreInputEvents() const {
-  return ignore_input_events_ || process_->IgnoreInputEvents();
+bool RenderWidgetHostImpl::ShouldDropInputEvents() const {
+  return ignore_input_events_ || process_->IgnoreInputEvents() || !delegate_;
 }
 
 void RenderWidgetHostImpl::SetBackgroundOpaque(bool opaque) {
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 678c422..3587de9 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -352,9 +352,8 @@
     return ignore_input_events_;
   }
 
-  // Whether forwarded WebInputEvents should be ignored.  True if either
-  // |ignore_input_events_| or |process_->IgnoreInputEvents()| is true.
-  bool IgnoreInputEvents() const;
+  // Whether forwarded WebInputEvents should be dropped.
+  bool ShouldDropInputEvents() const;
 
   bool has_touch_handler() const { return has_touch_handler_; }
 
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index 70cacc1..83b3d6f 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -1653,4 +1653,24 @@
   EXPECT_TRUE(host_->resize_ack_pending_);
 }
 
+// Tests that event dispatch after the delegate has been detached doesn't cause
+// a crash. See crbug.com/563237.
+TEST_F(RenderWidgetHostTest, EventDispatchPostDetach) {
+  host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
+  process_->sink().ClearMessages();
+
+  host_->DetachDelegate();
+
+  // Tests RWHI::ForwardGestureEventWithLatencyInfo().
+  SimulateGestureEventWithLatencyInfo(WebInputEvent::GestureScrollUpdate,
+                                      blink::WebGestureDeviceTouchscreen,
+                                      ui::LatencyInfo());
+
+
+  // Tests RWHI::ForwardWheelEventWithLatencyInfo().
+  SimulateWheelEventWithLatencyInfo(-5, 0, 0, true, ui::LatencyInfo());
+
+  ASSERT_FALSE(host_->input_router()->HasPendingEvents());
+}
+
 }  // namespace content
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 76f405a..b1822efe 100644
--- a/content/browser/renderer_host/render_widget_host_view_mus.cc
+++ b/content/browser/renderer_host/render_widget_host_view_mus.cc
@@ -12,7 +12,9 @@
 #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/client/screen_position_client.h"
 #include "ui/aura/window.h"
+#include "ui/base/hit_test.h"
 
 namespace blink {
 struct WebScreenInfo;
@@ -20,17 +22,15 @@
 
 namespace content {
 
-RenderWidgetHostViewMus::RenderWidgetHostViewMus(
-    mus::Window* parent_window,
-    RenderWidgetHostImpl* host,
-    base::WeakPtr<RenderWidgetHostViewBase> platform_view)
-    : host_(host), platform_view_(platform_view) {
+RenderWidgetHostViewMus::RenderWidgetHostViewMus(mus::Window* parent_window,
+                                                 RenderWidgetHostImpl* host)
+    : host_(host), aura_window_(nullptr) {
   DCHECK(parent_window);
   mus::Window* window = parent_window->connection()->NewWindow();
   window->SetVisible(true);
   window->SetBounds(gfx::Rect(300, 300));
   parent_window->AddChild(window);
-  window_.reset(new mus::ScopedWindowPtr(window));
+  mus_window_.reset(new mus::ScopedWindowPtr(window));
   host_->SetView(this);
 
   // Connect to the renderer, pass it a WindowTreeClient interface request
@@ -42,11 +42,18 @@
   mus::mojom::WindowTreeClientPtr window_tree_client;
   factory->CreateWindowTreeClientForRenderWidget(
       host_->GetRoutingID(), mojo::GetProxy(&window_tree_client));
-  window_->window()->Embed(window_tree_client.Pass());
+  mus_window_->window()->Embed(window_tree_client.Pass());
 }
 
 RenderWidgetHostViewMus::~RenderWidgetHostViewMus() {}
 
+void RenderWidgetHostViewMus::InternalSetBounds(const gfx::Rect& rect) {
+  aura_window_->SetBounds(rect);
+  gfx::Rect bounds = aura_window_->GetBoundsInRootWindow();
+  mus_window_->window()->SetBounds(bounds);
+  host_->WasResized();
+}
+
 void RenderWidgetHostViewMus::Show() {
   // TODO(fsamuel): Update visibility in Mus.
   // There is some interstitial complexity that we'll need to figure out here.
@@ -62,15 +69,28 @@
 }
 
 void RenderWidgetHostViewMus::SetSize(const gfx::Size& size) {
-  platform_view_->SetSize(size);
-  gfx::Rect bounds = platform_view_->GetNativeView()->GetBoundsInRootWindow();
-  window_->window()->SetBounds(bounds);
+  // For a SetSize operation, we don't care what coordinate system the origin
+  // of the window is in, it's only important to make sure that the origin
+  // remains constant after the operation.
+  InternalSetBounds(gfx::Rect(aura_window_->bounds().origin(), size));
 }
 
 void RenderWidgetHostViewMus::SetBounds(const gfx::Rect& rect) {
-  platform_view_->SetBounds(rect);
-  gfx::Rect bounds = platform_view_->GetNativeView()->GetBoundsInRootWindow();
-  window_->window()->SetBounds(bounds);
+  gfx::Point relative_origin(rect.origin());
+
+  // RenderWidgetHostViewMus::SetBounds() takes screen coordinates, but
+  // Window::SetBounds() takes parent coordinates, so do the conversion here.
+  aura::Window* root = aura_window_->GetRootWindow();
+  if (root) {
+    aura::client::ScreenPositionClient* screen_position_client =
+        aura::client::GetScreenPositionClient(root);
+    if (screen_position_client) {
+      screen_position_client->ConvertPointFromScreen(aura_window_->parent(),
+                                                     &relative_origin);
+    }
+  }
+
+  InternalSetBounds(gfx::Rect(relative_origin, rect.size()));
 }
 
 void RenderWidgetHostViewMus::Focus() {
@@ -89,7 +109,7 @@
 }
 
 gfx::Rect RenderWidgetHostViewMus::GetViewBounds() const {
-  return platform_view_->GetViewBounds();
+  return aura_window_->GetBoundsInScreen();
 }
 
 gfx::Vector2dF RenderWidgetHostViewMus::GetLastScrollOffset() const {
@@ -98,13 +118,11 @@
 
 void RenderWidgetHostViewMus::RenderProcessGone(base::TerminationStatus status,
                                                 int error_code) {
-  // TODO(fsamuel): Figure out the interstitial lifetime issues here.
-  platform_view_->Destroy();
+  NOTIMPLEMENTED();
 }
 
 void RenderWidgetHostViewMus::Destroy() {
-  if (platform_view_)  // The platform view might have been destroyed already.
-    platform_view_->Destroy();
+  delete aura_window_;
 }
 
 gfx::Size RenderWidgetHostViewMus::GetPhysicalBackingSize() const {
@@ -112,7 +130,8 @@
 }
 
 base::string16 RenderWidgetHostViewMus::GetSelectedText() const {
-  return platform_view_->GetSelectedText();
+  NOTIMPLEMENTED();
+  return base::string16();
 }
 
 void RenderWidgetHostViewMus::SetTooltipText(
@@ -121,7 +140,14 @@
 }
 
 void RenderWidgetHostViewMus::InitAsChild(gfx::NativeView parent_view) {
-  platform_view_->InitAsChild(parent_view);
+  aura_window_ = new aura::Window(nullptr);
+  aura_window_->SetType(ui::wm::WINDOW_TYPE_CONTROL);
+  aura_window_->Init(ui::LAYER_SOLID_COLOR);
+  aura_window_->SetName("RenderWidgetHostViewMus");
+  aura_window_->layer()->SetColor(background_color_);
+
+  if (parent_view)
+    parent_view->AddChild(GetNativeView());
 }
 
 RenderWidgetHost* RenderWidgetHostViewMus::GetRenderWidgetHost() const {
@@ -140,7 +166,7 @@
 }
 
 gfx::NativeView RenderWidgetHostViewMus::GetNativeView() const {
-  return platform_view_->GetNativeView();
+  return aura_window_;
 }
 
 gfx::NativeViewId RenderWidgetHostViewMus::GetNativeViewId() const {
@@ -153,7 +179,6 @@
 
 void RenderWidgetHostViewMus::MovePluginWindows(
     const std::vector<WebPluginGeometry>& moves) {
-  platform_view_->MovePluginWindows(moves);
 }
 
 void RenderWidgetHostViewMus::UpdateCursor(const WebCursor& cursor) {
@@ -162,7 +187,6 @@
 }
 
 void RenderWidgetHostViewMus::SetIsLoading(bool is_loading) {
-  platform_view_->SetIsLoading(is_loading);
 }
 
 void RenderWidgetHostViewMus::TextInputStateChanged(
@@ -183,7 +207,6 @@
 void RenderWidgetHostViewMus::SelectionChanged(const base::string16& text,
                                                size_t offset,
                                                const gfx::Range& range) {
-  platform_view_->SelectionChanged(text, offset, range);
 }
 
 void RenderWidgetHostViewMus::SelectionBoundsChanged(
@@ -242,21 +265,20 @@
 }
 
 gfx::Rect RenderWidgetHostViewMus::GetBoundsInRootWindow() {
-  return platform_view_->GetBoundsInRootWindow();
+  aura::Window* top_level = aura_window_->GetToplevelWindow();
+  gfx::Rect bounds(top_level->GetBoundsInScreen());
+  return bounds;
 }
 
 #if defined(OS_MACOSX)
 void RenderWidgetHostViewMus::SetActive(bool active) {
-  platform_view_->SetActive(active);
 }
 
 void RenderWidgetHostViewMus::SetWindowVisibility(bool visible) {
   // TODO(fsamuel): Propagate visibility to Mus?
-  platform_view_->SetWindowVisibility(visible);
 }
 
 void RenderWidgetHostViewMus::WindowFrameChanged() {
-  platform_view_->WindowFrameChanged();
 }
 
 void RenderWidgetHostViewMus::ShowDefinitionForSelection() {
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 4029668..ca110e8 100644
--- a/content/browser/renderer_host/render_widget_host_view_mus.h
+++ b/content/browser/renderer_host/render_widget_host_view_mus.h
@@ -28,13 +28,16 @@
 // the renderer from Mus.
 class CONTENT_EXPORT RenderWidgetHostViewMus : public RenderWidgetHostViewBase {
  public:
-  RenderWidgetHostViewMus(
-      mus::Window* parent_window,
-      RenderWidgetHostImpl* widget,
-      base::WeakPtr<RenderWidgetHostViewBase> platform_view);
+  RenderWidgetHostViewMus(mus::Window* parent_window,
+                          RenderWidgetHostImpl* widget);
   ~RenderWidgetHostViewMus() override;
 
  private:
+  // Set the bounds of the window and handle size changes.  Assumes the caller
+  // has already adjusted the origin of |rect| to conform to whatever coordinate
+  // space is required by the aura::Window.
+  void InternalSetBounds(const gfx::Rect& rect);
+
   // RenderWidgetHostView implementation.
   void InitAsChild(gfx::NativeView parent_view) override;
   RenderWidgetHost* GetRenderWidgetHost() const override;
@@ -123,11 +126,10 @@
 #endif
 
   RenderWidgetHostImpl* host_;
-  scoped_ptr<mus::ScopedWindowPtr> window_;
-  // The platform view for this RenderWidgetHostView.
-  // RenderWidgetHostViewMus mostly only cares about stuff related to
-  // compositing, the rest are directly forwared to this |platform_view_|.
-  base::WeakPtr<RenderWidgetHostViewBase> platform_view_;
+
+  aura::Window* aura_window_;
+
+  scoped_ptr<mus::ScopedWindowPtr> mus_window_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewMus);
 };
diff --git a/content/browser/renderer_host/sandbox_ipc_linux.cc b/content/browser/renderer_host/sandbox_ipc_linux.cc
index 966f350..b77ec14 100644
--- a/content/browser/renderer_host/sandbox_ipc_linux.cc
+++ b/content/browser/renderer_host/sandbox_ipc_linux.cc
@@ -14,7 +14,6 @@
 #include "base/files/scoped_file.h"
 #include "base/linux_util.h"
 #include "base/macros.h"
-#include "base/memory/scoped_vector.h"
 #include "base/memory/shared_memory.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/posix/unix_domain_socket_linux.h"
@@ -123,7 +122,7 @@
 }
 
 void SandboxIPCHandler::HandleRequestFromRenderer(int fd) {
-  ScopedVector<base::ScopedFD> fds;
+  std::vector<base::ScopedFD> fds;
 
   // A FontConfigIPC::METHOD_MATCH message could be kMaxFontFamilyLength
   // bytes long (this is the largest message type).
@@ -149,19 +148,19 @@
     return;
 
   if (kind == FontConfigIPC::METHOD_MATCH) {
-    HandleFontMatchRequest(fd, iter, fds.get());
+    HandleFontMatchRequest(fd, iter, fds);
   } else if (kind == FontConfigIPC::METHOD_OPEN) {
-    HandleFontOpenRequest(fd, iter, fds.get());
+    HandleFontOpenRequest(fd, iter, fds);
   } else if (kind == LinuxSandbox::METHOD_GET_FALLBACK_FONT_FOR_CHAR) {
-    HandleGetFallbackFontForChar(fd, iter, fds.get());
+    HandleGetFallbackFontForChar(fd, iter, fds);
   } else if (kind == LinuxSandbox::METHOD_LOCALTIME) {
-    HandleLocaltime(fd, iter, fds.get());
+    HandleLocaltime(fd, iter, fds);
   } else if (kind == LinuxSandbox::METHOD_GET_STYLE_FOR_STRIKE) {
-    HandleGetStyleForStrike(fd, iter, fds.get());
+    HandleGetStyleForStrike(fd, iter, fds);
   } else if (kind == LinuxSandbox::METHOD_MAKE_SHARED_MEMORY_SEGMENT) {
-    HandleMakeSharedMemorySegment(fd, iter, fds.get());
+    HandleMakeSharedMemorySegment(fd, iter, fds);
   } else if (kind == LinuxSandbox::METHOD_MATCH_WITH_FALLBACK) {
-    HandleMatchWithFallback(fd, iter, fds.get());
+    HandleMatchWithFallback(fd, iter, fds);
   }
 }
 
@@ -178,7 +177,7 @@
 void SandboxIPCHandler::HandleFontMatchRequest(
     int fd,
     base::PickleIterator iter,
-    const std::vector<base::ScopedFD*>& fds) {
+    const std::vector<base::ScopedFD>& fds) {
   uint32_t requested_style;
   std::string family;
   if (!iter.ReadString(&family) || !iter.ReadUInt32(&requested_style))
@@ -216,7 +215,7 @@
 void SandboxIPCHandler::HandleFontOpenRequest(
     int fd,
     base::PickleIterator iter,
-    const std::vector<base::ScopedFD*>& fds) {
+    const std::vector<base::ScopedFD>& fds) {
   uint32_t index;
   if (!iter.ReadUInt32(&index))
     return;
@@ -244,7 +243,7 @@
 void SandboxIPCHandler::HandleGetFallbackFontForChar(
     int fd,
     base::PickleIterator iter,
-    const std::vector<base::ScopedFD*>& fds) {
+    const std::vector<base::ScopedFD>& fds) {
   // The other side of this call is
   // content/common/child_process_sandbox_support_impl_linux.cc
 
@@ -284,7 +283,7 @@
 void SandboxIPCHandler::HandleGetStyleForStrike(
     int fd,
     base::PickleIterator iter,
-    const std::vector<base::ScopedFD*>& fds) {
+    const std::vector<base::ScopedFD>& fds) {
   std::string family;
   bool bold, italic;
   uint16 pixel_size;
@@ -322,7 +321,7 @@
 void SandboxIPCHandler::HandleLocaltime(
     int fd,
     base::PickleIterator iter,
-    const std::vector<base::ScopedFD*>& fds) {
+    const std::vector<base::ScopedFD>& fds) {
   // The other side of this call is in zygote_main_linux.cc
 
   std::string time_string;
@@ -352,7 +351,7 @@
 void SandboxIPCHandler::HandleMakeSharedMemorySegment(
     int fd,
     base::PickleIterator iter,
-    const std::vector<base::ScopedFD*>& fds) {
+    const std::vector<base::ScopedFD>& fds) {
   base::SharedMemoryCreateOptions options;
   uint32_t size;
   if (!iter.ReadUInt32(&size))
@@ -371,7 +370,7 @@
 void SandboxIPCHandler::HandleMatchWithFallback(
     int fd,
     base::PickleIterator iter,
-    const std::vector<base::ScopedFD*>& fds) {
+    const std::vector<base::ScopedFD>& fds) {
   std::string face;
   bool is_bold, is_italic;
   uint32 charset, fallback_family;
@@ -397,7 +396,7 @@
 }
 
 void SandboxIPCHandler::SendRendererReply(
-    const std::vector<base::ScopedFD*>& fds,
+    const std::vector<base::ScopedFD>& fds,
     const base::Pickle& reply,
     int reply_fd) {
   struct msghdr msg;
@@ -428,7 +427,7 @@
     msg.msg_controllen = cmsg->cmsg_len;
   }
 
-  if (HANDLE_EINTR(sendmsg(fds[0]->get(), &msg, MSG_DONTWAIT)) < 0)
+  if (HANDLE_EINTR(sendmsg(fds[0].get(), &msg, MSG_DONTWAIT)) < 0)
     PLOG(ERROR) << "sendmsg";
 }
 
diff --git a/content/browser/renderer_host/sandbox_ipc_linux.h b/content/browser/renderer_host/sandbox_ipc_linux.h
index 23a65e0..0d647049 100644
--- a/content/browser/renderer_host/sandbox_ipc_linux.h
+++ b/content/browser/renderer_host/sandbox_ipc_linux.h
@@ -37,33 +37,33 @@
 
   void HandleFontMatchRequest(int fd,
                               base::PickleIterator iter,
-                              const std::vector<base::ScopedFD*>& fds);
+                              const std::vector<base::ScopedFD>& fds);
 
   void HandleFontOpenRequest(int fd,
                              base::PickleIterator iter,
-                             const std::vector<base::ScopedFD*>& fds);
+                             const std::vector<base::ScopedFD>& fds);
 
   void HandleGetFallbackFontForChar(int fd,
-                                  base::PickleIterator iter,
-                                  const std::vector<base::ScopedFD*>& fds);
+                                    base::PickleIterator iter,
+                                    const std::vector<base::ScopedFD>& fds);
 
   void HandleGetStyleForStrike(int fd,
                                base::PickleIterator iter,
-                               const std::vector<base::ScopedFD*>& fds);
+                               const std::vector<base::ScopedFD>& fds);
 
   void HandleLocaltime(int fd,
                        base::PickleIterator iter,
-                       const std::vector<base::ScopedFD*>& fds);
+                       const std::vector<base::ScopedFD>& fds);
 
   void HandleMakeSharedMemorySegment(int fd,
                                      base::PickleIterator iter,
-                                     const std::vector<base::ScopedFD*>& fds);
+                                     const std::vector<base::ScopedFD>& fds);
 
   void HandleMatchWithFallback(int fd,
                                base::PickleIterator iter,
-                               const std::vector<base::ScopedFD*>& fds);
+                               const std::vector<base::ScopedFD>& fds);
 
-  void SendRendererReply(const std::vector<base::ScopedFD*>& fds,
+  void SendRendererReply(const std::vector<base::ScopedFD>& fds,
                          const base::Pickle& reply,
                          int reply_fd);
 
diff --git a/content/browser/service_worker/service_worker_context_request_handler_unittest.cc b/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
index e790ad9..5241a8d 100644
--- a/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
+++ b/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
@@ -95,8 +95,8 @@
           provider_host_,
           base::WeakPtr<storage::BlobStorageContext>(),
           RESOURCE_TYPE_SERVICE_WORKER));
-  scoped_refptr<net::URLRequestJob> job =
-      handler->MaybeCreateJob(request.get(), nullptr, nullptr);
+  scoped_ptr<net::URLRequestJob> job(
+      handler->MaybeCreateJob(request.get(), nullptr, nullptr));
   ASSERT_TRUE(job.get());
   ServiceWorkerWriteToCacheJob* sw_job =
       static_cast<ServiceWorkerWriteToCacheJob*>(job.get());
@@ -123,8 +123,8 @@
           provider_host_,
           base::WeakPtr<storage::BlobStorageContext>(),
           RESOURCE_TYPE_SERVICE_WORKER));
-  scoped_refptr<net::URLRequestJob> job =
-      handler->MaybeCreateJob(request.get(), nullptr, nullptr);
+  scoped_ptr<net::URLRequestJob> job(
+      handler->MaybeCreateJob(request.get(), nullptr, nullptr));
   ASSERT_TRUE(job.get());
   ServiceWorkerWriteToCacheJob* sw_job =
       static_cast<ServiceWorkerWriteToCacheJob*>(job.get());
@@ -150,8 +150,8 @@
           context()->AsWeakPtr(), provider_host_,
           base::WeakPtr<storage::BlobStorageContext>(),
           RESOURCE_TYPE_SERVICE_WORKER));
-  scoped_refptr<net::URLRequestJob> job =
-      handler->MaybeCreateJob(request.get(), nullptr, nullptr);
+  scoped_ptr<net::URLRequestJob> job(
+      handler->MaybeCreateJob(request.get(), nullptr, nullptr));
   ASSERT_TRUE(job.get());
   ServiceWorkerWriteToCacheJob* sw_job =
       static_cast<ServiceWorkerWriteToCacheJob*>(job.get());
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc
index ac41e003..3c3cb45 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/service_worker/service_worker_controllee_request_handler.h"
 
+#include "base/memory/scoped_ptr.h"
 #include "base/trace_event/trace_event.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_metrics.h"
@@ -97,10 +98,10 @@
   }
 
   // It's for original request (A) or redirect case (B-a or B-b).
-  ServiceWorkerURLRequestJob* job = new ServiceWorkerURLRequestJob(
+  scoped_ptr<ServiceWorkerURLRequestJob> job(new ServiceWorkerURLRequestJob(
       request, network_delegate, blob_storage_context_, resource_context,
       request_mode_, credentials_mode_, redirect_mode_, is_main_resource_load_,
-      request_context_type_, frame_type_, body_, this);
+      request_context_type_, frame_type_, body_, this));
   job_ = job->GetWeakPtr();
 
   resource_context_ = resource_context;
@@ -120,15 +121,11 @@
     if (!is_main_resource_load_)
       use_network_ = true;
 
-    // TODO(mmenke): Make job a scoped_ptr once URLRequestJobs are no longer
-    // reference counted.
-    scoped_refptr<ServiceWorkerURLRequestJob> owned_job(job);
+    job.reset();
     ClearJob();
-
-    return NULL;
   }
 
-  return job;
+  return job.release();
 }
 
 void ServiceWorkerControlleeRequestHandler::GetExtraResponseInfo(
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.h b/content/browser/service_worker/service_worker_controllee_request_handler.h
index 7832ba9..dca78ef 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.h
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.h
@@ -6,6 +6,9 @@
 #define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CONTROLLEE_REQUEST_HANDLER_H_
 
 #include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "content/browser/service_worker/service_worker_request_handler.h"
 #include "content/browser/service_worker/service_worker_url_request_job.h"
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
index b338ac8..3fe7fb1 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
@@ -129,8 +129,8 @@
           FetchRedirectMode::FOLLOW_MODE, RESOURCE_TYPE_MAIN_FRAME,
           REQUEST_CONTEXT_TYPE_HYPERLINK, REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
           scoped_refptr<ResourceRequestBody>()));
-  scoped_refptr<net::URLRequestJob> job =
-      handler->MaybeCreateJob(request.get(), NULL, &mock_resource_context_);
+  scoped_ptr<net::URLRequestJob> job(
+      handler->MaybeCreateJob(request.get(), nullptr, &mock_resource_context_));
   ServiceWorkerURLRequestJob* sw_job =
       static_cast<ServiceWorkerURLRequestJob*>(job.get());
 
@@ -169,8 +169,8 @@
           FetchRedirectMode::FOLLOW_MODE, RESOURCE_TYPE_MAIN_FRAME,
           REQUEST_CONTEXT_TYPE_HYPERLINK, REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
           scoped_refptr<ResourceRequestBody>()));
-  scoped_refptr<net::URLRequestJob> job =
-      handler->MaybeCreateJob(request.get(), NULL, &mock_resource_context_);
+  scoped_ptr<net::URLRequestJob> job(
+      handler->MaybeCreateJob(request.get(), nullptr, &mock_resource_context_));
   ServiceWorkerURLRequestJob* sw_job =
       static_cast<ServiceWorkerURLRequestJob*>(job.get());
 
@@ -217,8 +217,8 @@
           FetchRedirectMode::FOLLOW_MODE, RESOURCE_TYPE_MAIN_FRAME,
           REQUEST_CONTEXT_TYPE_HYPERLINK, REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
           scoped_refptr<ResourceRequestBody>()));
-  scoped_refptr<net::URLRequestJob> job =
-      handler->MaybeCreateJob(request.get(), NULL, &mock_resource_context_);
+  scoped_ptr<net::URLRequestJob> job(
+      handler->MaybeCreateJob(request.get(), nullptr, &mock_resource_context_));
   ServiceWorkerURLRequestJob* sw_job =
       static_cast<ServiceWorkerURLRequestJob*>(job.get());
 
diff --git a/content/browser/service_worker/service_worker_process_manager.cc b/content/browser/service_worker/service_worker_process_manager.cc
index d0c3a5d..04b2dc24 100644
--- a/content/browser/service_worker/service_worker_process_manager.cc
+++ b/content/browser/service_worker/service_worker_process_manager.cc
@@ -27,15 +27,6 @@
 
 }  // namespace
 
-static bool IncrementWorkerRefCountByPid(int process_id) {
-  RenderProcessHost* rph = RenderProcessHost::FromID(process_id);
-  if (!rph || rph->FastShutdownStarted())
-    return false;
-
-  static_cast<RenderProcessHostImpl*>(rph)->IncrementWorkerRefCount();
-  return true;
-}
-
 ServiceWorkerProcessManager::ProcessInfo::ProcessInfo(
     const scoped_refptr<SiteInstance>& site_instance)
     : site_instance(site_instance),
@@ -176,10 +167,11 @@
   DCHECK(!ContainsKey(instance_info_, embedded_worker_id))
       << embedded_worker_id << " already has a process allocated";
 
-  std::vector<int> sorted_candidates = SortProcessesForPattern(pattern);
-  for (int process_id : sorted_candidates) {
-    if (!IncrementWorkerRefCountByPid(process_id))
-      continue;
+  int process_id = FindAvailableProcess(pattern);
+  if (process_id != -1) {
+    RenderProcessHost* rph = RenderProcessHost::FromID(process_id);
+    DCHECK(rph);
+    static_cast<RenderProcessHostImpl*>(rph)->IncrementWorkerRefCount();
     instance_info_.insert(
         std::make_pair(embedded_worker_id, ProcessInfo(process_id)));
     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
@@ -192,6 +184,7 @@
   scoped_refptr<SiteInstance> site_instance =
       SiteInstance::CreateForURL(browser_context_, script_url);
   RenderProcessHost* rph = site_instance->GetProcess();
+
   // This Init() call posts a task to the IO thread that adds the RPH's
   // ServiceWorkerDispatcherHost to the
   // EmbeddedWorkerRegistry::process_sender_map_.
@@ -261,6 +254,8 @@
   if (it == pattern_processes_.end())
     return std::vector<int>();
 
+  // Prioritize higher refcount processes to choose the process which has more
+  // tabs and is less likely to be backgrounded by user action like tab close.
   std::vector<std::pair<int, int> > counted(
       it->second.begin(), it->second.end());
   std::sort(counted.begin(), counted.end(), SecondGreater());
@@ -271,6 +266,33 @@
   return result;
 }
 
+int ServiceWorkerProcessManager::FindAvailableProcess(const GURL& pattern) {
+  RenderProcessHost* backgrounded_candidate = nullptr;
+
+  // Try to find an available foreground process.
+  std::vector<int> sorted_candidates = SortProcessesForPattern(pattern);
+  for (int process_id : sorted_candidates) {
+    RenderProcessHost* rph = RenderProcessHost::FromID(process_id);
+    if (!rph || rph->FastShutdownStarted())
+      continue;
+
+    // Keep a backgrounded process for a suboptimal choice.
+    if (rph->IsProcessBackgrounded()) {
+      if (!backgrounded_candidate)
+        backgrounded_candidate = rph;
+      continue;
+    }
+
+    return process_id;
+  }
+
+  // No foreground processes available; choose a backgrounded one.
+  if (backgrounded_candidate)
+    return backgrounded_candidate->GetID();
+
+  return -1;
+}
+
 }  // namespace content
 
 namespace std {
diff --git a/content/browser/service_worker/service_worker_process_manager.h b/content/browser/service_worker/service_worker_process_manager.h
index cc368b5..17af1e8 100644
--- a/content/browser/service_worker/service_worker_process_manager.h
+++ b/content/browser/service_worker/service_worker_process_manager.h
@@ -77,6 +77,8 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerProcessManagerTest, SortProcess);
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerProcessManagerTest,
+                           FindAvailableProcess);
+  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerProcessManagerTest,
                            AllocateWorkerProcess_InShutdown);
 
   // Information about the process for an EmbeddedWorkerInstance.
@@ -109,6 +111,10 @@
   // Returns a process vector sorted by the reference count for the |pattern|.
   std::vector<int> SortProcessesForPattern(const GURL& pattern) const;
 
+  // Returns the id of an available process for this pattern, or -1 if there is
+  // none.
+  int FindAvailableProcess(const GURL& pattern);
+
   // These fields are only accessed on the UI thread.
   BrowserContext* browser_context_;
 
diff --git a/content/browser/service_worker/service_worker_process_manager_unittest.cc b/content/browser/service_worker/service_worker_process_manager_unittest.cc
index 37c0d8d9..9f3826ac 100644
--- a/content/browser/service_worker/service_worker_process_manager_unittest.cc
+++ b/content/browser/service_worker/service_worker_process_manager_unittest.cc
@@ -6,6 +6,8 @@
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "content/browser/service_worker/service_worker_process_manager.h"
+#include "content/public/test/mock_render_process_host.h"
+#include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -35,14 +37,24 @@
   ServiceWorkerProcessManagerTest() {}
 
   void SetUp() override {
-    process_manager_.reset(new ServiceWorkerProcessManager(NULL));
+    browser_context_.reset(new TestBrowserContext);
+    process_manager_.reset(
+        new ServiceWorkerProcessManager(browser_context_.get()));
     pattern_ = GURL("http://www.example.com/");
     script_url_ = GURL("http://www.example.com/sw.js");
   }
 
-  void TearDown() override { process_manager_.reset(); }
+  void TearDown() override {
+    process_manager_->Shutdown();
+    process_manager_.reset();
+  }
+
+  scoped_ptr<MockRenderProcessHost> CreateRenderProcessHost() {
+    return make_scoped_ptr(new MockRenderProcessHost(browser_context_.get()));
+  }
 
  protected:
+  scoped_ptr<TestBrowserContext> browser_context_;
   scoped_ptr<ServiceWorkerProcessManager> process_manager_;
   GURL pattern_;
   GURL script_url_;
@@ -53,7 +65,7 @@
 };
 
 TEST_F(ServiceWorkerProcessManagerTest, SortProcess) {
-  // Process 1 has 2 ref, 2 has 3 refs and 3 has 1 refs.
+  // Process 1 has 2 refs, 2 has 3 refs and 3 has 1 ref.
   process_manager_->AddProcessReferenceToPattern(pattern_, 1);
   process_manager_->AddProcessReferenceToPattern(pattern_, 1);
   process_manager_->AddProcessReferenceToPattern(pattern_, 2);
@@ -72,7 +84,40 @@
               testing::ElementsAre(2, 3));
 }
 
+TEST_F(ServiceWorkerProcessManagerTest, FindAvailableProcess) {
+  scoped_ptr<MockRenderProcessHost> host1(CreateRenderProcessHost());
+  scoped_ptr<MockRenderProcessHost> host2(CreateRenderProcessHost());
+  scoped_ptr<MockRenderProcessHost> host3(CreateRenderProcessHost());
+
+  // Process 1 has 2 refs, 2 has 3 refs and 3 has 1 ref.
+  process_manager_->AddProcessReferenceToPattern(pattern_, host1->GetID());
+  process_manager_->AddProcessReferenceToPattern(pattern_, host1->GetID());
+  process_manager_->AddProcessReferenceToPattern(pattern_, host2->GetID());
+  process_manager_->AddProcessReferenceToPattern(pattern_, host2->GetID());
+  process_manager_->AddProcessReferenceToPattern(pattern_, host2->GetID());
+  process_manager_->AddProcessReferenceToPattern(pattern_, host3->GetID());
+
+  // When all processes are in foreground, process 2 that has the highest
+  // refcount should be chosen.
+  EXPECT_EQ(host2->GetID(), process_manager_->FindAvailableProcess(pattern_));
+
+  // Backgrounded process 2 should be deprioritized.
+  host2->set_is_process_backgrounded(true);
+  EXPECT_EQ(host1->GetID(), process_manager_->FindAvailableProcess(pattern_));
+
+  // When all processes are in background, process 2 that has the highest
+  // refcount should be chosen.
+  host1->set_is_process_backgrounded(true);
+  host3->set_is_process_backgrounded(true);
+  EXPECT_EQ(host2->GetID(), process_manager_->FindAvailableProcess(pattern_));
+
+  // Process 3 should be chosen because it is the only foreground process.
+  host3->set_is_process_backgrounded(false);
+  EXPECT_EQ(host3->GetID(), process_manager_->FindAvailableProcess(pattern_));
+}
+
 TEST_F(ServiceWorkerProcessManagerTest, AllocateWorkerProcess_InShutdown) {
+  process_manager_->Shutdown();
   ASSERT_TRUE(process_manager_->IsShutdown());
 
   base::RunLoop run_loop;
diff --git a/content/browser/service_worker/service_worker_read_from_cache_job.cc b/content/browser/service_worker/service_worker_read_from_cache_job.cc
index 6aa92af8..8ce3d8f 100644
--- a/content/browser/service_worker/service_worker_read_from_cache_job.cc
+++ b/content/browser/service_worker/service_worker_read_from_cache_job.cc
@@ -152,7 +152,6 @@
 }
 
 void ServiceWorkerReadFromCacheJob::OnReadInfoComplete(int result) {
-  scoped_refptr<ServiceWorkerReadFromCacheJob> protect(this);
   if (!http_info_io_buffer_->http_info) {
     DCHECK_LT(result, 0);
     ServiceWorkerMetrics::CountReadResponseResult(
diff --git a/content/browser/service_worker/service_worker_url_request_job.cc b/content/browser/service_worker/service_worker_url_request_job.cc
index 2cf8207..277d775f 100644
--- a/content/browser/service_worker/service_worker_url_request_job.cc
+++ b/content/browser/service_worker/service_worker_url_request_job.cc
@@ -4,6 +4,9 @@
 
 #include "content/browser/service_worker/service_worker_url_request_job.h"
 
+#include <stdint.h>
+
+#include <limits>
 #include <map>
 #include <string>
 #include <vector>
@@ -135,6 +138,20 @@
   DCHECK(delegate_) << "ServiceWorkerURLRequestJob requires a delegate";
 }
 
+ServiceWorkerURLRequestJob::~ServiceWorkerURLRequestJob() {
+  ClearStream();
+
+  if (!ShouldRecordResult())
+    return;
+  ServiceWorkerMetrics::URLRequestJobResult result =
+      ServiceWorkerMetrics::REQUEST_JOB_ERROR_KILLED;
+  if (response_body_type_ == STREAM)
+    result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_KILLED_WITH_STREAM;
+  else if (response_body_type_ == BLOB)
+    result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_KILLED_WITH_BLOB;
+  RecordResult(result);
+}
+
 void ServiceWorkerURLRequestJob::FallbackToNetwork() {
   DCHECK_EQ(NOT_DETERMINED, response_type_);
   response_type_ = FALLBACK_TO_NETWORK;
@@ -367,20 +384,6 @@
   return http_response_info_.get();
 }
 
-ServiceWorkerURLRequestJob::~ServiceWorkerURLRequestJob() {
-  ClearStream();
-
-  if (!ShouldRecordResult())
-    return;
-  ServiceWorkerMetrics::URLRequestJobResult result =
-      ServiceWorkerMetrics::REQUEST_JOB_ERROR_KILLED;
-  if (response_body_type_ == STREAM)
-    result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_KILLED_WITH_STREAM;
-  else if (response_body_type_ == BLOB)
-    result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_KILLED_WITH_BLOB;
-  RecordResult(result);
-}
-
 void ServiceWorkerURLRequestJob::MaybeStartRequest() {
   if (is_started_ && response_type_ != NOT_DETERMINED) {
     // Start asynchronously.
@@ -439,7 +442,7 @@
 scoped_ptr<ServiceWorkerFetchRequest>
 ServiceWorkerURLRequestJob::CreateFetchRequest() {
   std::string blob_uuid;
-  uint64 blob_size = 0;
+  uint64_t blob_size = 0;
   CreateRequestBodyBlob(&blob_uuid, &blob_size);
   scoped_ptr<ServiceWorkerFetchRequest> request(
       new ServiceWorkerFetchRequest());
@@ -475,7 +478,7 @@
 }
 
 bool ServiceWorkerURLRequestJob::CreateRequestBodyBlob(std::string* blob_uuid,
-                                                       uint64* blob_size) {
+                                                       uint64_t* blob_size) {
   if (!body_.get() || !blob_storage_context_)
     return false;
 
@@ -505,15 +508,16 @@
   }
 
   const std::string uuid(base::GenerateGUID());
-  uint64 total_size = 0;
+  uint64_t total_size = 0;
 
   storage::BlobDataBuilder blob_builder(uuid);
   for (size_t i = 0; i < resolved_elements.size(); ++i) {
     const ResourceRequestBody::Element& element = *resolved_elements[i];
-    if (total_size != kuint64max && element.length() != kuint64max)
+    if (total_size != std::numeric_limits<uint64_t>::max() &&
+        element.length() != std::numeric_limits<uint64_t>::max())
       total_size += element.length();
     else
-      total_size = kuint64max;
+      total_size = std::numeric_limits<uint64_t>::max();
     switch (element.type()) {
       case ResourceRequestBody::Element::TYPE_BYTES:
         blob_builder.AppendData(element.bytes(), element.length());
diff --git a/content/browser/service_worker/service_worker_url_request_job.h b/content/browser/service_worker/service_worker_url_request_job.h
index 3694f652..8a50a49d 100644
--- a/content/browser/service_worker/service_worker_url_request_job.h
+++ b/content/browser/service_worker/service_worker_url_request_job.h
@@ -108,6 +108,8 @@
       scoped_refptr<ResourceRequestBody> body,
       Delegate* delegate);
 
+  ~ServiceWorkerURLRequestJob() override;
+
   // Sets the response type.
   void FallbackToNetwork();
   void ForwardToServiceWorker();
@@ -156,9 +158,6 @@
 
   base::WeakPtr<ServiceWorkerURLRequestJob> GetWeakPtr();
 
- protected:
-  ~ServiceWorkerURLRequestJob() override;
-
  private:
   enum ResponseType {
     NOT_DETERMINED,
diff --git a/content/browser/shared_worker/shared_worker_instance.cc b/content/browser/shared_worker/shared_worker_instance.cc
index ea8e02db..caa3876 100644
--- a/content/browser/shared_worker/shared_worker_instance.cc
+++ b/content/browser/shared_worker/shared_worker_instance.cc
@@ -14,13 +14,15 @@
     const base::string16& content_security_policy,
     blink::WebContentSecurityPolicyType security_policy_type,
     ResourceContext* resource_context,
-    const WorkerStoragePartitionId& partition_id)
+    const WorkerStoragePartitionId& partition_id,
+    blink::WebSharedWorkerCreationContextType creation_context_type)
     : url_(url),
       name_(name),
       content_security_policy_(content_security_policy),
       security_policy_type_(security_policy_type),
       resource_context_(resource_context),
-      partition_id_(partition_id) {
+      partition_id_(partition_id),
+      creation_context_type_(creation_context_type) {
   DCHECK(resource_context_);
 }
 
@@ -30,8 +32,8 @@
       content_security_policy_(other.content_security_policy_),
       security_policy_type_(other.security_policy_type_),
       resource_context_(other.resource_context_),
-      partition_id_(other.partition_id_) {
-}
+      partition_id_(other.partition_id_),
+      creation_context_type_(other.creation_context_type_) {}
 
 SharedWorkerInstance::~SharedWorkerInstance() {}
 
diff --git a/content/browser/shared_worker/shared_worker_instance.h b/content/browser/shared_worker/shared_worker_instance.h
index 5d650e5..f3b3be6 100644
--- a/content/browser/shared_worker/shared_worker_instance.h
+++ b/content/browser/shared_worker/shared_worker_instance.h
@@ -11,6 +11,7 @@
 #include "content/browser/shared_worker/worker_storage_partition.h"
 #include "content/common/content_export.h"
 #include "third_party/WebKit/public/web/WebContentSecurityPolicy.h"
+#include "third_party/WebKit/public/web/WebSharedWorkerCreationContextType.h"
 #include "url/gurl.h"
 
 namespace content {
@@ -20,12 +21,14 @@
 // the UI thread and be used for comparison in SharedWorkerDevToolsManager.
 class CONTENT_EXPORT SharedWorkerInstance {
  public:
-  SharedWorkerInstance(const GURL& url,
-                       const base::string16& name,
-                       const base::string16& content_security_policy,
-                       blink::WebContentSecurityPolicyType security_policy_type,
-                       ResourceContext* resource_context,
-                       const WorkerStoragePartitionId& partition_id);
+  SharedWorkerInstance(
+      const GURL& url,
+      const base::string16& name,
+      const base::string16& content_security_policy,
+      blink::WebContentSecurityPolicyType security_policy_type,
+      ResourceContext* resource_context,
+      const WorkerStoragePartitionId& partition_id,
+      blink::WebSharedWorkerCreationContextType creation_context_type);
   SharedWorkerInstance(const SharedWorkerInstance& other);
   ~SharedWorkerInstance();
 
@@ -54,6 +57,9 @@
     return resource_context_;
   }
   const WorkerStoragePartitionId& partition_id() const { return partition_id_; }
+  blink::WebSharedWorkerCreationContextType creation_context_type() const {
+    return creation_context_type_;
+  }
 
  private:
   const GURL url_;
@@ -62,6 +68,7 @@
   const blink::WebContentSecurityPolicyType security_policy_type_;
   ResourceContext* const resource_context_;
   const WorkerStoragePartitionId partition_id_;
+  const blink::WebSharedWorkerCreationContextType creation_context_type_;
 };
 
 }  // namespace content
diff --git a/content/browser/shared_worker/shared_worker_instance_unittest.cc b/content/browser/shared_worker/shared_worker_instance_unittest.cc
index 7811e77..8991b05f 100644
--- a/content/browser/shared_worker/shared_worker_instance_unittest.cc
+++ b/content/browser/shared_worker/shared_worker_instance_unittest.cc
@@ -47,12 +47,11 @@
 };
 
 TEST_F(SharedWorkerInstanceTest, MatchesTest) {
-  SharedWorkerInstance instance1(GURL("http://example.com/w.js"),
-                                 base::string16(),
-                                 base::string16(),
-                                 blink::WebContentSecurityPolicyTypeReport,
-                                 browser_context_->GetResourceContext(),
-                                 partition_id_);
+  SharedWorkerInstance instance1(
+      GURL("http://example.com/w.js"), base::string16(), base::string16(),
+      blink::WebContentSecurityPolicyTypeReport,
+      browser_context_->GetResourceContext(), partition_id_,
+      blink::WebSharedWorkerCreationContextTypeNonsecure);
   EXPECT_TRUE(Matches(instance1, "http://example.com/w.js", ""));
   EXPECT_FALSE(Matches(instance1, "http://example.com/w2.js", ""));
   EXPECT_FALSE(Matches(instance1, "http://example.net/w.js", ""));
@@ -62,12 +61,11 @@
   EXPECT_FALSE(Matches(instance1, "http://example.net/w.js", "name"));
   EXPECT_FALSE(Matches(instance1, "http://example.net/w2.js", "name"));
 
-  SharedWorkerInstance instance2(GURL("http://example.com/w.js"),
-                                 base::ASCIIToUTF16("name"),
-                                 base::string16(),
-                                 blink::WebContentSecurityPolicyTypeReport,
-                                 browser_context_->GetResourceContext(),
-                                 partition_id_);
+  SharedWorkerInstance instance2(
+      GURL("http://example.com/w.js"), base::ASCIIToUTF16("name"),
+      base::string16(), blink::WebContentSecurityPolicyTypeReport,
+      browser_context_->GetResourceContext(), partition_id_,
+      blink::WebSharedWorkerCreationContextTypeNonsecure);
   EXPECT_FALSE(Matches(instance2, "http://example.com/w.js", ""));
   EXPECT_FALSE(Matches(instance2, "http://example.com/w2.js", ""));
   EXPECT_FALSE(Matches(instance2, "http://example.net/w.js", ""));
diff --git a/content/browser/shared_worker/shared_worker_service_impl.cc b/content/browser/shared_worker/shared_worker_service_impl.cc
index 4e71bde..91579b4 100644
--- a/content/browser/shared_worker/shared_worker_service_impl.cc
+++ b/content/browser/shared_worker/shared_worker_service_impl.cc
@@ -287,13 +287,10 @@
     blink::WebWorkerCreationError* creation_error) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   *creation_error = blink::WebWorkerCreationErrorNone;
-  scoped_ptr<SharedWorkerInstance> instance(
-      new SharedWorkerInstance(params.url,
-                               params.name,
-                               params.content_security_policy,
-                               params.security_policy_type,
-                               resource_context,
-                               partition_id));
+  scoped_ptr<SharedWorkerInstance> instance(new SharedWorkerInstance(
+      params.url, params.name, params.content_security_policy,
+      params.security_policy_type, resource_context, partition_id,
+      params.creation_context_type));
   scoped_ptr<SharedWorkerPendingInstance::SharedWorkerPendingRequest> request(
       new SharedWorkerPendingInstance::SharedWorkerPendingRequest(
           filter,
@@ -306,6 +303,11 @@
       *creation_error = blink::WebWorkerCreationErrorURLMismatch;
       return;
     }
+    if (params.creation_context_type !=
+        pending->instance()->creation_context_type()) {
+      *creation_error = blink::WebWorkerCreationErrorSecureContextMismatch;
+      return;
+    }
     pending->AddRequest(request.Pass());
     return;
   }
@@ -483,6 +485,12 @@
         *creation_error = blink::WebWorkerCreationErrorURLMismatch;
       return;
     }
+    if (pending_instance->instance()->creation_context_type() !=
+        host->instance()->creation_context_type()) {
+      if (creation_error)
+        *creation_error = blink::WebWorkerCreationErrorSecureContextMismatch;
+      return;
+    }
     worker_process_id = host->process_id();
     worker_route_id = host->worker_route_id();
     is_new_worker = false;
diff --git a/content/browser/shared_worker/shared_worker_service_impl_unittest.cc b/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
index 6fe97578..332490a 100644
--- a/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
+++ b/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
@@ -251,6 +251,8 @@
   params.security_policy_type = blink::WebContentSecurityPolicyTypeReport;
   params.document_id = document_id;
   params.render_frame_route_id = render_frame_route_id;
+  params.creation_context_type =
+      blink::WebSharedWorkerCreationContextTypeSecure;
   EXPECT_TRUE(
       renderer->OnMessageReceived(new ViewHostMsg_CreateWorker(params, reply)));
 }
diff --git a/content/browser/speech/speech_recognition_manager_impl.cc b/content/browser/speech/speech_recognition_manager_impl.cc
index 852cfea..5488e4cc 100644
--- a/content/browser/speech/speech_recognition_manager_impl.cc
+++ b/content/browser/speech/speech_recognition_manager_impl.cc
@@ -200,11 +200,8 @@
   if (ask_user) {
     SpeechRecognitionSessionContext& context = session->context;
     context.label = media_stream_manager_->MakeMediaAccessRequest(
-        context.render_process_id,
-        context.render_frame_id,
-        context.request_id,
-        StreamOptions(true, false),
-        GURL(context.context_name),
+        context.render_process_id, context.render_frame_id, context.request_id,
+        StreamControls(true, false), GURL(context.context_name),
         base::Bind(
             &SpeechRecognitionManagerImpl::MediaRequestPermissionCallback,
             weak_factory_.GetWeakPtr(), session_id));
diff --git a/content/browser/ssl/ssl_manager.cc b/content/browser/ssl/ssl_manager.cc
index cd6c2bea..c1b42f0 100644
--- a/content/browser/ssl/ssl_manager.cc
+++ b/content/browser/ssl/ssl_manager.cc
@@ -134,11 +134,7 @@
   NotifyDidChangeVisibleSSLState();
 }
 
-void SSLManager::DidDisplayInsecureContent() {
-  UpdateEntry(controller_->GetLastCommittedEntry());
-}
-
-void SSLManager::DidRunInsecureContent(const std::string& security_origin) {
+void SSLManager::DidRunInsecureContent(const GURL& security_origin) {
   NavigationEntryImpl* navigation_entry = controller_->GetLastCommittedEntry();
   policy()->DidRunInsecureContent(navigation_entry, security_origin);
   UpdateEntry(navigation_entry);
diff --git a/content/browser/ssl/ssl_manager.h b/content/browser/ssl/ssl_manager.h
index 6e46705..fb31a25 100644
--- a/content/browser/ssl/ssl_manager.h
+++ b/content/browser/ssl/ssl_manager.h
@@ -31,6 +31,7 @@
 struct LoadFromMemoryCacheDetails;
 struct ResourceRedirectDetails;
 struct ResourceRequestDetails;
+struct SSLStatus;
 
 // The SSLManager SSLManager controls the SSL UI elements in a WebContents.  It
 // listens for various events that influence when these elements should or
@@ -88,8 +89,7 @@
   void DidReceiveResourceRedirect(const ResourceRedirectDetails& details);
 
   // Insecure content entry point.
-  void DidDisplayInsecureContent();
-  void DidRunInsecureContent(const std::string& security_origin);
+  void DidRunInsecureContent(const GURL& security_origin);
 
  private:
   // Updates the NavigationEntry with our current state. This will
diff --git a/content/browser/ssl/ssl_policy.cc b/content/browser/ssl/ssl_policy.cc
index ed8d80b3..06677dc 100644
--- a/content/browser/ssl/ssl_policy.cc
+++ b/content/browser/ssl/ssl_policy.cc
@@ -105,7 +105,7 @@
 }
 
 void SSLPolicy::DidRunInsecureContent(NavigationEntryImpl* entry,
-                                      const std::string& security_origin) {
+                                      const GURL& security_origin) {
   if (!entry)
     return;
 
@@ -113,20 +113,16 @@
   if (!site_instance)
       return;
 
-  backend_->HostRanInsecureContent(GURL(security_origin).host(),
+  backend_->HostRanInsecureContent(security_origin.host(),
                                    site_instance->GetProcess()->GetID());
 }
 
 void SSLPolicy::OnRequestStarted(SSLRequestInfo* info) {
-  // TODO(abarth): This mechanism is wrong.  What we should be doing is sending
-  // this information back through WebKit and out some FrameLoaderClient
-  // methods.
-
-  if (net::IsCertStatusError(info->ssl_cert_status())) {
-    backend_->HostRanInsecureContent(info->url().host(), info->child_id());
-  } else if (info->ssl_cert_id() && info->url().SchemeIsCryptographic()) {
-    // If the scheme is https: or wss: *and* the security info for the cert has
-    // been set (i.e. the cert id is not 0), revoke any previous decisions that
+  if (info->ssl_cert_id() && info->url().SchemeIsCryptographic() &&
+      !net::IsCertStatusError(info->ssl_cert_status())) {
+    // If the scheme is https: or wss: *and* the security info for the
+    // cert has been set (i.e. the cert id is not 0) and the cert did
+    // not have any errors, revoke any previous decisions that
     // have occurred. If the cert info has not been set, do nothing since it
     // isn't known if the connection was actually a valid connection or if it
     // had a cert error.
diff --git a/content/browser/ssl/ssl_policy.h b/content/browser/ssl/ssl_policy.h
index 2855a1b..c002bfc 100644
--- a/content/browser/ssl/ssl_policy.h
+++ b/content/browser/ssl/ssl_policy.h
@@ -36,7 +36,7 @@
   void OnCertError(SSLCertErrorHandler* handler);
 
   void DidRunInsecureContent(NavigationEntryImpl* entry,
-                             const std::string& security_origin);
+                             const GURL& security_origin);
 
   // We have started a resource request with the given info.
   void OnRequestStarted(SSLRequestInfo* info);
diff --git a/content/browser/system_message_window_win.cc b/content/browser/system_message_window_win.cc
index 08f44cb6a..36cc177 100644
--- a/content/browser/system_message_window_win.cc
+++ b/content/browser/system_message_window_win.cc
@@ -45,7 +45,7 @@
     filter.dbcc_size = sizeof(filter);
     filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
     bool core_audio_support = media::CoreAudioUtil::IsSupported();
-    for (int i = 0; i < arraysize(kDeviceCategoryMap); ++i) {
+    for (size_t i = 0; i < arraysize(kDeviceCategoryMap); ++i) {
       // If CoreAudio is supported, AudioDeviceListenerWin will
       // take care of monitoring audio devices.
       if (core_audio_support &&
@@ -63,7 +63,7 @@
   }
 
   void Unregister() {
-    for (int i = 0; i < arraysize(notifications_); ++i) {
+    for (size_t i = 0; i < arraysize(notifications_); ++i) {
       if (notifications_[i]) {
         UnregisterDeviceNotification(notifications_[i]);
         notifications_[i] = NULL;
@@ -122,7 +122,7 @@
           reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(data);
       if (device_interface->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE)
         return TRUE;
-      for (int i = 0; i < arraysize(kDeviceCategoryMap); ++i) {
+      for (size_t i = 0; i < arraysize(kDeviceCategoryMap); ++i) {
         if (kDeviceCategoryMap[i].device_category ==
             device_interface->dbcc_classguid) {
           device_type = kDeviceCategoryMap[i].device_type;
diff --git a/content/browser/web_contents/aura/overscroll_window_delegate_unittest.cc b/content/browser/web_contents/aura/overscroll_window_delegate_unittest.cc
index 13382a8..15c9f88 100644
--- a/content/browser/web_contents/aura/overscroll_window_delegate_unittest.cc
+++ b/content/browser/web_contents/aura/overscroll_window_delegate_unittest.cc
@@ -54,11 +54,9 @@
 
   OverscrollMode current_mode() { return current_mode_; }
 
-  const float touch_start_threshold() {
-    return touch_start_threshold_;
-  }
+  float touch_start_threshold() { return touch_start_threshold_; }
 
-  const float touch_complete_threshold() {
+  float touch_complete_threshold() {
     return kTestWindowWidth * touch_complete_threshold_;
   }
 
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index fe78dfd..1ca34e2 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -47,9 +47,9 @@
 #include "content/browser/manifest/manifest_manager_host.h"
 #include "content/browser/media/audio_stream_monitor.h"
 #include "content/browser/media/capture/web_contents_audio_muter.h"
+#include "content/browser/media/media_web_contents_observer.h"
 #include "content/browser/message_port_message_filter.h"
 #include "content/browser/plugin_content_origin_whitelist.h"
-#include "content/browser/power_save_blocker_impl.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/renderer_host/render_view_host_delegate_view.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
@@ -91,7 +91,6 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents_delegate.h"
-#include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/bindings_policy.h"
 #include "content/public/common/browser_plugin_guest_mode.h"
 #include "content/public/common/content_constants.h"
@@ -115,10 +114,6 @@
 #include "ui/gfx/screen.h"
 #include "ui/gl/gl_switches.h"
 
-#if defined(ENABLE_BROWSER_CDMS)
-#include "content/browser/media/media_web_contents_observer.h"
-#endif
-
 #if defined(OS_ANDROID)
 #include "content/browser/android/content_video_view.h"
 #include "content/browser/media/android/media_session.h"
@@ -413,10 +408,7 @@
   frame_tree_.SetFrameRemoveListener(
       base::Bind(&WebContentsImpl::OnFrameRemoved,
                  base::Unretained(this)));
-#if defined(ENABLE_BROWSER_CDMS)
   media_web_contents_observer_.reset(new MediaWebContentsObserver(this));
-#endif
-
   wake_lock_service_context_.reset(new WakeLockServiceContext(this));
 }
 
@@ -433,8 +425,6 @@
   // Destroy all WebUI instances.
   frame_tree_.ForEach(base::Bind(&RenderFrameHostManager::ClearWebUIInstances));
 
-  ClearAllPowerSaveBlockers();
-
   for (std::set<RenderWidgetHostImpl*>::iterator iter =
            created_widgets_.begin(); iter != created_widgets_.end(); ++iter) {
     (*iter)->DetachDelegate();
@@ -633,10 +623,7 @@
     IPC_MESSAGE_HANDLER(FrameHostMsg_EndColorChooser, OnEndColorChooser)
     IPC_MESSAGE_HANDLER(FrameHostMsg_SetSelectedColorInColorChooser,
                         OnSetSelectedColorInColorChooser)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_MediaPlayingNotification,
-                        OnMediaPlayingNotification)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_MediaPausedNotification,
-                        OnMediaPausedNotification)
+
     IPC_MESSAGE_HANDLER(ViewHostMsg_DidFirstVisuallyNonEmptyPaint,
                         OnFirstVisuallyNonEmptyPaint)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidLoadResourceFromMemoryCache,
@@ -645,6 +632,10 @@
                         OnDidDisplayInsecureContent)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidRunInsecureContent,
                         OnDidRunInsecureContent)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_DidDisplayContentWithCertificateErrors,
+                        OnDidDisplayContentWithCertificateErrors)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_DidRunContentWithCertificateErrors,
+                        OnDidRunContentWithCertificateErrors)
     IPC_MESSAGE_HANDLER(ViewHostMsg_GoToEntryAtOffset, OnGoToEntryAtOffset)
     IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateZoomLimits, OnUpdateZoomLimits)
     IPC_MESSAGE_HANDLER(ViewHostMsg_PageScaleFactorChanged,
@@ -1165,16 +1156,10 @@
   tracked_objects::ScopedTracker tracking_profile(
       FROM_HERE_WITH_EXPLICIT_FUNCTION(
           "466285 WebContentsImpl::NotifyNavigationStateChanged"));
-  // Create and release the audio power save blocker depending on whether the
-  // tab is actively producing audio or not.
-  if ((changed_flags & INVALIDATE_TYPE_TAB) &&
-      AudioStreamMonitor::monitoring_available()) {
-    if (WasRecentlyAudible()) {
-      if (!audio_power_save_blocker_)
-        CreateAudioPowerSaveBlocker();
-    } else {
-      audio_power_save_blocker_.reset();
-    }
+  // Notify the media observer of potential audibility changes.
+  if (changed_flags & INVALIDATE_TYPE_TAB) {
+    media_web_contents_observer_->MaybeUpdateAudibleState(
+        AudioStreamMonitor::monitoring_available() && WasRecentlyAudible());
   }
 
   if (delegate_)
@@ -1211,10 +1196,6 @@
         GetRootWindowResizerRect(rvh->GetWidget()));
   }
 
-  // Restore power save blocker if there are active video players running.
-  if (!active_video_players_.empty() && !video_power_save_blocker_)
-    CreateVideoPowerSaveBlocker();
-
   FOR_EACH_OBSERVER(WebContentsObserver, observers_, WasShown());
 
   should_normally_be_visible_ = true;
@@ -1234,9 +1215,6 @@
       if (view)
         view->Hide();
     }
-
-    // Release any video power save blockers held as video is not visible.
-    video_power_save_blocker_.reset();
   }
 
   FOR_EACH_OBSERVER(WebContentsObserver, observers_, WasHidden());
@@ -1386,8 +1364,22 @@
   WebContentsViewDelegate* delegate =
       GetContentClient()->browser()->GetWebContentsViewDelegate(this);
 
-  view_.reset(
-      CreateWebContentsView(this, delegate, &render_view_host_delegate_view_));
+#if defined(MOJO_SHELL_CLIENT)
+  if (MojoShellConnection::Get() &&
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kUseMusInRenderer)) {
+    mus::Window* mus_window = aura::GetMusWindow(params.context);
+    if (mus_window) {
+      view_.reset(new WebContentsViewMus(mus_window, this, delegate,
+                                         &render_view_host_delegate_view_));
+    }
+  }
+#endif
+
+  if (!view_) {
+    view_.reset(CreateWebContentsView(this, delegate,
+                                      &render_view_host_delegate_view_));
+  }
 
   if (browser_plugin_guest_ &&
       !BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) {
@@ -1395,19 +1387,6 @@
                                          view_.Pass(),
                                          &render_view_host_delegate_view_));
   }
-
-#if defined(MOJO_SHELL_CLIENT)
-  if (MojoShellConnection::Get() &&
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kUseMusInRenderer)) {
-    mus::Window* window = aura::GetMusWindow(params.context);
-    if (window) {
-      view_.reset(new WebContentsViewMus(this, window, view_.Pass(),
-                                         &render_view_host_delegate_view_));
-    }
-  }
-#endif
-
   CHECK(render_view_host_delegate_view_);
   CHECK(view_.get());
 
@@ -3195,12 +3174,12 @@
       GetController().GetBrowserContext());
 }
 
-void WebContentsImpl::OnDidRunInsecureContent(
-    const std::string& security_origin, const GURL& target_url) {
+void WebContentsImpl::OnDidRunInsecureContent(const GURL& security_origin,
+                                              const GURL& target_url) {
   LOG(WARNING) << security_origin << " ran insecure content from "
                << target_url.possibly_invalid_spec();
   RecordAction(base::UserMetricsAction("SSL.RanInsecureContent"));
-  if (base::EndsWith(security_origin, kDotGoogleDotCom,
+  if (base::EndsWith(security_origin.spec(), kDotGoogleDotCom,
                      base::CompareCase::INSENSITIVE_ASCII))
     RecordAction(base::UserMetricsAction("SSL.RanInsecureContentGoogle"));
   controller_.ssl_manager()->DidRunInsecureContent(security_origin);
@@ -3208,6 +3187,39 @@
       GetController().GetBrowserContext());
 }
 
+void WebContentsImpl::OnDidDisplayContentWithCertificateErrors(
+    const GURL& url,
+    const std::string& security_info) {
+  SSLStatus ssl;
+  if (!DeserializeSecurityInfo(security_info, &ssl)) {
+    bad_message::ReceivedBadMessage(
+        GetRenderProcessHost(),
+        bad_message::WC_CONTENT_WITH_CERT_ERRORS_BAD_SECURITY_INFO);
+    return;
+  }
+
+  displayed_insecure_content_ = true;
+  SSLManager::NotifySSLInternalStateChanged(
+      GetController().GetBrowserContext());
+}
+
+void WebContentsImpl::OnDidRunContentWithCertificateErrors(
+    const GURL& security_origin,
+    const GURL& url,
+    const std::string& security_info) {
+  SSLStatus ssl;
+  if (!DeserializeSecurityInfo(security_info, &ssl)) {
+    bad_message::ReceivedBadMessage(
+        GetRenderProcessHost(),
+        bad_message::WC_CONTENT_WITH_CERT_ERRORS_BAD_SECURITY_INFO);
+    return;
+  }
+
+  controller_.ssl_manager()->DidRunInsecureContent(security_origin);
+  SSLManager::NotifySSLInternalStateChanged(
+      GetController().GetBrowserContext());
+}
+
 void WebContentsImpl::OnDocumentLoadedInFrame() {
   if (!HasValidFrameSource())
     return;
@@ -3470,78 +3482,6 @@
                     DidUpdateFaviconURL(candidates));
 }
 
-void WebContentsImpl::CreateAudioPowerSaveBlocker() {
-  DCHECK(!audio_power_save_blocker_);
-  audio_power_save_blocker_ = PowerSaveBlocker::Create(
-      PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
-      PowerSaveBlocker::kReasonAudioPlayback, "Playing audio");
-}
-
-void WebContentsImpl::CreateVideoPowerSaveBlocker() {
-  DCHECK(!video_power_save_blocker_);
-  DCHECK(!active_video_players_.empty());
-  video_power_save_blocker_ = PowerSaveBlocker::Create(
-      PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
-      PowerSaveBlocker::kReasonVideoPlayback, "Playing video");
-  //TODO(mfomitchev): Support PowerSaveBlocker on Aura - crbug.com/546718.
-#if defined(OS_ANDROID) && !defined(USE_AURA)
-static_cast<PowerSaveBlockerImpl*>(video_power_save_blocker_.get())
-      ->InitDisplaySleepBlocker(this);
-#endif
-}
-
-void WebContentsImpl::MaybeReleasePowerSaveBlockers() {
-  // If there are no more audio players and we don't have audio stream
-  // monitoring, release the audio power save blocker here instead of during
-  // NotifyNavigationStateChanged().
-  if (active_audio_players_.empty() &&
-      !AudioStreamMonitor::monitoring_available()) {
-    audio_power_save_blocker_.reset();
-  }
-
-  // If there are no more video players, clear the video power save blocker.
-  if (active_video_players_.empty())
-    video_power_save_blocker_.reset();
-}
-
-void WebContentsImpl::OnMediaPlayingNotification(int64 player_cookie,
-                                                 bool has_video,
-                                                 bool has_audio,
-                                                 bool is_remote) {
-  // Ignore the videos playing remotely and don't hold the wake lock for the
-  // screen.
-  if (is_remote) return;
-
-  if (has_audio) {
-    AddMediaPlayerEntry(player_cookie, &active_audio_players_);
-
-    // If we don't have audio stream monitoring, allocate the audio power save
-    // blocker here instead of during NotifyNavigationStateChanged().
-    if (!audio_power_save_blocker_ &&
-        !AudioStreamMonitor::monitoring_available()) {
-      CreateAudioPowerSaveBlocker();
-    }
-  }
-
-  if (has_video) {
-    AddMediaPlayerEntry(player_cookie, &active_video_players_);
-
-    // If we're not hidden and have just created a player, create a blocker.
-    if (!video_power_save_blocker_ && !IsHidden())
-      CreateVideoPowerSaveBlocker();
-  }
-
-  FOR_EACH_OBSERVER(WebContentsObserver, observers_, MediaStartedPlaying());
-}
-
-void WebContentsImpl::OnMediaPausedNotification(int64 player_cookie) {
-  RemoveMediaPlayerEntry(player_cookie, &active_audio_players_);
-  RemoveMediaPlayerEntry(player_cookie, &active_video_players_);
-  MaybeReleasePowerSaveBlockers();
-
-  FOR_EACH_OBSERVER(WebContentsObserver, observers_, MediaPaused());
-}
-
 #if defined(OS_ANDROID)
 
 void WebContentsImpl::OnMediaSessionStateChanged() {
@@ -3776,7 +3716,6 @@
 }
 
 void WebContentsImpl::RenderFrameDeleted(RenderFrameHost* render_frame_host) {
-  ClearPowerSaveBlockers(render_frame_host);
   FOR_EACH_OBSERVER(WebContentsObserver,
                     observers_,
                     RenderFrameDeleted(render_frame_host));
@@ -4721,20 +4660,6 @@
   browser_plugin_embedder_.reset(BrowserPluginEmbedder::Create(this));
 }
 
-void WebContentsImpl::ClearPowerSaveBlockers(
-    RenderFrameHost* render_frame_host) {
-  RemoveAllMediaPlayerEntries(render_frame_host, &active_audio_players_);
-  RemoveAllMediaPlayerEntries(render_frame_host, &active_video_players_);
-  MaybeReleasePowerSaveBlockers();
-}
-
-void WebContentsImpl::ClearAllPowerSaveBlockers() {
-  active_audio_players_.clear();
-  active_video_players_.clear();
-  audio_power_save_blocker_.reset();
-  video_power_save_blocker_.reset();
-}
-
 gfx::Size WebContentsImpl::GetSizeForNewRenderView() {
   gfx::Size size;
   if (delegate_)
@@ -4757,51 +4682,6 @@
     delegate_->UpdatePreferredSize(this, new_size);
 }
 
-void WebContentsImpl::AddMediaPlayerEntry(int64 player_cookie,
-                                          ActiveMediaPlayerMap* player_map) {
-  if (!HasValidFrameSource())
-    return;
-
-  const uintptr_t key =
-      reinterpret_cast<uintptr_t>(render_frame_message_source_);
-  DCHECK(std::find((*player_map)[key].begin(),
-                   (*player_map)[key].end(),
-                   player_cookie) == (*player_map)[key].end());
-  (*player_map)[key].push_back(player_cookie);
-}
-
-void WebContentsImpl::RemoveMediaPlayerEntry(int64 player_cookie,
-                                             ActiveMediaPlayerMap* player_map) {
-  if (!HasValidFrameSource())
-    return;
-
-  const uintptr_t key =
-      reinterpret_cast<uintptr_t>(render_frame_message_source_);
-  ActiveMediaPlayerMap::iterator it = player_map->find(key);
-  if (it == player_map->end())
-    return;
-
-  // Remove the player.
-  PlayerList::iterator player_it =
-      std::find(it->second.begin(), it->second.end(), player_cookie);
-  if (player_it != it->second.end())
-    it->second.erase(player_it);
-
-  // If there are no players left, remove the map entry.
-  if (it->second.empty())
-    player_map->erase(it);
-}
-
-void WebContentsImpl::RemoveAllMediaPlayerEntries(
-    RenderFrameHost* render_frame_host,
-    ActiveMediaPlayerMap* player_map) {
-  ActiveMediaPlayerMap::iterator it =
-      player_map->find(reinterpret_cast<uintptr_t>(render_frame_host));
-  if (it == player_map->end())
-    return;
-  player_map->erase(it);
-}
-
 WebUI* WebContentsImpl::CreateWebUI(const GURL& url,
                                     const std::string& frame_name) {
   WebUIImpl* web_ui = new WebUIImpl(this, frame_name);
@@ -4823,4 +4703,14 @@
     view_->SetOverscrollControllerEnabled(CanOverscrollContent());
 }
 
+void WebContentsImpl::MediaStartedPlaying(
+    const WebContentsObserver::MediaPlayerId& id) {
+  FOR_EACH_OBSERVER(WebContentsObserver, observers_, MediaStartedPlaying(id));
+}
+
+void WebContentsImpl::MediaStoppedPlaying(
+    const WebContentsObserver::MediaPlayerId& id) {
+  FOR_EACH_OBSERVER(WebContentsObserver, observers_, MediaStoppedPlaying(id));
+}
+
 }  // namespace content
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 69656888..a46f717 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -32,6 +32,7 @@
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/page_importance_signals.h"
 #include "content/public/common/renderer_preferences.h"
 #include "content/public/common/resource_type.h"
@@ -69,7 +70,6 @@
 class WebContentsAudioMuter;
 class WebContentsDelegate;
 class WebContentsImpl;
-class WebContentsObserver;
 class WebContentsView;
 class WebContentsViewDelegate;
 struct AXEventNotificationDetails;
@@ -714,19 +714,14 @@
     return &audio_stream_monitor_;
   }
 
-  bool has_audio_power_save_blocker_for_testing() const {
-    return audio_power_save_blocker_;
-  }
+  // Called by MediaWebContentsObserver when playback starts or stops.  See the
+  // WebContentsObserver function stubs for more details.
+  void MediaStartedPlaying(const WebContentsObserver::MediaPlayerId& id);
+  void MediaStoppedPlaying(const WebContentsObserver::MediaPlayerId& id);
 
-  bool has_video_power_save_blocker_for_testing() const {
-    return video_power_save_blocker_;
-  }
-
-#if defined(ENABLE_BROWSER_CDMS)
   MediaWebContentsObserver* media_web_contents_observer() {
     return media_web_contents_observer_.get();
   }
-#endif
 
  private:
   friend class WebContentsObserver;
@@ -842,8 +837,14 @@
                                         const std::string& mime_type,
                                         ResourceType resource_type);
   void OnDidDisplayInsecureContent();
-  void OnDidRunInsecureContent(const std::string& security_origin,
+  void OnDidRunInsecureContent(const GURL& security_origin,
                                const GURL& target_url);
+  void OnDidDisplayContentWithCertificateErrors(
+      const GURL& url,
+      const std::string& security_info);
+  void OnDidRunContentWithCertificateErrors(const GURL& security_origin,
+                                            const GURL& url,
+                                            const std::string& security_info);
   void OnDocumentLoadedInFrame();
   void OnDidFinishLoad(const GURL& url);
   void OnGoToEntryAtOffset(int offset);
@@ -904,11 +905,6 @@
 #endif  // defined(ENABLE_PLUGINS)
   void OnUpdateFaviconURL(const std::vector<FaviconURL>& candidates);
   void OnFirstVisuallyNonEmptyPaint();
-  void OnMediaPlayingNotification(int64 player_cookie,
-                                  bool has_video,
-                                  bool has_audio,
-                                  bool is_remote);
-  void OnMediaPausedNotification(int64 player_cookie);
   void OnShowValidationMessage(const gfx::Rect& anchor_in_root_view,
                                const base::string16& main_text,
                                const base::string16& sub_text);
@@ -996,22 +992,6 @@
   // Removes browser plugin embedder if there is one.
   void RemoveBrowserPluginEmbedder();
 
-  // Clear |render_frame_host|'s tracking entry for its power save blockers.
-  void ClearPowerSaveBlockers(RenderFrameHost* render_frame_host);
-
-  // Clear tracking entries for all RenderFrameHosts, clears
-  // |audio_power_save_blocker_| and |video_power_save_blocker_|.
-  void ClearAllPowerSaveBlockers();
-
-  // Creates an audio or video power save blocker respectively.
-  void CreateAudioPowerSaveBlocker();
-  void CreateVideoPowerSaveBlocker();
-
-  // Releases the audio power save blockers if |active_audio_players_| is empty.
-  // Likewise, releases the video power save blockers if |active_video_players_|
-  // is empty.
-  void MaybeReleasePowerSaveBlockers();
-
   // Helper function to invoke WebContentsDelegate::GetSizeForNewRenderView().
   gfx::Size GetSizeForNewRenderView();
 
@@ -1022,18 +1002,6 @@
   // |delegate_|.
   void OnPreferredSizeChanged(const gfx::Size& old_size);
 
-  // Helper methods for adding or removing player entries in |player_map| under
-  // the key |render_frame_message_source_|.
-  typedef std::vector<int64> PlayerList;
-  typedef std::map<uintptr_t, PlayerList> ActiveMediaPlayerMap;
-  void AddMediaPlayerEntry(int64 player_cookie,
-                           ActiveMediaPlayerMap* player_map);
-  void RemoveMediaPlayerEntry(int64 player_cookie,
-                              ActiveMediaPlayerMap* player_map);
-  // Removes all entries from |player_map| for |render_frame_host|.
-  void RemoveAllMediaPlayerEntries(RenderFrameHost* render_frame_host,
-                                   ActiveMediaPlayerMap* player_map);
-
   // Internal helper to create WebUI objects associated with |this|. |url| is
   // used to determine which WebUI should be created (if any). |frame_name|
   // corresponds to the name of a frame that the WebUI should be created for (or
@@ -1085,12 +1053,6 @@
 
   // Helper classes ------------------------------------------------------------
 
-  // Tracking variables and associated power save blockers for media playback.
-  ActiveMediaPlayerMap active_audio_players_;
-  ActiveMediaPlayerMap active_video_players_;
-  scoped_ptr<PowerSaveBlocker> audio_power_save_blocker_;
-  scoped_ptr<PowerSaveBlocker> video_power_save_blocker_;
-
   // Manages the frame tree of the page and process swaps in each node.
   FrameTree frame_tree_;
 
@@ -1323,10 +1285,8 @@
 
   bool virtual_keyboard_requested_;
 
-#if defined(ENABLE_BROWSER_CDMS)
-  // Manages all the media player and CDM managers and forwards IPCs to them.
+  // Manages media players, CDMs, and power save blockers for media.
   scoped_ptr<MediaWebContentsObserver> media_web_contents_observer_;
-#endif
 
   scoped_ptr<RenderWidgetHostInputEventRouter> rwh_input_event_router_;
 
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index 186b066f..c66ac28 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -11,6 +11,7 @@
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/frame_host/render_frame_proxy_host.h"
 #include "content/browser/media/audio_stream_monitor.h"
+#include "content/browser/media/media_web_contents_observer.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/browser/webui/content_web_ui_controller_factory.h"
@@ -245,6 +246,18 @@
         ContentWebUIControllerFactory::GetInstance());
     RenderViewHostImplTestHarness::TearDown();
   }
+
+  bool has_audio_power_save_blocker() {
+    return contents()
+        ->media_web_contents_observer()
+        ->has_audio_power_save_blocker_for_testing();
+  }
+
+  bool has_video_power_save_blocker() {
+    return contents()
+        ->media_web_contents_observer()
+        ->has_video_power_save_blocker_for_testing();
+  }
 };
 
 class TestWebContentsObserver : public WebContentsObserver {
@@ -3195,8 +3208,8 @@
   const int kPlayerVideoOnlyId = 30;
   const int kPlayerRemoteId = -30;
 
-  EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
-  EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
+  EXPECT_FALSE(has_audio_power_save_blocker());
+  EXPECT_FALSE(has_video_power_save_blocker());
 
   TestRenderFrameHost* rfh = contents()->GetMainFrame();
   AudioStreamMonitor* monitor = contents()->audio_stream_monitor();
@@ -3211,13 +3224,13 @@
     // blocker should be created.
     monitor->set_was_recently_audible_for_testing(true);
     contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
-    EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing());
+    EXPECT_TRUE(has_audio_power_save_blocker());
 
     // Send another fake notification, this time when WasRecentlyAudible() will
     // be false.  The power save blocker should be released.
     monitor->set_was_recently_audible_for_testing(false);
     contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
-    EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
+    EXPECT_FALSE(has_audio_power_save_blocker());
   }
 
   // Start a player with both audio and video.  A video power save blocker
@@ -3225,84 +3238,84 @@
   // save blocker should be created too.
   rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
       0, kPlayerAudioVideoId, true, true, false));
-  EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
-  EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
+  EXPECT_TRUE(has_video_power_save_blocker());
+  EXPECT_EQ(has_audio_power_save_blocker(),
             !AudioStreamMonitor::monitoring_available());
 
   // Upon hiding the video power save blocker should be released.
   contents()->WasHidden();
-  EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
+  EXPECT_FALSE(has_video_power_save_blocker());
 
   // Start another player that only has video.  There should be no change in
   // the power save blockers.  The notification should take into account the
   // visibility state of the WebContents.
   rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
       0, kPlayerVideoOnlyId, true, false, false));
-  EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
-  EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
+  EXPECT_FALSE(has_video_power_save_blocker());
+  EXPECT_EQ(has_audio_power_save_blocker(),
             !AudioStreamMonitor::monitoring_available());
 
   // Showing the WebContents should result in the creation of the blocker.
   contents()->WasShown();
-  EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
+  EXPECT_TRUE(has_video_power_save_blocker());
 
   // Start another player that only has audio.  There should be no change in
   // the power save blockers.
   rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
       0, kPlayerAudioOnlyId, false, true, false));
-  EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
-  EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
+  EXPECT_TRUE(has_video_power_save_blocker());
+  EXPECT_EQ(has_audio_power_save_blocker(),
             !AudioStreamMonitor::monitoring_available());
 
   // Start a remote player. There should be no change in the power save
   // blockers.
   rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
       0, kPlayerRemoteId, true, true, true));
-  EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
-  EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
+  EXPECT_TRUE(has_video_power_save_blocker());
+  EXPECT_EQ(has_audio_power_save_blocker(),
             !AudioStreamMonitor::monitoring_available());
 
   // Destroy the original audio video player.  Both power save blockers should
   // remain.
   rfh->OnMessageReceived(
       FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId));
-  EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
-  EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
+  EXPECT_TRUE(has_video_power_save_blocker());
+  EXPECT_EQ(has_audio_power_save_blocker(),
             !AudioStreamMonitor::monitoring_available());
 
   // Destroy the audio only player.  The video power save blocker should remain.
   rfh->OnMessageReceived(
       FrameHostMsg_MediaPausedNotification(0, kPlayerAudioOnlyId));
-  EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
-  EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
+  EXPECT_TRUE(has_video_power_save_blocker());
+  EXPECT_FALSE(has_audio_power_save_blocker());
 
   // Destroy the video only player.  No power save blockers should remain.
   rfh->OnMessageReceived(
       FrameHostMsg_MediaPausedNotification(0, kPlayerVideoOnlyId));
-  EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
-  EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
+  EXPECT_FALSE(has_video_power_save_blocker());
+  EXPECT_FALSE(has_audio_power_save_blocker());
 
   // Destroy the remote player. No power save blockers should remain.
   rfh->OnMessageReceived(
       FrameHostMsg_MediaPausedNotification(0, kPlayerRemoteId));
-  EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
-  EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
+  EXPECT_FALSE(has_video_power_save_blocker());
+  EXPECT_FALSE(has_audio_power_save_blocker());
 
   // Start a player with both audio and video.  A video power save blocker
   // should be created.  If audio stream monitoring is available, an audio power
   // save blocker should be created too.
   rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
       0, kPlayerAudioVideoId, true, true, false));
-  EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
-  EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
+  EXPECT_TRUE(has_video_power_save_blocker());
+  EXPECT_EQ(has_audio_power_save_blocker(),
             !AudioStreamMonitor::monitoring_available());
 
   // Crash the renderer.
   contents()->GetMainFrame()->GetProcess()->SimulateCrash();
 
   // Verify that all the power save blockers have been released.
-  EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
-  EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
+  EXPECT_FALSE(has_video_power_save_blocker());
+  EXPECT_FALSE(has_audio_power_save_blocker());
 }
 
 TEST_F(WebContentsImplTest, ThemeColorChangeDependingOnFirstVisiblePaint) {
diff --git a/content/browser/web_contents/web_contents_view_mus.cc b/content/browser/web_contents/web_contents_view_mus.cc
index 86de954..b987ab1 100644
--- a/content/browser/web_contents/web_contents_view_mus.cc
+++ b/content/browser/web_contents/web_contents_view_mus.cc
@@ -7,10 +7,15 @@
 #include "build/build_config.h"
 #include "components/mus/public/cpp/window.h"
 #include "components/mus/public/cpp/window_tree_connection.h"
+#include "content/browser/frame_host/interstitial_page_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_mus.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/web_contents_view_delegate.h"
 #include "third_party/WebKit/public/web/WebDragOperation.h"
+#include "ui/aura/client/window_tree_client.h"
+#include "ui/aura/window.h"
+#include "ui/base/hit_test.h"
 
 using blink::WebDragOperation;
 using blink::WebDragOperationsMask;
@@ -18,100 +23,127 @@
 namespace content {
 
 WebContentsViewMus::WebContentsViewMus(
-    WebContentsImpl* web_contents,
     mus::Window* parent_window,
-    scoped_ptr<WebContentsView> platform_view,
+    WebContentsImpl* web_contents,
+    WebContentsViewDelegate* delegate,
     RenderViewHostDelegateView** delegate_view)
-    : web_contents_(web_contents),
-      platform_view_(platform_view.Pass()),
-      platform_view_delegate_view_(*delegate_view) {
+    : web_contents_(web_contents), delegate_(delegate) {
   DCHECK(parent_window);
   *delegate_view = this;
   mus::Window* window = parent_window->connection()->NewWindow();
   window->SetVisible(true);
   window->SetBounds(gfx::Rect(300, 300));
   parent_window->AddChild(window);
-  window_.reset(new mus::ScopedWindowPtr(window));
+  mus_window_.reset(new mus::ScopedWindowPtr(window));
 }
 
 WebContentsViewMus::~WebContentsViewMus() {}
 
+void WebContentsViewMus::SizeChangedCommon(const gfx::Size& size) {
+  if (web_contents_->GetInterstitialPage())
+    web_contents_->GetInterstitialPage()->SetSize(size);
+  RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView();
+  if (rwhv)
+    rwhv->SetSize(size);
+  mus_window_->window()->SetBounds(gfx::Rect(size));
+}
+
 gfx::NativeView WebContentsViewMus::GetNativeView() const {
-  return platform_view_->GetNativeView();
+  return aura_window_.get();
 }
 
 gfx::NativeView WebContentsViewMus::GetContentNativeView() const {
   RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView();
-  if (!rwhv)
-    return NULL;
-  return rwhv->GetNativeView();
+  return rwhv ? rwhv->GetNativeView() : nullptr;
 }
 
 gfx::NativeWindow WebContentsViewMus::GetTopLevelNativeWindow() const {
-  return platform_view_->GetTopLevelNativeWindow();
+  gfx::NativeWindow window = aura_window_->GetToplevelWindow();
+  return window ? window : delegate_->GetNativeWindow();
 }
 
 void WebContentsViewMus::GetContainerBounds(gfx::Rect* out) const {
-  // TODO(fsamuel): Get the position right.
-  out->set_size(size_);
+  *out = aura_window_->GetBoundsInScreen();
 }
 
 void WebContentsViewMus::SizeContents(const gfx::Size& size) {
-  size_ = size;
-  RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView();
-  if (rwhv)
-    rwhv->SetSize(size);
-  window_->window()->SetBounds(gfx::Rect(size));
+  gfx::Rect bounds = aura_window_->bounds();
+  if (bounds.size() != size) {
+    bounds.set_size(size);
+    aura_window_->SetBounds(bounds);
+    SizeChangedCommon(size);
+  } else {
+    // Our size matches what we want but the renderers size may not match.
+    // Pretend we were resized so that the renderers size is updated too.
+    SizeChangedCommon(size);
+  }
 }
 
 void WebContentsViewMus::SetInitialFocus() {
-  platform_view_->SetInitialFocus();
+  if (web_contents_->FocusLocationBarByDefault())
+    web_contents_->SetFocusToLocationBar(false);
 }
 
 gfx::Rect WebContentsViewMus::GetViewBounds() const {
-  return gfx::Rect(size_);
+  return aura_window_->GetBoundsInScreen();
 }
 
 #if defined(OS_MACOSX)
 void WebContentsViewMus::SetAllowOtherViews(bool allow) {
-  platform_view_->SetAllowOtherViews(allow);
 }
 
 bool WebContentsViewMus::GetAllowOtherViews() const {
-  return platform_view_->GetAllowOtherViews();
+  return false;
 }
 #endif
 
 void WebContentsViewMus::CreateView(const gfx::Size& initial_size,
                                     gfx::NativeView context) {
-  platform_view_->CreateView(initial_size, context);
-  size_ = initial_size;
+  // We install a WindowDelegate so that the mus_window_ can track the size
+  // of the |aura_window_|.
+  aura_window_.reset(new aura::Window(this));
+  aura_window_->set_owned_by_parent(false);
+  aura_window_->SetType(ui::wm::WINDOW_TYPE_CONTROL);
+  aura_window_->SetTransparent(false);
+  aura_window_->Init(ui::LAYER_NOT_DRAWN);
+  aura::Window* root_window = context ? context->GetRootWindow() : nullptr;
+  if (root_window) {
+    // There are places where there is no context currently because object
+    // hierarchies are built before they're attached to a Widget. (See
+    // views::WebView as an example; GetWidget() returns nullptr at the point
+    // where we are created.)
+    //
+    // It should be OK to not set a default parent since such users will
+    // explicitly add this WebContentsViewMus to their tree after they create
+    // us.
+    aura::client::ParentWindowWithContext(aura_window_.get(), root_window,
+                                          root_window->GetBoundsInScreen());
+  }
+  aura_window_->layer()->SetMasksToBounds(true);
+  aura_window_->SetName("WebContentsViewMus");
 }
 
 RenderWidgetHostViewBase* WebContentsViewMus::CreateViewForWidget(
     RenderWidgetHost* render_widget_host,
     bool is_guest_view_hack) {
-  RenderWidgetHostViewBase* platform_widget =
-      platform_view_->CreateViewForWidget(render_widget_host, true);
-
-  return new RenderWidgetHostViewMus(
-      window_->window(), RenderWidgetHostImpl::From(render_widget_host),
-      platform_widget->GetWeakPtr());
+  RenderWidgetHostViewBase* view = new RenderWidgetHostViewMus(
+      mus_window_->window(), RenderWidgetHostImpl::From(render_widget_host));
+  view->InitAsChild(GetNativeView());
+  return view;
 }
 
 RenderWidgetHostViewBase* WebContentsViewMus::CreateViewForPopupWidget(
     RenderWidgetHost* render_widget_host) {
-  return platform_view_->CreateViewForPopupWidget(render_widget_host);
+  return new RenderWidgetHostViewMus(
+      mus_window_->window(), RenderWidgetHostImpl::From(render_widget_host));
 }
 
 void WebContentsViewMus::SetPageTitle(const base::string16& title) {}
 
 void WebContentsViewMus::RenderViewCreated(RenderViewHost* host) {
-  platform_view_->RenderViewCreated(host);
 }
 
 void WebContentsViewMus::RenderViewSwappedIn(RenderViewHost* host) {
-  platform_view_->RenderViewSwappedIn(host);
 }
 
 void WebContentsViewMus::SetOverscrollControllerEnabled(bool enabled) {
@@ -131,33 +163,41 @@
 }
 
 void WebContentsViewMus::RestoreFocus() {
-  platform_view_->RestoreFocus();
+  // Focus is managed by mus, not the browser.
+  NOTIMPLEMENTED();
 }
 
 void WebContentsViewMus::Focus() {
-  platform_view_->Focus();
+  // Focus is managed by mus, not the browser.
+  NOTIMPLEMENTED();
 }
 
 void WebContentsViewMus::StoreFocus() {
-  platform_view_->StoreFocus();
+  // Focus is managed by mus, not the browser.
+  NOTIMPLEMENTED();
 }
 
 DropData* WebContentsViewMus::GetDropData() const {
   NOTIMPLEMENTED();
-  return NULL;
+  return nullptr;
 }
 
 void WebContentsViewMus::UpdateDragCursor(WebDragOperation operation) {
   // TODO(fsamuel): Implement cursor in Mus.
 }
 
-void WebContentsViewMus::GotFocus() {}
+void WebContentsViewMus::GotFocus() {
+  // Focus is managed by mus, not the browser.
+  NOTIMPLEMENTED();
+}
 
-void WebContentsViewMus::TakeFocus(bool reverse) {}
+void WebContentsViewMus::TakeFocus(bool reverse) {
+  // Focus is managed by mus, not the browser.
+  NOTIMPLEMENTED();
+}
 
 void WebContentsViewMus::ShowContextMenu(RenderFrameHost* render_frame_host,
                                          const ContextMenuParams& params) {
-  platform_view_delegate_view_->ShowContextMenu(render_frame_host, params);
 }
 
 void WebContentsViewMus::StartDragging(const DropData& drop_data,
@@ -168,4 +208,59 @@
   // TODO(fsamuel): Implement drag and drop.
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// WebContentsViewMus, aura::WindowDelegate implementation:
+
+gfx::Size WebContentsViewMus::GetMinimumSize() const {
+  return gfx::Size();
+}
+
+gfx::Size WebContentsViewMus::GetMaximumSize() const {
+  return gfx::Size();
+}
+
+void WebContentsViewMus::OnBoundsChanged(const gfx::Rect& old_bounds,
+                                         const gfx::Rect& new_bounds) {
+  SizeChangedCommon(new_bounds.size());
+  if (delegate_)
+    delegate_->SizeChanged(new_bounds.size());
+}
+
+gfx::NativeCursor WebContentsViewMus::GetCursor(const gfx::Point& point) {
+  return gfx::kNullCursor;
+}
+
+int WebContentsViewMus::GetNonClientComponent(const gfx::Point& point) const {
+  return HTCLIENT;
+}
+
+bool WebContentsViewMus::ShouldDescendIntoChildForEventHandling(
+    aura::Window* child,
+    const gfx::Point& location) {
+  return true;
+}
+
+bool WebContentsViewMus::CanFocus() {
+  return false;
+}
+
+void WebContentsViewMus::OnCaptureLost() {}
+
+void WebContentsViewMus::OnPaint(const ui::PaintContext& context) {}
+
+void WebContentsViewMus::OnDeviceScaleFactorChanged(float device_scale_factor) {
+}
+
+void WebContentsViewMus::OnWindowDestroying(aura::Window* window) {}
+
+void WebContentsViewMus::OnWindowDestroyed(aura::Window* window) {}
+
+void WebContentsViewMus::OnWindowTargetVisibilityChanged(bool visible) {}
+
+bool WebContentsViewMus::HasHitTestMask() const {
+  return false;
+}
+
+void WebContentsViewMus::GetHitTestMask(gfx::Path* mask) const {}
+
 }  // namespace content
diff --git a/content/browser/web_contents/web_contents_view_mus.h b/content/browser/web_contents/web_contents_view_mus.h
index 5e4e4ed..4e5952c 100644
--- a/content/browser/web_contents/web_contents_view_mus.h
+++ b/content/browser/web_contents/web_contents_view_mus.h
@@ -15,29 +15,32 @@
 #include "content/browser/web_contents/web_contents_view.h"
 #include "content/common/content_export.h"
 #include "content/common/drag_event_source_info.h"
+#include "ui/aura/window_delegate.h"
 
 namespace content {
 
 class WebContents;
 class WebContentsImpl;
+class WebContentsViewDelegate;
 
 class WebContentsViewMus : public WebContentsView,
-                           public RenderViewHostDelegateView {
+                           public RenderViewHostDelegateView,
+                           public aura::WindowDelegate {
  public:
   // The corresponding WebContentsImpl is passed in the constructor, and manages
   // our lifetime. This doesn't need to be the case, but is this way currently
   // because that's what was easiest when they were split.
-  // WebContentsViewMus always has a backing platform dependent view,
-  // |platform_view|.
-  WebContentsViewMus(WebContentsImpl* web_contents,
-                     mus::Window* parent_window,
-                     scoped_ptr<WebContentsView> platform_view,
-                     RenderViewHostDelegateView** platform_view_delegate_view);
+  WebContentsViewMus(mus::Window* parent_window,
+                     WebContentsImpl* web_contents,
+                     WebContentsViewDelegate* delegate,
+                     RenderViewHostDelegateView** delegate_view);
   ~WebContentsViewMus() override;
 
   WebContents* web_contents();
 
  private:
+  void SizeChangedCommon(const gfx::Size& size);
+
   // WebContentsView implementation:
   gfx::NativeView GetNativeView() const override;
   gfx::NativeView GetContentNativeView() const override;
@@ -80,18 +83,32 @@
   void GotFocus() override;
   void TakeFocus(bool reverse) override;
 
+  // Overridden from aura::WindowDelegate:
+  gfx::Size GetMinimumSize() const override;
+  gfx::Size GetMaximumSize() const override;
+  void OnBoundsChanged(const gfx::Rect& old_bounds,
+                       const gfx::Rect& new_bounds) override;
+  gfx::NativeCursor GetCursor(const gfx::Point& point) override;
+  int GetNonClientComponent(const gfx::Point& point) const override;
+  bool ShouldDescendIntoChildForEventHandling(
+      aura::Window* child,
+      const gfx::Point& location) override;
+  bool CanFocus() override;
+  void OnCaptureLost() override;
+  void OnPaint(const ui::PaintContext& context) override;
+  void OnDeviceScaleFactorChanged(float device_scale_factor) override;
+  void OnWindowDestroying(aura::Window* window) override;
+  void OnWindowDestroyed(aura::Window* window) override;
+  void OnWindowTargetVisibilityChanged(bool visible) override;
+  bool HasHitTestMask() const override;
+  void GetHitTestMask(gfx::Path* mask) const override;
+
   // The WebContentsImpl whose contents we display.
   WebContentsImpl* web_contents_;
 
-  scoped_ptr<mus::ScopedWindowPtr> window_;
-
-  // The platform dependent view backing this WebContentsView.
-  // Calls to this WebContentsViewMus are forwarded to |platform_view_|.
-  scoped_ptr<WebContentsView> platform_view_;
-  gfx::Size size_;
-
-  // Delegate view for guest's platform view.
-  RenderViewHostDelegateView* platform_view_delegate_view_;
+  scoped_ptr<WebContentsViewDelegate> delegate_;
+  scoped_ptr<aura::Window> aura_window_;
+  scoped_ptr<mus::ScopedWindowPtr> mus_window_;
 
   DISALLOW_COPY_AND_ASSIGN(WebContentsViewMus);
 };
diff --git a/content/browser/zygote_host/zygote_host_impl_linux.cc b/content/browser/zygote_host/zygote_host_impl_linux.cc
index a736fb0..3b82e2a 100644
--- a/content/browser/zygote_host/zygote_host_impl_linux.cc
+++ b/content/browser/zygote_host/zygote_host_impl_linux.cc
@@ -21,7 +21,6 @@
 #include "base/logging.h"
 #include "base/memory/linked_ptr.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/path_service.h"
@@ -63,7 +62,7 @@
                          size_t expect_len,
                          base::ProcessId* sender_pid) {
   char buf[expect_len + 1];
-  ScopedVector<base::ScopedFD> fds_vec;
+  std::vector<base::ScopedFD> fds_vec;
 
   const ssize_t len = base::UnixDomainSocket::RecvMsgWithPid(
       fd, buf, sizeof(buf), &fds_vec, sender_pid);
@@ -363,7 +362,7 @@
 
     {
       char buf[sizeof(kZygoteChildPingMessage) + 1];
-      ScopedVector<base::ScopedFD> recv_fds;
+      std::vector<base::ScopedFD> recv_fds;
       base::ProcessId real_pid;
 
       ssize_t n = base::UnixDomainSocket::RecvMsgWithPid(
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc
index 510c05b..e1fc89f 100644
--- a/content/child/blink_platform_impl.cc
+++ b/content/child/blink_platform_impl.cc
@@ -689,42 +689,6 @@
   return result;
 }
 
-blink::Platform::TraceEventHandle BlinkPlatformImpl::addTraceEvent(
-    char phase,
-    const unsigned char* category_group_enabled,
-    const char* name,
-    unsigned long long id,
-    double timestamp,
-    int num_args,
-    const char** arg_names,
-    const unsigned char* arg_types,
-    const unsigned long long* arg_values,
-    blink::WebConvertableToTraceFormat* convertable_values,
-    unsigned char flags) {
-  scoped_refptr<base::trace_event::ConvertableToTraceFormat>
-      convertable_wrappers[2];
-  if (convertable_values) {
-    size_t size = std::min(static_cast<size_t>(num_args),
-                           arraysize(convertable_wrappers));
-    for (size_t i = 0; i < size; ++i) {
-      if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
-        convertable_wrappers[i] =
-            new ConvertableToTraceFormatWrapper(convertable_values[i]);
-      }
-    }
-  }
-  base::TimeTicks timestamp_tt =
-      base::TimeTicks() + base::TimeDelta::FromSecondsD(timestamp);
-  base::trace_event::TraceEventHandle handle =
-      TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
-          phase, category_group_enabled, name, id, trace_event_internal::kNoId,
-          base::PlatformThread::CurrentId(), timestamp_tt, num_args, arg_names,
-          arg_types, arg_values, convertable_wrappers, flags);
-  blink::Platform::TraceEventHandle result;
-  memcpy(&result, &handle, sizeof(result));
-  return result;
-}
-
 void BlinkPlatformImpl::updateTraceEventDuration(
     const unsigned char* category_group_enabled,
     const char* name,
diff --git a/content/child/blink_platform_impl.h b/content/child/blink_platform_impl.h
index c77dd9a..4bfeb7e 100644
--- a/content/child/blink_platform_impl.h
+++ b/content/child/blink_platform_impl.h
@@ -132,18 +132,6 @@
       const unsigned long long* arg_values,
       blink::WebConvertableToTraceFormat* convertable_values,
       unsigned int flags) override;
-  virtual TraceEventHandle addTraceEvent(
-      char phase,
-      const unsigned char* category_group_enabled,
-      const char* name,
-      unsigned long long id,
-      double timestamp,
-      int num_args,
-      const char** arg_names,
-      const unsigned char* arg_types,
-      const unsigned long long* arg_values,
-      blink::WebConvertableToTraceFormat* convertable_values,
-      unsigned char flags);
   void updateTraceEventDuration(const unsigned char* category_group_enabled,
                                 const char* name,
                                 TraceEventHandle) override;
diff --git a/content/child/blob_storage/blob_consolidation.cc b/content/child/blob_storage/blob_consolidation.cc
index 4985059e..a2b0925d 100644
--- a/content/child/blob_storage/blob_consolidation.cc
+++ b/content/child/blob_storage/blob_consolidation.cc
@@ -4,7 +4,10 @@
 
 #include "content/child/blob_storage/blob_consolidation.h"
 
+#include <stdint.h>
+
 #include <algorithm>
+#include <limits>
 #include <string>
 
 using storage::DataElement;
@@ -17,9 +20,8 @@
 BlobConsolidation::ConsolidatedItem::ConsolidatedItem()
     : type(DataElement::TYPE_UNKNOWN),
       offset(0),
-      length(kuint64max),
-      expected_modification_time(0) {
-}
+      length(std::numeric_limits<uint64_t>::max()),
+      expected_modification_time(0) {}
 
 BlobConsolidation::ConsolidatedItem::~ConsolidatedItem() {
 }
diff --git a/content/child/npapi/webplugin_delegate_impl_win.cc b/content/child/npapi/webplugin_delegate_impl_win.cc
index 8dd3687..d09123f 100644
--- a/content/child/npapi/webplugin_delegate_impl_win.cc
+++ b/content/child/npapi/webplugin_delegate_impl_win.cc
@@ -169,7 +169,7 @@
   DWORD size = 0;
   DWORD result = 0;
   result = func(key, KeyNameInformation, 0, 0, &size);
-  if (result != STATUS_BUFFER_TOO_SMALL)
+  if (result != static_cast<DWORD>(STATUS_BUFFER_TOO_SMALL))
     return L"";
 
   scoped_ptr<char[]> buffer(new char[size]);
@@ -177,7 +177,7 @@
     return L"";
 
   result = func(key, KeyNameInformation, buffer.get(), size, &size);
-  if (result != STATUS_SUCCESS)
+  if (result != static_cast<DWORD>(STATUS_SUCCESS))
     return L"";
 
   KEY_NAME_INFORMATION* info =
@@ -594,7 +594,8 @@
                                             UINT message, WPARAM wParam,
                                             LPARAM lParam) {
   MSG msg;
-  msg.time = reinterpret_cast<DWORD>(proc);
+  // Cast through uintptr_t and then DWORD to make the truncation explicit.
+  msg.time = static_cast<DWORD>(reinterpret_cast<uintptr_t>(proc));
   msg.hwnd = hwnd;
   msg.message = message;
   msg.wParam = wParam;
diff --git a/content/child/npapi/webplugin_ime_win.cc b/content/child/npapi/webplugin_ime_win.cc
index 7ff6a5d..e095ee1 100644
--- a/content/child/npapi/webplugin_ime_win.cc
+++ b/content/child/npapi/webplugin_ime_win.cc
@@ -169,7 +169,7 @@
         reinterpret_cast<FARPROC>(ImmSetCandidateWindow) },
     { "ImmSetOpenStatus", reinterpret_cast<FARPROC>(ImmSetOpenStatus) },
   };
-  for (int i = 0; i < arraysize(kImm32Functions); ++i) {
+  for (size_t i = 0; i < arraysize(kImm32Functions); ++i) {
     if (!lstrcmpiA(name, kImm32Functions[i].name))
       return kImm32Functions[i].function;
   }
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc
index c3c8cc4..89893b1 100644
--- a/content/child/resource_dispatcher.cc
+++ b/content/child/resource_dispatcher.cc
@@ -218,6 +218,15 @@
   request_info->buffer_size = shm_size;
 }
 
+void ResourceDispatcher::OnReceivedDataDebug(int request_id, int data_offset) {
+  PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+  if (request_info) {
+    CHECK_GE(data_offset, 0);
+    CHECK_LE(data_offset, 512 * 1024);
+    request_info->data_offset = data_offset;
+  }
+}
+
 void ResourceDispatcher::OnReceivedData(int request_id,
                                         int data_offset,
                                         int data_length,
@@ -235,8 +244,9 @@
     CHECK_LE(request_info->buffer_size, 512 * 1024);
     CHECK_GE(data_length, 0);
     CHECK_LE(data_length, 512 * 1024);
-    CHECK_GE(data_offset, 0);
-    CHECK_LE(data_offset, 512 * 1024);
+
+    int cached_data_offset = request_info->data_offset;
+    CHECK_EQ(cached_data_offset, data_offset);
 
     // Ensure that the SHM buffer remains valid for the duration of this scope.
     // It is possible for Cancel() to be called before we exit this scope.
@@ -488,7 +498,8 @@
       resource_type(RESOURCE_TYPE_SUB_RESOURCE),
       is_deferred(false),
       download_to_file(false),
-      buffer_size(0) {
+      buffer_size(0),
+      data_offset(-1) {
 }
 
 ResourceDispatcher::PendingRequestInfo::PendingRequestInfo(
@@ -507,7 +518,8 @@
       frame_origin(frame_origin),
       response_url(request_url),
       download_to_file(download_to_file),
-      request_start(base::TimeTicks::Now()) {
+      request_start(base::TimeTicks::Now()),
+      data_offset(-1) {
 }
 
 ResourceDispatcher::PendingRequestInfo::~PendingRequestInfo() {
@@ -523,6 +535,7 @@
                         OnReceivedCachedMetadata)
     IPC_MESSAGE_HANDLER(ResourceMsg_ReceivedRedirect, OnReceivedRedirect)
     IPC_MESSAGE_HANDLER(ResourceMsg_SetDataBuffer, OnSetDataBuffer)
+    IPC_MESSAGE_HANDLER(ResourceMsg_DataReceivedDebug, OnReceivedDataDebug)
     IPC_MESSAGE_HANDLER(ResourceMsg_DataReceived, OnReceivedData)
     IPC_MESSAGE_HANDLER(ResourceMsg_DataDownloaded, OnDownloadedData)
     IPC_MESSAGE_HANDLER(ResourceMsg_RequestComplete, OnRequestComplete)
@@ -706,6 +719,7 @@
     case ResourceMsg_ReceivedCachedMetadata::ID:
     case ResourceMsg_ReceivedRedirect::ID:
     case ResourceMsg_SetDataBuffer::ID:
+    case ResourceMsg_DataReceivedDebug::ID:
     case ResourceMsg_DataReceived::ID:
     case ResourceMsg_DataDownloaded::ID:
     case ResourceMsg_RequestComplete::ID:
diff --git a/content/child/resource_dispatcher.h b/content/child/resource_dispatcher.h
index 05500f5..bf28cd5 100644
--- a/content/child/resource_dispatcher.h
+++ b/content/child/resource_dispatcher.h
@@ -173,6 +173,9 @@
     scoped_refptr<SharedMemoryReceivedDataFactory> received_data_factory;
     linked_ptr<SiteIsolationResponseMetaData> site_isolation_metadata;
     int buffer_size;
+
+    // Debugging for https://code.google.com/p/chromium/issues/detail?id=527588.
+    int data_offset;
   };
   typedef base::hash_map<int, PendingRequestInfo> PendingRequestList;
 
@@ -194,6 +197,7 @@
                        base::SharedMemoryHandle shm_handle,
                        int shm_size,
                        base::ProcessId renderer_pid);
+  void OnReceivedDataDebug(int request_id, int data_offset);
   void OnReceivedData(int request_id,
                       int data_offset,
                       int data_length,
diff --git a/content/child/resource_dispatcher_unittest.cc b/content/child/resource_dispatcher_unittest.cc
index 0f26c821..c9f4d304 100644
--- a/content/child/resource_dispatcher_unittest.cc
+++ b/content/child/resource_dispatcher_unittest.cc
@@ -305,6 +305,8 @@
            data.length());
 
     EXPECT_TRUE(dispatcher_.OnMessageReceived(
+        ResourceMsg_DataReceivedDebug(request_id, 0)));
+    EXPECT_TRUE(dispatcher_.OnMessageReceived(
         ResourceMsg_DataReceived(request_id, 0, data.length(), data.length())));
   }
 
diff --git a/content/child/service_worker/service_worker_dispatcher.cc b/content/child/service_worker/service_worker_dispatcher.cc
index 832395a..30304f01 100644
--- a/content/child/service_worker/service_worker_dispatcher.cc
+++ b/content/child/service_worker/service_worker_dispatcher.cc
@@ -56,6 +56,10 @@
 
 void ServiceWorkerDispatcher::OnMessageReceived(const IPC::Message& msg) {
   bool handled = true;
+
+  // When you add a new message handler, you should consider adding a similar
+  // handler in ServiceWorkerMessageFilter to release references passed from
+  // the browser process in case we fail to post task to the thread.
   IPC_BEGIN_MESSAGE_MAP(ServiceWorkerDispatcher, msg)
     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_AssociateRegistration,
                         OnAssociateRegistration)
diff --git a/content/child/service_worker/service_worker_dispatcher_unittest.cc b/content/child/service_worker/service_worker_dispatcher_unittest.cc
index 93d9465c..b22e819a 100644
--- a/content/child/service_worker/service_worker_dispatcher_unittest.cc
+++ b/content/child/service_worker/service_worker_dispatcher_unittest.cc
@@ -17,6 +17,8 @@
 
 namespace content {
 
+namespace {
+
 class ServiceWorkerTestSender : public ThreadSafeSender {
  public:
   explicit ServiceWorkerTestSender(IPC::TestSink* ipc_sink)
@@ -35,6 +37,8 @@
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTestSender);
 };
 
+}  // namespace
+
 class ServiceWorkerDispatcherTest : public testing::Test {
  public:
   ServiceWorkerDispatcherTest() {}
@@ -150,9 +154,6 @@
   ServiceWorkerDispatcher* dispatcher_;
 };
 
-// TODO(nhiroki): Add tests for message handlers especially to receive reference
-// counts.
-
 TEST_F(ServiceWorkerDispatcherTest, OnAssociateRegistration_NoProviderContext) {
   // Assume that these objects are passed from the browser process and own
   // references to browser-side registration/worker representations.
diff --git a/content/child/service_worker/service_worker_message_filter.cc b/content/child/service_worker/service_worker_message_filter.cc
index 7aa24d9..9754dfd 100644
--- a/content/child/service_worker/service_worker_message_filter.cc
+++ b/content/child/service_worker/service_worker_message_filter.cc
@@ -65,16 +65,40 @@
   // Specifically handle some messages in case we failed to post task
   // to the thread (meaning that the context on the thread is now gone).
   IPC_BEGIN_MESSAGE_MAP(ServiceWorkerMessageFilter, msg)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_AssociateRegistration,
+                        OnStaleAssociateRegistration)
     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerRegistered,
-                        OnStaleRegistered)
+                        OnStaleGetRegistration)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetRegistration,
+                        OnStaleGetRegistration)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetRegistrations,
+                        OnStaleGetRegistrations)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetRegistrationForReady,
+                        OnStaleGetRegistration)
     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SetVersionAttributes,
                         OnStaleSetVersionAttributes)
     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SetControllerServiceWorker,
                         OnStaleSetControllerServiceWorker)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_MessageToDocument,
+                        OnStaleMessageToDocument)
   IPC_END_MESSAGE_MAP()
 }
 
-void ServiceWorkerMessageFilter::OnStaleRegistered(
+void ServiceWorkerMessageFilter::OnStaleAssociateRegistration(
+    int thread_id,
+    int provider_id,
+    const ServiceWorkerRegistrationObjectInfo& info,
+    const ServiceWorkerVersionAttributes& attrs) {
+  SendServiceWorkerObjectDestroyed(thread_safe_sender(),
+                                   attrs.installing.handle_id);
+  SendServiceWorkerObjectDestroyed(thread_safe_sender(),
+                                   attrs.waiting.handle_id);
+  SendServiceWorkerObjectDestroyed(thread_safe_sender(),
+                                   attrs.active.handle_id);
+  SendRegistrationObjectDestroyed(thread_safe_sender(), info.handle_id);
+}
+
+void ServiceWorkerMessageFilter::OnStaleGetRegistration(
     int thread_id,
     int request_id,
     const ServiceWorkerRegistrationObjectInfo& info,
@@ -88,6 +112,16 @@
   SendRegistrationObjectDestroyed(thread_safe_sender(), info.handle_id);
 }
 
+void ServiceWorkerMessageFilter::OnStaleGetRegistrations(
+    int thread_id,
+    int request_id,
+    const std::vector<ServiceWorkerRegistrationObjectInfo>& infos,
+    const std::vector<ServiceWorkerVersionAttributes>& attrs) {
+  DCHECK_EQ(infos.size(), attrs.size());
+  for (size_t i = 0; i < infos.size(); ++i)
+    OnStaleGetRegistration(thread_id, request_id, infos[i], attrs[i]);
+}
+
 void ServiceWorkerMessageFilter::OnStaleSetVersionAttributes(
     int thread_id,
     int registration_handle_id,
@@ -111,4 +145,10 @@
   SendServiceWorkerObjectDestroyed(thread_safe_sender(), info.handle_id);
 }
 
+void ServiceWorkerMessageFilter::OnStaleMessageToDocument(
+    const ServiceWorkerMsg_MessageToDocument_Params& params) {
+  SendServiceWorkerObjectDestroyed(thread_safe_sender(),
+                                   params.service_worker_info.handle_id);
+}
+
 }  // namespace content
diff --git a/content/child/service_worker/service_worker_message_filter.h b/content/child/service_worker/service_worker_message_filter.h
index 61995928..55292d12 100644
--- a/content/child/service_worker/service_worker_message_filter.h
+++ b/content/child/service_worker/service_worker_message_filter.h
@@ -5,9 +5,13 @@
 #ifndef CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_MESSAGE_FILTER_H_
 #define CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_MESSAGE_FILTER_H_
 
+#include <vector>
+
 #include "content/child/worker_thread_message_filter.h"
 #include "content/common/content_export.h"
 
+struct ServiceWorkerMsg_MessageToDocument_Params;
+
 namespace content {
 
 struct ServiceWorkerObjectInfo;
@@ -33,11 +37,20 @@
   void OnStaleMessageReceived(const IPC::Message& msg) override;
 
   // Message handlers for stale messages.
-  void OnStaleRegistered(
+  void OnStaleAssociateRegistration(
       int thread_id,
-      int request_id,
+      int provider_id,
       const ServiceWorkerRegistrationObjectInfo& info,
       const ServiceWorkerVersionAttributes& attrs);
+  void OnStaleGetRegistration(int thread_id,
+                              int request_id,
+                              const ServiceWorkerRegistrationObjectInfo& info,
+                              const ServiceWorkerVersionAttributes& attrs);
+  void OnStaleGetRegistrations(
+      int thread_id,
+      int request_id,
+      const std::vector<ServiceWorkerRegistrationObjectInfo>& info,
+      const std::vector<ServiceWorkerVersionAttributes>& attrs);
   void OnStaleSetVersionAttributes(
       int thread_id,
       int registration_handle_id,
@@ -48,6 +61,8 @@
       int provider_id,
       const ServiceWorkerObjectInfo& info,
       bool should_notify_controllerchange);
+  void OnStaleMessageToDocument(
+      const ServiceWorkerMsg_MessageToDocument_Params& params);
 
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerMessageFilter);
 };
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc
index bea6020..dbcff212 100644
--- a/content/child/web_url_loader_impl.cc
+++ b/content/child/web_url_loader_impl.cc
@@ -887,6 +887,7 @@
   response->setTextEncodingName(WebString::fromUTF8(info.charset));
   response->setExpectedContentLength(info.content_length);
   response->setSecurityInfo(info.security_info);
+  response->setHasMajorCertificateErrors(info.has_major_certificate_errors);
   response->setAppCacheID(info.appcache_id);
   response->setAppCacheManifestURL(info.appcache_manifest_url);
   response->setWasCached(!info.load_timing.request_start_time.is_null() &&
diff --git a/content/child/web_url_request_util.cc b/content/child/web_url_request_util.cc
index cf46ed4..037e761 100644
--- a/content/child/web_url_request_util.cc
+++ b/content/child/web_url_request_util.cc
@@ -4,6 +4,10 @@
 
 #include "content/child/web_url_request_util.h"
 
+#include <stdint.h>
+
+#include <limits>
+
 #include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "net/base/load_flags.h"
@@ -245,13 +249,13 @@
       case WebHTTPBody::Element::TypeFile:
         if (element.fileLength == -1) {
           request_body->AppendFileRange(
-              base::FilePath::FromUTF16Unsafe(element.filePath),
-              0, kuint64max, base::Time());
+              base::FilePath::FromUTF16Unsafe(element.filePath), 0,
+              std::numeric_limits<uint64_t>::max(), base::Time());
         } else {
           request_body->AppendFileRange(
               base::FilePath::FromUTF16Unsafe(element.filePath),
-              static_cast<uint64>(element.fileStart),
-              static_cast<uint64>(element.fileLength),
+              static_cast<uint64_t>(element.fileStart),
+              static_cast<uint64_t>(element.fileLength),
               base::Time::FromDoubleT(element.modificationTime));
         }
         break;
@@ -259,9 +263,8 @@
         GURL file_system_url = element.fileSystemURL;
         DCHECK(file_system_url.SchemeIsFileSystem());
         request_body->AppendFileSystemFileRange(
-            file_system_url,
-            static_cast<uint64>(element.fileStart),
-            static_cast<uint64>(element.fileLength),
+            file_system_url, static_cast<uint64_t>(element.fileStart),
+            static_cast<uint64_t>(element.fileLength),
             base::Time::FromDoubleT(element.modificationTime));
         break;
       }
diff --git a/content/common/DEPS b/content/common/DEPS
index e2d9fd7..a890606f 100644
--- a/content/common/DEPS
+++ b/content/common/DEPS
@@ -57,6 +57,7 @@
   "+third_party/WebKit/public/web/WebPluginAction.h",
   "+third_party/WebKit/public/web/WebPopupType.h",
   "+third_party/WebKit/public/web/WebSandboxFlags.h",
+  "+third_party/WebKit/public/web/WebSharedWorkerCreationContextType.h",
   "+third_party/WebKit/public/web/WebSharedWorkerCreationErrors.h",
   "+third_party/WebKit/public/web/WebTextDirection.h",
   "+third_party/WebKit/public/web/WebTreeScopeType.h",
diff --git a/content/common/OWNERS b/content/common/OWNERS
index ce0169c..df1d46c5 100644
--- a/content/common/OWNERS
+++ b/content/common/OWNERS
@@ -1,4 +1,5 @@
-# For Linux sandboxing
+# For Linux sandboxing related changes only. Regular content/
+# OWNERS own content/common/.
 jln@chromium.org
 
 # For security review of sandboxes
@@ -56,6 +57,18 @@
 per-file *param_traits*.h=tsepez@chromium.org
 per-file *param_traits*.h=wfh@chromium.org
 
+per-file *font_config_ipc_linux*=set noparent
+per-file *font_config_ipc_linux*=dcheng@chromium.org
+per-file *font_config_ipc_linux*=inferno@chromium.org
+per-file *font_config_ipc_linux*=jln@chromium.org
+per-file *font_config_ipc_linux*=jschuh@chromium.org
+per-file *font_config_ipc_linux*=kenrb@chromium.org
+per-file *font_config_ipc_linux*=mkwst@chromium.org
+per-file *font_config_ipc_linux*=nasko@chromium.org
+per-file *font_config_ipc_linux*=palmer@chromium.org
+per-file *font_config_ipc_linux*=tsepez@chromium.org
+per-file *font_config_ipc_linux*=wfh@chromium.org
+
 # Changes to Mojo interfaces require a security review to avoid
 # introducing new sandbox escapes.
 per-file *.mojom=set noparent
diff --git a/content/common/cc_messages.cc b/content/common/cc_messages.cc
index 34b5614d..992ff8a 100644
--- a/content/common/cc_messages.cc
+++ b/content/common/cc_messages.cc
@@ -300,7 +300,6 @@
   WriteParam(m, p.damage_rect);
   WriteParam(m, p.transform_to_root_target);
   WriteParam(m, p.has_transparent_background);
-  WriteParam(m, p.referenced_surfaces);
   WriteParam(m, p.quad_list.size());
 
   cc::SharedQuadStateList::ConstIterator shared_quad_state_iter =
@@ -384,9 +383,6 @@
 
   // The largest quad type, verified by a unit test.
   to_reserve += p.quad_list.size() * cc::LargestDrawQuadSize();
-
-  // The actual list of referenced surfaces.
-  to_reserve += p.referenced_surfaces.size() * sizeof(cc::SurfaceId);
   return to_reserve;
 }
 
@@ -408,14 +404,12 @@
   gfx::Rect damage_rect;
   gfx::Transform transform_to_root_target;
   bool has_transparent_background;
-  std::vector<cc::SurfaceId> referenced_surfaces;
   size_t quad_list_size;
 
   if (!ReadParam(m, iter, &id) || !ReadParam(m, iter, &output_rect) ||
       !ReadParam(m, iter, &damage_rect) ||
       !ReadParam(m, iter, &transform_to_root_target) ||
       !ReadParam(m, iter, &has_transparent_background) ||
-      !ReadParam(m, iter, &referenced_surfaces) ||
       !ReadParam(m, iter, &quad_list_size))
     return false;
 
@@ -424,7 +418,6 @@
             damage_rect,
             transform_to_root_target,
             has_transparent_background);
-  p->referenced_surfaces.swap(referenced_surfaces);
 
   for (size_t i = 0; i < quad_list_size; ++i) {
     cc::DrawQuad::Material material;
@@ -513,8 +506,6 @@
   l->append(", ");
   LogParam(p.has_transparent_background, l);
   l->append(", ");
-  LogParam(p.referenced_surfaces, l);
-  l->append(", ");
 
   l->append("[");
   for (const auto& shared_quad_state : p.shared_quad_state_list) {
diff --git a/content/common/cc_messages.h b/content/common/cc_messages.h
index f31964b..9f2e84ec 100644
--- a/content/common/cc_messages.h
+++ b/content/common/cc_messages.h
@@ -318,6 +318,7 @@
   IPC_STRUCT_TRAITS_MEMBER(selection)
   IPC_STRUCT_TRAITS_MEMBER(latency_info)
   IPC_STRUCT_TRAITS_MEMBER(satisfies_sequences)
+  IPC_STRUCT_TRAITS_MEMBER(referenced_surfaces)
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(cc::GLFrameData)
diff --git a/content/common/cc_messages_unittest.cc b/content/common/cc_messages_unittest.cc
index a94cd4a8e..87073960 100644
--- a/content/common/cc_messages_unittest.cc
+++ b/content/common/cc_messages_unittest.cc
@@ -52,7 +52,6 @@
     EXPECT_EQ(a->damage_rect.ToString(), b->damage_rect.ToString());
     EXPECT_EQ(a->transform_to_root_target, b->transform_to_root_target);
     EXPECT_EQ(a->has_transparent_background, b->has_transparent_background);
-    EXPECT_EQ(a->referenced_surfaces, b->referenced_surfaces);
   }
 
   void Compare(const SharedQuadState* a, const SharedQuadState* b) {
@@ -399,8 +398,6 @@
                      arbitrary_surface_id);
   pass_cmp->CopyFromAndAppendDrawQuad(surface_in,
                                       surface_in->shared_quad_state);
-  pass_in->referenced_surfaces.push_back(arbitrary_surface_id);
-  pass_cmp->referenced_surfaces.push_back(arbitrary_surface_id);
 
   TextureDrawQuad* texture_in =
       pass_in->CreateAndAppendDrawQuad<TextureDrawQuad>();
diff --git a/content/common/content_param_traits_macros.h b/content/common/content_param_traits_macros.h
index 67d7237..762436d 100644
--- a/content/common/content_param_traits_macros.h
+++ b/content/common/content_param_traits_macros.h
@@ -18,6 +18,7 @@
 #include "third_party/WebKit/public/web/WebCompositionUnderline.h"
 #include "third_party/WebKit/public/web/WebContentSecurityPolicy.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "third_party/WebKit/public/web/WebSharedWorkerCreationContextType.h"
 
 #undef IPC_MESSAGE_EXPORT
 #define IPC_MESSAGE_EXPORT CONTENT_EXPORT
@@ -32,6 +33,8 @@
                           content::REQUEST_CONTEXT_FRAME_TYPE_LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(blink::WebContentSecurityPolicyType,
                           blink::WebContentSecurityPolicyTypeLast)
+IPC_ENUM_TRAITS_MAX_VALUE(blink::WebSharedWorkerCreationContextType,
+                          blink::WebSharedWorkerCreationContextTypeLast)
 IPC_ENUM_TRAITS_MIN_MAX_VALUE(blink::WebInputEvent::Type,
                               blink::WebInputEvent::TypeFirst,
                               blink::WebInputEvent::TypeLast)
diff --git a/content/common/cursors/webcursor.cc b/content/common/cursors/webcursor.cc
index b2dfcdf..d610ceb 100644
--- a/content/common/cursors/webcursor.cc
+++ b/content/common/cursors/webcursor.cc
@@ -192,9 +192,9 @@
     { LoadCursor(NULL, IDC_APPSTARTING), WebCursorInfo::TypeProgress },
     { LoadCursor(NULL, IDC_NO),          WebCursorInfo::TypeNotAllowed },
   };
-  for (int i = 0; i < arraysize(kStandardCursors); ++i) {
-    if (cursor == kStandardCursors[i].cursor)
-      return kStandardCursors[i].type;
+  for (const auto& kStandardCursor : kStandardCursors) {
+    if (cursor == kStandardCursor.cursor)
+      return kStandardCursor.type;
   }
   return WebCursorInfo::TypeCustom;
 }
diff --git a/content/common/font_warmup_win_unittest.cc b/content/common/font_warmup_win_unittest.cc
index 80eb9e57b..c6ba7b1 100644
--- a/content/common/font_warmup_win_unittest.cc
+++ b/content/common/font_warmup_win_unittest.cc
@@ -256,9 +256,9 @@
 
   HDC hdc = CreateCompatibleDC(0);
   EXPECT_NE(hdc, nullptr);
-  EXPECT_EQ(GetEmulatedGdiHandleCountForTesting(), 1);
+  EXPECT_EQ(1u, GetEmulatedGdiHandleCountForTesting());
   EXPECT_TRUE(DeleteDC(hdc));
-  EXPECT_EQ(GetEmulatedGdiHandleCountForTesting(), 0);
+  EXPECT_EQ(0u, GetEmulatedGdiHandleCountForTesting());
 }
 
 TEST(GDIFontEmulationTest, CreateUniqueDCSuccess) {
@@ -274,9 +274,9 @@
   EXPECT_NE(hdc2, nullptr);
   EXPECT_NE(hdc1, hdc2);
   EXPECT_TRUE(DeleteDC(hdc2));
-  EXPECT_EQ(GetEmulatedGdiHandleCountForTesting(), 1);
+  EXPECT_EQ(1u, GetEmulatedGdiHandleCountForTesting());
   EXPECT_TRUE(DeleteDC(hdc1));
-  EXPECT_EQ(GetEmulatedGdiHandleCountForTesting(), 0);
+  EXPECT_EQ(0u, GetEmulatedGdiHandleCountForTesting());
 }
 
 TEST(GDIFontEmulationTest, CreateFontSuccess) {
@@ -290,7 +290,7 @@
   HFONT font = CreateFontIndirectW(&logfont);
   EXPECT_NE(font, nullptr);
   EXPECT_TRUE(DeleteObject(font));
-  EXPECT_EQ(GetEmulatedGdiHandleCountForTesting(), 0);
+  EXPECT_EQ(0u, GetEmulatedGdiHandleCountForTesting());
 }
 
 TEST(GDIFontEmulationTest, CreateFontFailure) {
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 36aebda..08b7337 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -40,6 +40,15 @@
 #include "content/common/pepper_renderer_instance_data.h"
 #endif
 
+// Singly-included section for type definitions.
+#ifndef CONTENT_COMMON_FRAME_MESSAGES_H_
+#define CONTENT_COMMON_FRAME_MESSAGES_H_
+
+using FrameMsg_GetSerializedHtmlWithLocalLinks_Map =
+    std::map<GURL, base::FilePath>;
+
+#endif  // CONTENT_COMMON_FRAME_MESSAGES_H_
+
 #undef IPC_MESSAGE_EXPORT
 #define IPC_MESSAGE_EXPORT CONTENT_EXPORT
 
@@ -324,6 +333,7 @@
   IPC_STRUCT_TRAITS_MEMBER(pending_history_list_offset)
   IPC_STRUCT_TRAITS_MEMBER(current_history_list_offset)
   IPC_STRUCT_TRAITS_MEMBER(current_history_list_length)
+  IPC_STRUCT_TRAITS_MEMBER(is_view_source)
   IPC_STRUCT_TRAITS_MEMBER(should_clear_history_list)
   IPC_STRUCT_TRAITS_MEMBER(should_create_service_worker)
   IPC_STRUCT_TRAITS_MEMBER(service_worker_provider_id)
@@ -714,10 +724,8 @@
 
 // Get html data by serializing the target frame and replacing all resource
 // links with a path to the local copy passed in the message payload.
-IPC_MESSAGE_ROUTED3(FrameMsg_GetSerializedHtmlWithLocalLinks,
-                    std::vector<GURL> /* urls that have local copy */,
-                    std::vector<base::FilePath> /* paths of local copy */,
-                    base::FilePath /* local directory path */)
+IPC_MESSAGE_ROUTED1(FrameMsg_GetSerializedHtmlWithLocalLinks,
+                    FrameMsg_GetSerializedHtmlWithLocalLinks_Map)
 
 IPC_MESSAGE_ROUTED1(FrameMsg_SetFrameOwnerProperties,
                     blink::WebFrameOwnerProperties /* frame_owner_properties */)
@@ -1224,9 +1232,22 @@
 
 // Sent when the renderer runs insecure content in a secure origin.
 IPC_MESSAGE_ROUTED2(FrameHostMsg_DidRunInsecureContent,
-                    std::string /* security_origin */,
+                    GURL /* security_origin */,
                     GURL /* target URL */)
 
+// Sent when the renderer displays content that was loaded with
+// certificate errors.
+IPC_MESSAGE_ROUTED2(FrameHostMsg_DidDisplayContentWithCertificateErrors,
+                    GURL /* resource url */,
+                    std::string /* serialized security info */)
+
+// Sent when the renderer runs content that was loaded with certificate
+// errors.
+IPC_MESSAGE_ROUTED3(FrameHostMsg_DidRunContentWithCertificateErrors,
+                    GURL /* security_origin */,
+                    GURL /* resource url */,
+                    std::string /* serialized security info */)
+
 // Response to FrameMsg_GetSavableResourceLinks.
 IPC_MESSAGE_ROUTED3(FrameHostMsg_SavableResourceLinksResponse,
                     std::vector<GURL> /* savable resource links */,
diff --git a/content/common/gpu/client/command_buffer_proxy_impl.cc b/content/common/gpu/client/command_buffer_proxy_impl.cc
index 47e20d1..22afb00 100644
--- a/content/common/gpu/client/command_buffer_proxy_impl.cc
+++ b/content/common/gpu/client/command_buffer_proxy_impl.cc
@@ -52,6 +52,7 @@
       verified_fence_sync_release_(0),
       next_signal_id_(0) {
   DCHECK(channel);
+  DCHECK(stream_id);
 }
 
 CommandBufferProxyImpl::~CommandBufferProxyImpl() {
@@ -449,7 +450,7 @@
 
   if (image_fence_sync) {
     gpu::SyncToken sync_token(GetNamespaceID(), GetCommandBufferID(),
-                              image_fence_sync);
+                              GetExtraCommandBufferData(), image_fence_sync);
 
     // Force a synchronous IPC to validate sync token.
     channel_->ValidateFlushIDReachedServer(stream_id_, true);
@@ -519,6 +520,10 @@
   return command_buffer_id_;
 }
 
+int32_t CommandBufferProxyImpl::GetExtraCommandBufferData() const {
+  return stream_id_;
+}
+
 uint64_t CommandBufferProxyImpl::GenerateFenceSyncRelease() {
   return next_fence_sync_release_++;
 }
@@ -577,8 +582,20 @@
   // Can only wait on an unverified sync token if it is from the same channel.
   const uint64_t token_channel = sync_token->command_buffer_id() >> 32;
   const uint64_t channel = command_buffer_id_ >> 32;
-  return (sync_token->namespace_id() == gpu::CommandBufferNamespace::GPU_IO &&
-          token_channel == channel);
+  if (sync_token->namespace_id() != gpu::CommandBufferNamespace::GPU_IO ||
+      token_channel != channel) {
+    return false;
+  }
+
+  // If waiting on a different stream, flush pending commands on that stream.
+  const int32_t release_stream_id = sync_token->extra_data_field();
+  if (release_stream_id == 0)
+    return false;
+
+  if (release_stream_id != stream_id_)
+    channel_->FlushPendingStream(release_stream_id);
+
+  return true;
 }
 
 uint32 CommandBufferProxyImpl::InsertSyncPoint() {
diff --git a/content/common/gpu/client/command_buffer_proxy_impl.h b/content/common/gpu/client/command_buffer_proxy_impl.h
index 047544a7..b5468a7f 100644
--- a/content/common/gpu/client/command_buffer_proxy_impl.h
+++ b/content/common/gpu/client/command_buffer_proxy_impl.h
@@ -122,6 +122,7 @@
   bool IsGpuChannelLost() override;
   gpu::CommandBufferNamespace GetNamespaceID() const override;
   uint64_t GetCommandBufferID() const override;
+  int32_t GetExtraCommandBufferData() const override;
   uint64_t GenerateFenceSyncRelease() override;
   bool IsFenceSyncRelease(uint64_t release) override;
   bool IsFenceSyncFlushed(uint64_t release) override;
diff --git a/content/common/gpu/client/gpu_channel_host.cc b/content/common/gpu/client/gpu_channel_host.cc
index 80dfe0a..652f93a 100644
--- a/content/common/gpu/client/gpu_channel_host.cc
+++ b/content/common/gpu/client/gpu_channel_host.cc
@@ -162,6 +162,17 @@
   return 0;
 }
 
+void GpuChannelHost::FlushPendingStream(int32 stream_id) {
+  AutoLock lock(context_lock_);
+  auto flush_info_iter = stream_flush_info_.find(stream_id);
+  if (flush_info_iter == stream_flush_info_.end())
+    return;
+
+  StreamFlushInfo& flush_info = flush_info_iter->second;
+  if (flush_info.flush_pending)
+    InternalFlush(&flush_info);
+}
+
 void GpuChannelHost::InternalFlush(StreamFlushInfo* flush_info) {
   context_lock_.AssertAcquired();
   DCHECK(flush_info);
@@ -396,7 +407,10 @@
 }
 
 int32 GpuChannelHost::GenerateStreamID() {
-  return next_stream_id_.GetNext();
+  const int32 stream_id = next_stream_id_.GetNext();
+  DCHECK_NE(0, stream_id);
+  DCHECK_NE(kDefaultStreamId, stream_id);
+  return stream_id;
 }
 
 uint32_t GpuChannelHost::ValidateFlushIDReachedServer(int32 stream_id,
diff --git a/content/common/gpu/client/gpu_channel_host.h b/content/common/gpu/client/gpu_channel_host.h
index b5488ed9..d33c7c7 100644
--- a/content/common/gpu/client/gpu_channel_host.h
+++ b/content/common/gpu/client/gpu_channel_host.h
@@ -88,7 +88,7 @@
       base::WaitableEvent* shutdown_event,
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager);
 
-  static const int32 kDefaultStreamId = 0;
+  static const int32 kDefaultStreamId = -1;
   static const GpuStreamPriority kDefaultStreamPriority =
       GpuStreamPriority::NORMAL;
 
@@ -116,6 +116,8 @@
                            bool put_offset_changed,
                            bool do_flush);
 
+  void FlushPendingStream(int32 stream_id);
+
   // Create and connect to a command buffer in the GPU process.
   scoped_ptr<CommandBufferProxyImpl> CreateViewCommandBuffer(
       int32 surface_id,
diff --git a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
index e2bf504..7ceb366 100644
--- a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
+++ b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
@@ -154,6 +154,8 @@
                  weak_ptr_factory_.GetWeakPtr()));
 
   real_gl_->SetErrorMessageCallback(getErrorMessageCallback());
+  real_gl_->TraceBeginCHROMIUM("WebGraphicsContext3D",
+                               "CommandBufferContext");
 
   visible_ = true;
   initialized_ = true;
diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc
index 86a3711..9dbe6b3 100644
--- a/content/common/gpu/gpu_command_buffer_stub.cc
+++ b/content/common/gpu/gpu_command_buffer_stub.cc
@@ -930,7 +930,7 @@
     // We can simply use the global sync point number as the release count with
     // 0 for the command buffer ID (under normal circumstances 0 is invalid so
     // will not be used) until the old sync points are replaced.
-    gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0,
+    gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0, 0,
                               sync_point);
     mailbox_manager->PushTextureUpdates(sync_token);
   }
@@ -986,7 +986,7 @@
   gpu::gles2::MailboxManager* mailbox_manager =
       context_group_->mailbox_manager();
   if (mailbox_manager->UsesSync() && MakeCurrent()) {
-    gpu::SyncToken sync_token(namespace_id, command_buffer_id, release);
+    gpu::SyncToken sync_token(namespace_id, 0, command_buffer_id, release);
     mailbox_manager->PullTextureUpdates(sync_token);
   }
 }
@@ -1044,7 +1044,7 @@
   gpu::gles2::MailboxManager* mailbox_manager =
       context_group_->mailbox_manager();
   if (mailbox_manager->UsesSync() && MakeCurrent()) {
-    gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO,
+    gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0,
                               command_buffer_id_, release);
     mailbox_manager->PushTextureUpdates(sync_token);
   }
diff --git a/content/common/media/media_stream_messages.h b/content/common/media/media_stream_messages.h
index 89753553..46acb9b 100644
--- a/content/common/media/media_stream_messages.h
+++ b/content/common/media/media_stream_messages.h
@@ -26,18 +26,17 @@
 IPC_ENUM_TRAITS_MAX_VALUE(content::MediaStreamRequestResult,
                           content::NUM_MEDIA_REQUEST_RESULTS - 1)
 
-IPC_STRUCT_TRAITS_BEGIN(content::StreamOptions::Constraint)
-  IPC_STRUCT_TRAITS_MEMBER(name)
-  IPC_STRUCT_TRAITS_MEMBER(value)
+IPC_STRUCT_TRAITS_BEGIN(content::TrackControls)
+  IPC_STRUCT_TRAITS_MEMBER(requested)
+  IPC_STRUCT_TRAITS_MEMBER(stream_source)
+  IPC_STRUCT_TRAITS_MEMBER(device_ids)
+  IPC_STRUCT_TRAITS_MEMBER(alternate_device_ids)
 IPC_STRUCT_TRAITS_END()
 
-IPC_STRUCT_TRAITS_BEGIN(content::StreamOptions)
-  IPC_STRUCT_TRAITS_MEMBER(audio_requested)
-  IPC_STRUCT_TRAITS_MEMBER(mandatory_audio)
-  IPC_STRUCT_TRAITS_MEMBER(optional_audio)
-  IPC_STRUCT_TRAITS_MEMBER(video_requested)
-  IPC_STRUCT_TRAITS_MEMBER(mandatory_video)
-  IPC_STRUCT_TRAITS_MEMBER(optional_video)
+IPC_STRUCT_TRAITS_BEGIN(content::StreamControls)
+  IPC_STRUCT_TRAITS_MEMBER(audio)
+  IPC_STRUCT_TRAITS_MEMBER(video)
+  IPC_STRUCT_TRAITS_MEMBER(hotword_enabled)
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(content::StreamDeviceInfo)
@@ -102,7 +101,7 @@
 IPC_MESSAGE_CONTROL5(MediaStreamHostMsg_GenerateStream,
                      int /* render frame id */,
                      int /* request id */,
-                     content::StreamOptions /* components */,
+                     content::StreamControls /* controls */,
                      GURL /* security origin */,
                      bool /* user_gesture */)
 
diff --git a/content/common/media/media_stream_options.cc b/content/common/media/media_stream_options.cc
index 795e36c..c942f46 100644
--- a/content/common/media/media_stream_options.cc
+++ b/content/common/media/media_stream_options.cc
@@ -21,80 +21,21 @@
 // constraints for audio.
 const char kMediaStreamAudioHotword[] = "googHotword";
 
-namespace {
+TrackControls::TrackControls()
+    : requested(false) {}
 
-bool GetFirstConstraintByName(const StreamOptions::Constraints& constraints,
-                              const std::string& name,
-                              std::string* value) {
-  for (StreamOptions::Constraints::const_iterator it = constraints.begin();
-      it != constraints.end(); ++it ) {
-    if (it->name == name) {
-      *value = it->value;
-      return true;
-    }
-  }
-  return false;
-}
+TrackControls::TrackControls(bool request)
+    : requested(request) {}
 
-bool GetFirstConstraintByName(const StreamOptions::Constraints& mandatory,
-                              const StreamOptions::Constraints& optional,
-                              const std::string& name,
-                              std::string* value,
-                              bool* is_mandatory) {
-  if (GetFirstConstraintByName(mandatory, name, value)) {
-    if (is_mandatory)
-      *is_mandatory = true;
-    return true;
-  }
-  if (is_mandatory)
-    *is_mandatory = false;
-  return GetFirstConstraintByName(optional, name, value);
-}
+TrackControls::~TrackControls() {}
 
-} // namespace
+StreamControls::StreamControls()
+    : audio(false), video(false), hotword_enabled(false) {}
 
-StreamOptions::StreamOptions()
-    : audio_requested(false),
-      video_requested(false) {}
+StreamControls::StreamControls(bool request_audio, bool request_video)
+    : audio(request_audio), video(request_video), hotword_enabled(false) {}
 
-StreamOptions::StreamOptions(bool request_audio, bool request_video)
-    :  audio_requested(request_audio), video_requested(request_video) {
-}
-
-StreamOptions::~StreamOptions() {}
-
-StreamOptions::Constraint::Constraint() {}
-
-StreamOptions::Constraint::Constraint(const std::string& name,
-                                      const std::string& value)
-    : name(name), value(value) {
-}
-
-bool StreamOptions::GetFirstAudioConstraintByName(const std::string& name,
-                                                  std::string* value,
-                                                  bool* is_mandatory) const {
-  return GetFirstConstraintByName(mandatory_audio, optional_audio, name, value,
-                                  is_mandatory);
-}
-
-bool StreamOptions::GetFirstVideoConstraintByName(const std::string& name,
-                                                  std::string* value,
-                                                  bool* is_mandatory) const {
-  return GetFirstConstraintByName(mandatory_video, optional_video, name, value,
-                                  is_mandatory);
-}
-
-// static
-void StreamOptions::GetConstraintsByName(
-    const StreamOptions::Constraints& constraints,
-    const std::string& name,
-    std::vector<std::string>* values) {
-  for (StreamOptions::Constraints::const_iterator it = constraints.begin();
-      it != constraints.end(); ++it ) {
-    if (it->name == name)
-      values->push_back(it->value);
-  }
-}
+StreamControls::~StreamControls() {}
 
 // static
 const int StreamDeviceInfo::kNoId = -1;
diff --git a/content/common/media/media_stream_options.h b/content/common/media/media_stream_options.h
index e795fdb..4d61d57 100644
--- a/content/common/media/media_stream_options.h
+++ b/content/common/media/media_stream_options.h
@@ -32,60 +32,41 @@
 // it.
 CONTENT_EXPORT extern const char kMediaStreamAudioHotword[];
 
-// StreamOptions is a Chromium representation of constraints
-// used in WebUserMediaRequest.
-// It describes properties requested by JS in a request for a new
-// media stream.
-class CONTENT_EXPORT StreamOptions {
+struct CONTENT_EXPORT TrackControls {
  public:
-  StreamOptions();
-  StreamOptions(bool request_audio, bool request_video);
-  ~StreamOptions();
+  TrackControls();
+  TrackControls(bool request);
+  ~TrackControls();
+  bool requested;
 
-  struct CONTENT_EXPORT Constraint {
-    Constraint();
-    Constraint(const std::string& name,
-               const std::string& value);
+  // Source. This is "tab", "screen", "desktop", "system", or blank.
+  // Consider replacing with MediaStreamType enum variables.
+  std::string stream_source;  // audio.kMediaStreamSource
 
-    std::string name;
-    std::string value;
-  };
-  typedef std::vector<Constraint> Constraints;
+  // Device ID requests.
+  // The first set represents required devices - either grab one or fail.
+  // The second set represents optional devices - if we can't get one of
+  // these, we will grab the default device (if possible).
+  // The constraint names are "sourceId" and "chromeMediaSourceId".
+  std::vector<std::string> device_ids;
+  std::vector<std::string> alternate_device_ids;
+};
 
-  bool audio_requested;
-  Constraints mandatory_audio;
-  Constraints optional_audio;
-
-  bool video_requested;
-  Constraints mandatory_video;
-  Constraints optional_video;
-
-  // Fetches |value| from the first audio constraint with a name that matches
-  // |name| from |mandatory_audio| and |optional_audio|. First mandatory
-  // constraints are searched, then optional.
-  // |is_mandatory| may be NULL but if it is provided, it is set
-  // to true if the found constraint is mandatory.
-  // Returns false if no constraint is found.
-  bool GetFirstAudioConstraintByName(const std::string& name,
-                                     std::string* value,
-                                     bool* is_mandatory) const;
-
-  // Fetches |value| from the first video constraint with a name that matches
-  // |name| from |mandatory_video| and |optional_video|. First mandatory
-  // constraints are searched, then optional.
-  // |is_mandatory| may be NULL but if it is provided, it is set
-  // to true if the found constraint is mandatory.
-  // Returns false if no constraint is found.
-  bool GetFirstVideoConstraintByName(const std::string& name,
-                                     std::string* value,
-                                     bool* is_mandatory) const;
-
-  // Fetches |values| from all constraint with a name that matches |name|
-  // from |constraints|.
-  static void GetConstraintsByName(
-      const StreamOptions::Constraints& constraints,
-      const std::string& name,
-      std::vector<std::string>* values);
+// StreamControls describes what is sent to the browser process
+// to the renderer process in order to control the opening of a device
+// pair. This may result in opening one audio and/or one video device.
+// This has to be a struct with public members in order to allow it to
+// be sent in the IPC of media_stream_messages.h
+struct CONTENT_EXPORT StreamControls {
+ public:
+  StreamControls();
+  StreamControls(bool request_audio, bool request_video);
+  ~StreamControls();
+  TrackControls audio;
+  TrackControls video;
+  // Hotword functionality (chromeos only)
+  // See crbug.com/564574 for discussion on possibly #ifdef'ing this out.
+  bool hotword_enabled;  // kMediaStreamAudioHotword = "googHotword";
 };
 
 // StreamDeviceInfo describes information about a device.
diff --git a/content/common/navigation_params.cc b/content/common/navigation_params.cc
index 790f2d2e..f54e876 100644
--- a/content/common/navigation_params.cc
+++ b/content/common/navigation_params.cc
@@ -127,6 +127,7 @@
       pending_history_list_offset(-1),
       current_history_list_offset(-1),
       current_history_list_length(0),
+      is_view_source(false),
       should_clear_history_list(false),
       should_create_service_worker(false),
       service_worker_provider_id(kInvalidServiceWorkerProviderId) {}
@@ -145,6 +146,7 @@
     int pending_history_list_offset,
     int current_history_list_offset,
     int current_history_list_length,
+    bool is_view_source,
     bool should_clear_history_list)
     : is_overriding_user_agent(is_overriding_user_agent),
       redirects(redirects),
@@ -159,6 +161,7 @@
       pending_history_list_offset(pending_history_list_offset),
       current_history_list_offset(current_history_list_offset),
       current_history_list_length(current_history_list_length),
+      is_view_source(is_view_source),
       should_clear_history_list(should_clear_history_list),
       should_create_service_worker(false),
       service_worker_provider_id(kInvalidServiceWorkerProviderId) {}
diff --git a/content/common/navigation_params.h b/content/common/navigation_params.h
index d4f88dc..7caceeb 100644
--- a/content/common/navigation_params.h
+++ b/content/common/navigation_params.h
@@ -224,6 +224,7 @@
                           int pending_history_list_offset,
                           int current_history_list_offset,
                           int current_history_list_length,
+                          bool is_view_source,
                           bool should_clear_history_list);
   ~RequestNavigationParams();
 
@@ -283,6 +284,12 @@
   int current_history_list_offset;
   int current_history_list_length;
 
+  // Indicates whether the navigation is to a view-source:// scheme or not.
+  // It is a separate boolean as the view-source scheme is stripped from the
+  // URL before it is sent to the renderer process and the RenderFrame needs
+  // to be put in special view source mode.
+  bool is_view_source;
+
   // Whether session history should be cleared. In that case, the RenderView
   // needs to notify the browser that the clearing was succesful when the
   // navigation commits.
diff --git a/content/common/pepper_file_util.cc b/content/common/pepper_file_util.cc
index 6264faa5..4e5df94 100644
--- a/content/common/pepper_file_util.cc
+++ b/content/common/pepper_file_util.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "content/common/pepper_file_util.h"
+#include "ppapi/shared_impl/platform_file.h"
 
 namespace content {
 
@@ -22,13 +23,7 @@
 
 int IntegerFromSyncSocketHandle(
     const base::SyncSocket::Handle& socket_handle) {
-#if defined(OS_WIN)
-  return reinterpret_cast<int>(socket_handle);
-#elif defined(OS_POSIX)
-  return socket_handle;
-#else
-#error Platform not supported.
-#endif
+  return ppapi::PlatformFileToInt(socket_handle);
 }
 
 }  // namespace content
diff --git a/content/common/resource_messages.cc b/content/common/resource_messages.cc
index d5eff4cd..5ce7bda 100644
--- a/content/common/resource_messages.cc
+++ b/content/common/resource_messages.cc
@@ -12,9 +12,9 @@
 namespace content {
 // TODO(erikchen): Temporary code to help track http://crbug.com/527588.
 void CheckContentsOfResourceMessage(const IPC::Message* message) {
-  if (message->type() == ResourceMsg_DataReceived::ID) {
-    ResourceMsg_DataReceived::Schema::Param arg;
-    bool success = ResourceMsg_DataReceived::Read(message, &arg);
+  if (message->type() == ResourceMsg_DataReceivedDebug::ID) {
+    ResourceMsg_DataReceivedDebug::Schema::Param arg;
+    bool success = ResourceMsg_DataReceivedDebug::Read(message, &arg);
     CHECK(success);
     int data_offset = base::get<1>(arg);
     CHECK_LE(data_offset, 512 * 1024);
diff --git a/content/common/resource_messages.h b/content/common/resource_messages.h
index e015a105..65e7f00 100644
--- a/content/common/resource_messages.h
+++ b/content/common/resource_messages.h
@@ -119,6 +119,7 @@
   IPC_STRUCT_TRAITS_MEMBER(mime_type)
   IPC_STRUCT_TRAITS_MEMBER(charset)
   IPC_STRUCT_TRAITS_MEMBER(security_info)
+  IPC_STRUCT_TRAITS_MEMBER(has_major_certificate_errors)
   IPC_STRUCT_TRAITS_MEMBER(content_length)
   IPC_STRUCT_TRAITS_MEMBER(encoded_data_length)
   IPC_STRUCT_TRAITS_MEMBER(appcache_id)
@@ -346,6 +347,12 @@
                      int /* shm_size */,
                      base::ProcessId /* renderer_pid */)
 
+// A message that always precedes ResourceMsg_DataReceived. Exists to help debug
+// https://code.google.com/p/chromium/issues/detail?id=527588.
+IPC_MESSAGE_CONTROL2(ResourceMsg_DataReceivedDebug,
+                     int /* request_id */,
+                     int /* data_offset */)
+
 // Sent when some data from a resource request is ready.  The data offset and
 // length specify a byte range into the shared memory buffer provided by the
 // SetDataBuffer message.
diff --git a/content/common/sandbox_win.cc b/content/common/sandbox_win.cc
index a3554a23..5f0c5b24 100644
--- a/content/common/sandbox_win.cc
+++ b/content/common/sandbox_win.cc
@@ -24,6 +24,7 @@
 #include "base/win/iat_patch_function.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/scoped_process_information.h"
+#include "base/win/win_util.h"
 #include "base/win/windows_version.h"
 #include "content/common/content_switches_internal.h"
 #include "content/public/common/content_client.h"
@@ -743,8 +744,9 @@
       if (direct_write_font_cache_section.Open(name, true)) {
         void* shared_handle = policy->AddHandleToShare(
             direct_write_font_cache_section.handle().GetHandle());
-        cmd_line->AppendSwitchASCII(switches::kFontCacheSharedHandle,
-            base::UintToString(reinterpret_cast<unsigned int>(shared_handle)));
+        cmd_line->AppendSwitchASCII(
+            switches::kFontCacheSharedHandle,
+            base::UintToString(base::win::HandleToUint32(shared_handle)));
       }
     }
   }
@@ -814,7 +816,7 @@
 
   delegate->PostSpawnTarget(target.process_handle());
 
-  CHECK(ResumeThread(target.thread_handle()) != -1);
+  CHECK(ResumeThread(target.thread_handle()) != static_cast<DWORD>(-1));
   return base::Process(target.TakeProcessHandle());
 }
 
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index e1375a5..a95ad796 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -50,6 +50,7 @@
 #include "third_party/WebKit/public/web/WebMediaPlayerAction.h"
 #include "third_party/WebKit/public/web/WebPluginAction.h"
 #include "third_party/WebKit/public/web/WebPopupType.h"
+#include "third_party/WebKit/public/web/WebSharedWorkerCreationContextType.h"
 #include "third_party/WebKit/public/web/WebSharedWorkerCreationErrors.h"
 #include "third_party/WebKit/public/web/WebTextDirection.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -377,6 +378,10 @@
 
   // RenderFrame routing id used to send messages back to the parent.
   IPC_STRUCT_MEMBER(int, render_frame_route_id)
+
+  // The type (secure or nonsecure) of the context that created the worker.
+  IPC_STRUCT_MEMBER(blink::WebSharedWorkerCreationContextType,
+                    creation_context_type)
 IPC_STRUCT_END()
 
 IPC_STRUCT_BEGIN(ViewHostMsg_CreateWorker_Reply)
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 29c063e7..4e803add 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -906,6 +906,10 @@
       'browser/indexed_db/leveldb/leveldb_write_batch.h',
       'browser/loader/async_resource_handler.cc',
       'browser/loader/async_resource_handler.h',
+      'browser/loader/async_revalidation_driver.cc',
+      'browser/loader/async_revalidation_driver.h',
+      'browser/loader/async_revalidation_manager.cc',
+      'browser/loader/async_revalidation_manager.h',
       'browser/loader/certificate_resource_handler.cc',
       'browser/loader/certificate_resource_handler.h',
       'browser/loader/cross_site_resource_handler.cc',
@@ -1002,6 +1006,9 @@
       'browser/media/capture/web_contents_tracker.h',
       'browser/media/capture/web_contents_video_capture_device.cc',
       'browser/media/capture/web_contents_video_capture_device.h',
+      'browser/media/capture/window_activity_tracker.h',
+      'browser/media/capture/window_activity_tracker_aura.cc',
+      'browser/media/capture/window_activity_tracker_aura.h',
       'browser/media/media_internals.cc',
       'browser/media/media_internals.h',
       'browser/media/media_internals_handler.cc',
@@ -1010,6 +1017,8 @@
       'browser/media/media_internals_proxy.h',
       'browser/media/media_internals_ui.cc',
       'browser/media/media_internals_ui.h',
+      'browser/media/media_web_contents_observer.cc',
+      'browser/media/media_web_contents_observer.h',
       'browser/media/midi_host.cc',
       'browser/media/midi_host.h',
       'browser/media/webrtc_identity_store.cc',
@@ -2175,9 +2184,6 @@
       'sources': [
         'browser/media/cdm/browser_cdm_manager.cc',
         'browser/media/cdm/browser_cdm_manager.h',
-        # This works on Android because enable_browser_cdms==1 on Android.
-        'browser/media/media_web_contents_observer.cc',
-        'browser/media/media_web_contents_observer.h',
       ],
     }],
     ['OS == "linux"', {
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index 8b91ee3e1..a7ad29d 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -15,6 +15,7 @@
     '../components/url_formatter/url_formatter.gyp:url_formatter',
     '../device/battery/battery.gyp:device_battery',
     '../device/battery/battery.gyp:device_battery_mojo_bindings',
+    '../device/devices_app/devices_app.gyp:device_usb_mojo_bindings_lib',
     '../device/vibration/vibration.gyp:device_vibration',
     '../device/vibration/vibration.gyp:device_vibration_mojo_bindings',
     '../gin/gin.gyp:gin',
@@ -805,12 +806,6 @@
     ['OS=="android"', {
       'sources!': [
         'renderer/media/audio_decoder.cc',
-        'renderer/usb/type_converters.cc',
-        'renderer/usb/type_converters.h',
-        'renderer/usb/web_usb_client_impl.cc',
-        'renderer/usb/web_usb_client_impl.h',
-        'renderer/usb/web_usb_device_impl.cc',
-        'renderer/usb/web_usb_device_impl.h',
       ],
       'sources': [
         'renderer/external_popup_menu.cc',
@@ -821,7 +816,6 @@
         '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber',
       ],
       'dependencies!': [
-        '../components/components.gyp:webusb',
         '../device/battery/battery.gyp:device_battery',
       ],
     }, {
@@ -836,8 +830,6 @@
         'renderer/java/gin_java_function_invocation_helper.h',
       ],
       'dependencies': [
-        '../device/devices_app/devices_app.gyp:device_usb_mojo_bindings_lib',
-        '../device/devices_app/devices_app.gyp:devices_app_public_cpp',
         '../media/cast/cast.gyp:cast_sender',
       ]
     }],
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 5dfc0a5..ef88817 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -243,6 +243,7 @@
       'browser/message_port_provider_browsertest.cc',
       'browser/mojo_shell_browsertest.cc',
       'browser/net_info_browsertest.cc',
+      'browser/renderer_host/input/composited_scrolling_browsertest.cc',
       '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',
@@ -488,6 +489,8 @@
       'browser/indexed_db/mock_indexed_db_database_callbacks.h',
       'browser/indexed_db/mock_indexed_db_factory.cc',
       'browser/indexed_db/mock_indexed_db_factory.h',
+      'browser/loader/async_revalidation_driver_unittest.cc',
+      'browser/loader/async_revalidation_manager_unittest.cc',
       'browser/loader/mime_type_resource_handler_unittest.cc',
       'browser/loader/navigation_url_loader_unittest.cc',
       'browser/loader/resource_buffer_unittest.cc',
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index 46e147a..66e8177 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -293,6 +293,9 @@
                                                  int cdm_id) const = 0;
 #endif
 
+  // Returns true if this process currently has backgrounded priority.
+  virtual bool IsProcessBackgrounded() const = 0;
+
   // Returns the current number of active views in this process.  Excludes
   // any RenderViewHosts that are swapped out.
   size_t GetActiveViewCount();
diff --git a/content/public/browser/resource_throttle.h b/content/public/browser/resource_throttle.h
index 240d95e..010e16c 100644
--- a/content/public/browser/resource_throttle.h
+++ b/content/public/browser/resource_throttle.h
@@ -5,17 +5,15 @@
 #ifndef CONTENT_PUBLIC_BROWSER_RESOURCE_THROTTLE_H_
 #define CONTENT_PUBLIC_BROWSER_RESOURCE_THROTTLE_H_
 
-#include <vector>
-
-class GURL;
-
 namespace net {
 struct RedirectInfo;
 }
 
 namespace content {
 
+class AsyncRevalidationDriver;
 class ResourceController;
+class ThrottlingResourceHandler;
 
 // A ResourceThrottle gets notified at various points during the process of
 // loading a resource.  At each stage, it has the opportunity to defer the
@@ -56,6 +54,7 @@
   ResourceController* controller() { return controller_; }
 
  private:
+  friend class AsyncRevalidationDriver;
   friend class ThrottlingResourceHandler;
   void set_controller(ResourceController* c) { controller_ = c; }
 
diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h
index 92bf977..f77f911 100644
--- a/content/public/browser/web_contents_observer.h
+++ b/content/public/browser/web_contents_observer.h
@@ -424,11 +424,14 @@
   // Invoked when theme color is changed to |theme_color|.
   virtual void DidChangeThemeColor(SkColor theme_color) {}
 
-  // Invoked when media is playing.
-  virtual void MediaStartedPlaying() {}
-
-  // Invoked when media is paused.
-  virtual void MediaPaused() {}
+  // Invoked when media is playing or paused.  |id| is unique per player and per
+  // RenderFrameHost.  There may be multiple players within a RenderFrameHost
+  // and subsequently within a WebContents.  MediaStartedPlaying() will always
+  // be followed by MediaStoppedPlaying() after player teardown.  Observers must
+  // release all stored copies of |id| when MediaStoppedPlaying() is received.
+  using MediaPlayerId = std::pair<RenderFrameHost*, int64_t>;
+  virtual void MediaStartedPlaying(const MediaPlayerId& id) {}
+  virtual void MediaStoppedPlaying(const MediaPlayerId& id) {}
 
   // Invoked when media session has changed its state.
   virtual void MediaSessionStateChanged(bool is_controllable,
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn
index 9c1e0f7..b8a7cd1 100644
--- a/content/public/common/BUILD.gn
+++ b/content/public/common/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/chromecast_build.gni")
 import("//build/config/features.gni")
 import("//content/common/common.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
@@ -48,7 +49,7 @@
 # Mojo shell.
 config("mojo_shell_client") {
   # This configuration has only been tested on these platforms.
-  if (is_win || is_linux || is_chromeos) {
+  if ((is_win || is_linux || is_chromeos) && !is_chromecast) {
     defines = [ "MOJO_SHELL_CLIENT" ]
   }
 }
diff --git a/content/public/common/common_param_traits.h b/content/public/common/common_param_traits.h
index 69fb84a..170caad 100644
--- a/content/public/common/common_param_traits.h
+++ b/content/public/common/common_param_traits.h
@@ -25,6 +25,10 @@
 #include "url/gurl.h"
 #include "url/origin.h"
 
+#if defined(OS_WIN)
+#include "base/win/win_util.h"
+#endif
+
 namespace content {
 class PageState;
 }
@@ -81,8 +85,7 @@
   typedef gfx::NativeWindow param_type;
   static void Write(Message* m, const param_type& p) {
 #if defined(OS_WIN)
-    // HWNDs are always 32 bits on Windows, even on 64 bit systems.
-    m->WriteUInt32(reinterpret_cast<uint32>(p));
+    m->WriteUInt32(base::win::HandleToUint32(p));
 #else
     m->WriteData(reinterpret_cast<const char*>(&p), sizeof(p));
 #endif
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 51a0b014..5db5df6 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -435,6 +435,11 @@
 // Enable spatial navigation
 const char kEnableSpatialNavigation[]       = "enable-spatial-navigation";
 
+// Enables implementation of the Cache-Control: stale-while-revalidate directive
+// which permits servers to allow the use of stale resources while revalidation
+// proceeds in the background.
+const char kEnableStaleWhileRevalidate[]    = "enable-stale-while-revalidate";
+
 // Enables StatsTable, logging statistics to a global named shared memory table.
 const char kEnableStatsTable[]              = "enable-stats-table";
 
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index afed374..24056b6 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -130,6 +130,7 @@
 CONTENT_EXPORT extern const char kEnableSlimmingPaintV2[];
 CONTENT_EXPORT extern const char kEnableSmoothScrolling[];
 CONTENT_EXPORT extern const char kEnableSpatialNavigation[];
+CONTENT_EXPORT extern const char kEnableStaleWhileRevalidate[];
 CONTENT_EXPORT extern const char kEnableStatsTable[];
 CONTENT_EXPORT extern const char kEnableStrictMixedContentChecking[];
 CONTENT_EXPORT extern const char kEnableStrictPowerfulFeatureRestrictions[];
diff --git a/content/public/common/resource_response.cc b/content/public/common/resource_response.cc
index 12f1dd7..12773554 100644
--- a/content/public/common/resource_response.cc
+++ b/content/public/common/resource_response.cc
@@ -19,6 +19,8 @@
   new_response->head.mime_type = head.mime_type;
   new_response->head.charset = head.charset;
   new_response->head.security_info = head.security_info;
+  new_response->head.has_major_certificate_errors =
+      head.has_major_certificate_errors;
   new_response->head.content_length = head.content_length;
   new_response->head.encoded_data_length = head.encoded_data_length;
   new_response->head.appcache_id = head.appcache_id;
diff --git a/content/public/common/resource_response_info.cc b/content/public/common/resource_response_info.cc
index 1d4e304..f05ee19 100644
--- a/content/public/common/resource_response_info.cc
+++ b/content/public/common/resource_response_info.cc
@@ -10,7 +10,8 @@
 namespace content {
 
 ResourceResponseInfo::ResourceResponseInfo()
-    : content_length(-1),
+    : has_major_certificate_errors(false),
+      content_length(-1),
       encoded_data_length(-1),
       appcache_id(kAppCacheNoCacheId),
       was_fetched_via_spdy(false),
@@ -22,8 +23,7 @@
       was_fallback_required_by_service_worker(false),
       response_type_via_service_worker(
           blink::WebServiceWorkerResponseTypeDefault),
-      is_using_lofi(false) {
-}
+      is_using_lofi(false) {}
 
 ResourceResponseInfo::~ResourceResponseInfo() {
 }
diff --git a/content/public/common/resource_response_info.h b/content/public/common/resource_response_info.h
index 1a0f126..8b81f6d 100644
--- a/content/public/common/resource_response_info.h
+++ b/content/public/common/resource_response_info.h
@@ -50,6 +50,9 @@
   // response.  This may include information about the SSL connection used.
   std::string security_info;
 
+  // True if the resource was loaded in spite of certificate errors.
+  bool has_major_certificate_errors;
+
   // Content length if available. -1 if not available
   int64 content_length;
 
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index 669a85d4..28689837 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -144,12 +144,9 @@
   base::mac::SetOverrideAmIBundled(true);
 #endif
 
-#if defined(USE_AURA)
-#if defined(USE_X11)
+#if defined(USE_AURA) && defined(USE_X11)
   aura::test::SetUseOverrideRedirectWindowByDefault(true);
 #endif
-  aura::test::InitializeAuraEventGeneratorDelegate();
-#endif
 
 #if defined(OS_POSIX)
   handle_sigterm_ = true;
@@ -215,6 +212,8 @@
   // us to, or it's requested on the command line.
   if (!enable_pixel_output_ && !use_software_compositing_)
     command_line->AppendSwitch(switches::kDisableGLDrawingForTests);
+
+  aura::test::InitializeAuraEventGeneratorDelegate();
 #endif
 
   bool use_osmesa = true;
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc
index aef164f..55be9ff 100644
--- a/content/public/test/mock_render_process_host.cc
+++ b/content/public/test/mock_render_process_host.cc
@@ -42,7 +42,8 @@
       prev_routing_id_(0),
       fast_shutdown_started_(false),
       deletion_callback_called_(false),
-      is_for_guests_only_(false) {
+      is_for_guests_only_(false),
+      is_process_backgrounded_(false) {
   // Child process security operations can't be unit tested unless we add
   // ourselves as an existing child process.
   ChildProcessSecurityPolicyImpl::GetInstance()->Add(GetID());
@@ -293,6 +294,10 @@
 }
 #endif
 
+bool MockRenderProcessHost::IsProcessBackgrounded() const {
+  return is_process_backgrounded_;
+}
+
 void MockRenderProcessHost::FilterURL(bool empty_allowed, GURL* url) {
   RenderProcessHostImpl::FilterURL(this, empty_allowed, url);
 }
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h
index 2ff295c..e0b9c7d 100644
--- a/content/public/test/mock_render_process_host.h
+++ b/content/public/test/mock_render_process_host.h
@@ -96,6 +96,7 @@
   scoped_refptr<media::MediaKeys> GetCdm(int render_frame_id,
                                          int cdm_id) const override;
 #endif
+  bool IsProcessBackgrounded() const override;
 
   // IPC::Sender via RenderProcessHost.
   bool Send(IPC::Message* msg) override;
@@ -114,6 +115,10 @@
     is_for_guests_only_ = is_for_guests_only;
   }
 
+  void set_is_process_backgrounded(bool is_process_backgrounded) {
+    is_process_backgrounded_ = is_process_backgrounded;
+  }
+
   void SetProcessHandle(scoped_ptr<base::ProcessHandle> new_handle) {
     process_handle = new_handle.Pass();
   }
@@ -137,6 +142,7 @@
   bool fast_shutdown_started_;
   bool deletion_callback_called_;
   bool is_for_guests_only_;
+  bool is_process_backgrounded_;
   scoped_ptr<base::ProcessHandle> process_handle;
 
   DISALLOW_COPY_AND_ASSIGN(MockRenderProcessHost);
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index f009eeed..ad5a503 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -41,6 +41,7 @@
     "//content/public/common:mojo_bindings",
     "//crypto:platform",
     "//device/battery:mojo_bindings",
+    "//device/devices_app/usb/public/interfaces",
     "//device/vibration:mojo_bindings",
     "//gin",
     "//gpu",
@@ -92,15 +93,7 @@
   }
 
   if (is_android) {
-    sources -= [
-      "media/audio_decoder.cc",
-      "usb/type_converters.cc",
-      "usb/type_converters.h",
-      "usb/web_usb_client_impl.cc",
-      "usb/web_usb_client_impl.h",
-      "usb/web_usb_device_impl.cc",
-      "usb/web_usb_device_impl.h",
-    ]
+    sources -= [ "media/audio_decoder.cc" ]
     sources += [
       "external_popup_menu.cc",
       "external_popup_menu.h",
@@ -114,8 +107,6 @@
       "//third_party/android_tools:cpu_features",
       "//third_party/libphonenumber",
     ]
-
-    deps -= [ "//components/webusb" ]
   } else {
     sources -= [
       "java/gin_java_bridge_dispatcher.cc",
@@ -127,11 +118,6 @@
       "java/gin_java_function_invocation_helper.cc",
       "java/gin_java_function_invocation_helper.h",
     ]
-
-    deps += [
-      "//device/devices_app/public/cpp",
-      "//device/devices_app/usb/public/interfaces",
-    ]
   }
 
   # TODO(jrg): remove the OS=="android" section?
diff --git a/content/renderer/android/synchronous_compositor_output_surface.cc b/content/renderer/android/synchronous_compositor_output_surface.cc
index 7b829f9..8362530 100644
--- a/content/renderer/android/synchronous_compositor_output_surface.cc
+++ b/content/renderer/android/synchronous_compositor_output_surface.cc
@@ -263,7 +263,7 @@
 }
 
 void SynchronousCompositorOutputSurface::GetMessagesToDeliver(
-    ScopedVector<IPC::Message>* messages) {
+    std::vector<scoped_ptr<IPC::Message>>* messages) {
   DCHECK(CalledOnValidThread());
   scoped_ptr<FrameSwapMessageQueue::SendMessageScope> send_message_scope =
       frame_swap_message_queue_->AcquireSendMessageScope();
diff --git a/content/renderer/android/synchronous_compositor_output_surface.h b/content/renderer/android/synchronous_compositor_output_surface.h
index 337b066d..f183d1f 100644
--- a/content/renderer/android/synchronous_compositor_output_surface.h
+++ b/content/renderer/android/synchronous_compositor_output_surface.h
@@ -82,7 +82,7 @@
   scoped_ptr<cc::CompositorFrame> DemandDrawSw(SkCanvas* canvas);
   void SetMemoryPolicy(size_t bytes_limit);
   void SetTreeActivationCallback(const base::Closure& callback);
-  void GetMessagesToDeliver(ScopedVector<IPC::Message>* messages);
+  void GetMessagesToDeliver(std::vector<scoped_ptr<IPC::Message>>* messages);
 
   size_t GetMemoryPolicy() const {
     return memory_policy_.bytes_limit_when_visible;
diff --git a/content/renderer/android/synchronous_compositor_proxy.cc b/content/renderer/android/synchronous_compositor_proxy.cc
index 5b83d2f..e176975 100644
--- a/content/renderer/android/synchronous_compositor_proxy.cc
+++ b/content/renderer/android/synchronous_compositor_proxy.cc
@@ -110,12 +110,11 @@
 }
 
 void SynchronousCompositorProxy::DeliverMessages() {
-  ScopedVector<IPC::Message> messages;
+  std::vector<scoped_ptr<IPC::Message>> messages;
   output_surface_->GetMessagesToDeliver(&messages);
-  for (auto* message : messages) {
-    Send(message);
+  for (auto& msg : messages) {
+    Send(msg.release());
   }
-  messages.weak_clear();  // Don't double delete.
 }
 
 void SynchronousCompositorProxy::SendAsyncRendererStateIfNeeded() {
diff --git a/content/renderer/browser_plugin/OWNERS b/content/renderer/browser_plugin/OWNERS
index 0521a45..e3502a8 100644
--- a/content/renderer/browser_plugin/OWNERS
+++ b/content/renderer/browser_plugin/OWNERS
@@ -1,3 +1,4 @@
 fsamuel@chromium.org
 lazyboy@chromium.org
+lfg@chromium.org
 wjmaclean@chromium.org
diff --git a/content/renderer/dom_serializer_browsertest.cc b/content/renderer/dom_serializer_browsertest.cc
index 5dc4c68..1737cac9 100644
--- a/content/renderer/dom_serializer_browsertest.cc
+++ b/content/renderer/dom_serializer_browsertest.cc
@@ -77,9 +77,7 @@
 class DomSerializerTests : public ContentBrowserTest,
                            public WebPageSerializerClient {
  public:
-  DomSerializerTests()
-      : serialization_reported_end_of_data_(false),
-        local_directory_name_(FILE_PATH_LITERAL("./dummy_files/")) {}
+  DomSerializerTests() : serialization_reported_end_of_data_(false) {}
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitch(switches::kSingleProcess);
@@ -161,18 +159,14 @@
     // Find corresponding WebFrame according to frame_url.
     WebFrame* web_frame = FindSubFrameByURL(frame_url);
     ASSERT_TRUE(web_frame != NULL);
-    WebVector<WebURL> links;
-    links.assign(&frame_url, 1);
     WebString file_path =
         base::FilePath(FILE_PATH_LITERAL("c:\\dummy.htm")).AsUTF16Unsafe();
-    WebVector<WebString> local_paths;
-    local_paths.assign(&file_path, 1);
+    std::vector<std::pair<WebURL, WebString>> url_to_local_path;
+    url_to_local_path.push_back(std::make_pair(WebURL(frame_url), file_path));
     // Start serializing DOM.
-    bool result = WebPageSerializer::serialize(web_frame->toWebLocalFrame(),
-       static_cast<WebPageSerializerClient*>(this),
-       links,
-       local_paths,
-       local_directory_name_.AsUTF16Unsafe());
+    bool result = WebPageSerializer::serialize(
+        web_frame->toWebLocalFrame(),
+        static_cast<WebPageSerializerClient*>(this), url_to_local_path);
     ASSERT_TRUE(result);
   }
 
@@ -615,9 +609,6 @@
   int32 render_view_routing_id_;
   std::string serialized_contents_;
   bool serialization_reported_end_of_data_;
-  // The local_directory_name_ is dummy relative path of directory which
-  // contain all saved auxiliary files included all sub frames and resources.
-  const base::FilePath local_directory_name_;
 };
 
 // If original contents have document type, the serialized contents also have
diff --git a/content/renderer/gpu/compositor_output_surface.cc b/content/renderer/gpu/compositor_output_surface.cc
index 1d8a065..eaea1d5 100644
--- a/content/renderer/gpu/compositor_output_surface.cc
+++ b/content/renderer/gpu/compositor_output_surface.cc
@@ -139,12 +139,12 @@
     return;
   } else {
     {
-      ScopedVector<IPC::Message> messages;
+      std::vector<scoped_ptr<IPC::Message>> messages;
       std::vector<IPC::Message> messages_to_deliver_with_frame;
       scoped_ptr<FrameSwapMessageQueue::SendMessageScope> send_message_scope =
           frame_swap_message_queue_->AcquireSendMessageScope();
       frame_swap_message_queue_->DrainMessages(&messages);
-      FrameSwapMessageQueue::TransferMessages(messages,
+      FrameSwapMessageQueue::TransferMessages(&messages,
                                               &messages_to_deliver_with_frame);
       Send(new ViewHostMsg_SwapCompositorFrame(routing_id_,
                                                output_surface_id_,
diff --git a/content/renderer/gpu/frame_swap_message_queue.cc b/content/renderer/gpu/frame_swap_message_queue.cc
index 84fcdd4..7e7a75b 100644
--- a/content/renderer/gpu/frame_swap_message_queue.cc
+++ b/content/renderer/gpu/frame_swap_message_queue.cc
@@ -4,6 +4,7 @@
 
 #include "content/renderer/gpu/frame_swap_message_queue.h"
 
+#include <algorithm>
 #include <limits>
 
 #include "base/containers/hash_tables.h"
@@ -23,8 +24,9 @@
   virtual void QueueMessage(int source_frame_number,
                             scoped_ptr<IPC::Message> msg,
                             bool* is_first) = 0;
-  virtual void DrainMessages(int source_frame_number,
-                             ScopedVector<IPC::Message>* messages) = 0;
+  virtual void DrainMessages(
+      int source_frame_number,
+      std::vector<scoped_ptr<IPC::Message>>* messages) = 0;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(FrameSwapMessageSubQueue);
@@ -65,11 +67,13 @@
   }
 
   void DrainMessages(int source_frame_number,
-                     ScopedVector<IPC::Message>* messages) override {
-    VisualStateQueueMap::iterator end = queue_.upper_bound(source_frame_number);
-    for (VisualStateQueueMap::iterator i = queue_.begin(); i != end; i++) {
+                     std::vector<scoped_ptr<IPC::Message>>* messages) override {
+    auto end = queue_.upper_bound(source_frame_number);
+    for (auto i = queue_.begin(); i != end; i++) {
       DCHECK(i->first <= source_frame_number);
-      messages->insert(messages->end(), i->second.begin(), i->second.end());
+      for (IPC::Message* msg : i->second) {
+        messages->push_back(make_scoped_ptr(msg));
+      }
       i->second.clear();
     }
     queue_.erase(queue_.begin(), end);
@@ -93,17 +97,17 @@
                     bool* is_first) override {
     if (is_first)
       *is_first = Empty();
-    queue_.push_back(msg.release());
+    queue_.push_back(msg.Pass());
   }
 
   void DrainMessages(int source_frame_number,
-                     ScopedVector<IPC::Message>* messages) override {
-    messages->insert(messages->end(), queue_.begin(), queue_.end());
-    queue_.weak_clear();
+                     std::vector<scoped_ptr<IPC::Message>>* messages) override {
+    std::move(queue_.begin(), queue_.end(), std::back_inserter(*messages));
+    queue_.clear();
   }
 
  private:
-  ScopedVector<IPC::Message> queue_;
+  std::vector<scoped_ptr<IPC::Message>> queue_;
 
   DISALLOW_COPY_AND_ASSIGN(SwapQueue);
 };
@@ -157,9 +161,10 @@
   swap_queue_->DrainMessages(0, &next_drain_messages_);
 }
 
-void FrameSwapMessageQueue::DidNotSwap(int source_frame_number,
-                                       cc::SwapPromise::DidNotSwapReason reason,
-                                       ScopedVector<IPC::Message>* messages) {
+void FrameSwapMessageQueue::DidNotSwap(
+    int source_frame_number,
+    cc::SwapPromise::DidNotSwapReason reason,
+    std::vector<scoped_ptr<IPC::Message>>* messages) {
   base::AutoLock lock(lock_);
   switch (reason) {
     case cc::SwapPromise::SWAP_FAILS:
@@ -178,12 +183,11 @@
 }
 
 void FrameSwapMessageQueue::DrainMessages(
-    ScopedVector<IPC::Message>* messages) {
+    std::vector<scoped_ptr<IPC::Message>>* messages) {
   lock_.AssertAcquired();
-  messages->insert(messages->end(),
-                   next_drain_messages_.begin(),
-                   next_drain_messages_.end());
-  next_drain_messages_.weak_clear();
+  std::move(next_drain_messages_.begin(), next_drain_messages_.end(),
+            std::back_inserter(*messages));
+  next_drain_messages_.clear();
 }
 
 scoped_ptr<FrameSwapMessageQueue::SendMessageScope>
@@ -192,15 +196,13 @@
 }
 
 // static
-void FrameSwapMessageQueue::TransferMessages(ScopedVector<IPC::Message>& source,
-                                             vector<IPC::Message>* dest) {
-  for (vector<IPC::Message*>::iterator i = source.begin(); i != source.end();
-       ++i) {
-    IPC::Message* m(*i);
-    dest->push_back(*m);
-    delete m;
+void FrameSwapMessageQueue::TransferMessages(
+    std::vector<scoped_ptr<IPC::Message>>* source,
+    vector<IPC::Message>* dest) {
+  for (const auto& msg : *source) {
+    dest->push_back(*msg.get());
   }
-  source.weak_clear();
+  source->clear();
 }
 
 }  // namespace content
diff --git a/content/renderer/gpu/frame_swap_message_queue.h b/content/renderer/gpu/frame_swap_message_queue.h
index b12b417..87ce2d8 100644
--- a/content/renderer/gpu/frame_swap_message_queue.h
+++ b/content/renderer/gpu/frame_swap_message_queue.h
@@ -73,7 +73,7 @@
   //            messages.
   void DidNotSwap(int source_frame_number,
                   cc::SwapPromise::DidNotSwapReason reason,
-                  ScopedVector<IPC::Message>* messages);
+                  std::vector<scoped_ptr<IPC::Message>>* messages);
 
   // A SendMessageScope object must be held by the caller when this method is
   // called.
@@ -81,7 +81,7 @@
   // |messages| vector to store messages, it's not cleared, only appended to.
   //            The method will append messages queued for frame numbers lower
   //            or equal to |source_frame_number|
-  void DrainMessages(ScopedVector<IPC::Message>* messages);
+  void DrainMessages(std::vector<scoped_ptr<IPC::Message>>* messages);
 
   // SendMessageScope is used to make sure that messages sent from different
   // threads (impl/main) are scheduled in the right order on the IO threads.
@@ -90,7 +90,7 @@
   // |messages| is sent.
   scoped_ptr<SendMessageScope> AcquireSendMessageScope();
 
-  static void TransferMessages(ScopedVector<IPC::Message>& source,
+  static void TransferMessages(std::vector<scoped_ptr<IPC::Message>>* source,
                                std::vector<IPC::Message>* dest);
 
  private:
@@ -103,7 +103,7 @@
   mutable base::Lock lock_;
   scoped_ptr<FrameSwapMessageSubQueue> visual_state_queue_;
   scoped_ptr<FrameSwapMessageSubQueue> swap_queue_;
-  ScopedVector<IPC::Message> next_drain_messages_;
+  std::vector<scoped_ptr<IPC::Message>> next_drain_messages_;
 
   DISALLOW_COPY_AND_ASSIGN(FrameSwapMessageQueue);
 };
diff --git a/content/renderer/gpu/frame_swap_message_queue_unittest.cc b/content/renderer/gpu/frame_swap_message_queue_unittest.cc
index 8040598..0f6afa8 100644
--- a/content/renderer/gpu/frame_swap_message_queue_unittest.cc
+++ b/content/renderer/gpu/frame_swap_message_queue_unittest.cc
@@ -45,7 +45,7 @@
   }
 
   void DrainMessages(int source_frame_number,
-                     ScopedVector<IPC::Message>* messages) {
+                     std::vector<scoped_ptr<IPC::Message>>* messages) {
     messages->clear();
     queue_->DidActivate(source_frame_number);
     queue_->DidSwap(source_frame_number);
@@ -54,12 +54,10 @@
     queue_->DrainMessages(messages);
   }
 
-  bool HasMessageForId(const ScopedVector<IPC::Message>& messages,
+  bool HasMessageForId(const std::vector<scoped_ptr<IPC::Message>>& messages,
                        int routing_id) {
-    for (ScopedVector<IPC::Message>::const_iterator i = messages.begin();
-         i != messages.end();
-         ++i) {
-      if ((*i)->routing_id() == routing_id)
+    for (const auto& msg : messages) {
+      if (msg->routing_id() == routing_id)
         return true;
     }
     return false;
@@ -78,14 +76,14 @@
 };
 
 TEST_F(FrameSwapMessageQueueTest, TestEmptyQueueDrain) {
-  ScopedVector<IPC::Message> messages;
+  std::vector<scoped_ptr<IPC::Message>> messages;
 
   DrainMessages(0, &messages);
   ASSERT_TRUE(messages.empty());
 }
 
 TEST_F(FrameSwapMessageQueueTest, TestEmpty) {
-  ScopedVector<IPC::Message> messages;
+  std::vector<scoped_ptr<IPC::Message>> messages;
   ASSERT_TRUE(queue_->Empty());
   QueueNextSwapMessage(CloneMessage(first_message_));
   ASSERT_FALSE(queue_->Empty());
@@ -99,7 +97,7 @@
 }
 
 TEST_F(FrameSwapMessageQueueTest, TestQueueMessageFirst) {
-  ScopedVector<IPC::Message> messages;
+  std::vector<scoped_ptr<IPC::Message>> messages;
   bool visual_state_first = false;
   bool next_swap_first = false;
 
@@ -128,7 +126,7 @@
 }
 
 TEST_F(FrameSwapMessageQueueTest, TestNextSwapMessageSentWithNextFrame) {
-  ScopedVector<IPC::Message> messages;
+  std::vector<scoped_ptr<IPC::Message>> messages;
 
   DrainMessages(1, &messages);
   QueueNextSwapMessage(CloneMessage(first_message_));
@@ -142,7 +140,7 @@
 }
 
 TEST_F(FrameSwapMessageQueueTest, TestNextSwapMessageSentWithCurrentFrame) {
-  ScopedVector<IPC::Message> messages;
+  std::vector<scoped_ptr<IPC::Message>> messages;
 
   DrainMessages(1, &messages);
   QueueNextSwapMessage(CloneMessage(first_message_));
@@ -157,7 +155,7 @@
 
 TEST_F(FrameSwapMessageQueueTest,
        TestDrainsVisualStateMessagesForCorrespondingFrames) {
-  ScopedVector<IPC::Message> messages;
+  std::vector<scoped_ptr<IPC::Message>> messages;
 
   QueueVisualStateMessage(1, CloneMessage(first_message_));
   QueueVisualStateMessage(2, CloneMessage(second_message_));
@@ -181,7 +179,7 @@
 
 TEST_F(FrameSwapMessageQueueTest,
        TestQueueNextSwapMessagePreservesFifoOrdering) {
-  ScopedVector<IPC::Message> messages;
+  std::vector<scoped_ptr<IPC::Message>> messages;
 
   QueueNextSwapMessage(CloneMessage(first_message_));
   QueueNextSwapMessage(CloneMessage(second_message_));
@@ -193,7 +191,7 @@
 
 TEST_F(FrameSwapMessageQueueTest,
        TestQueueVisualStateMessagePreservesFifoOrdering) {
-  ScopedVector<IPC::Message> messages;
+  std::vector<scoped_ptr<IPC::Message>> messages;
 
   QueueVisualStateMessage(1, CloneMessage(first_message_));
   QueueVisualStateMessage(1, CloneMessage(second_message_));
@@ -205,7 +203,7 @@
 
 void FrameSwapMessageQueueTest::TestDidNotSwap(
     cc::SwapPromise::DidNotSwapReason reason) {
-  ScopedVector<IPC::Message> messages;
+  std::vector<scoped_ptr<IPC::Message>> messages;
 
   QueueNextSwapMessage(CloneMessage(first_message_));
   QueueVisualStateMessage(2, CloneMessage(second_message_));
diff --git a/content/renderer/gpu/gpu_benchmarking_extension.cc b/content/renderer/gpu/gpu_benchmarking_extension.cc
index 706cdb0..3c4321d 100644
--- a/content/renderer/gpu/gpu_benchmarking_extension.cc
+++ b/content/renderer/gpu/gpu_benchmarking_extension.cc
@@ -54,12 +54,12 @@
  protected:
   bool onUseEncodedData(const void* data, size_t len) override { return true; }
 
-  SkData* onEncodePixels(const SkImageInfo& info,
-                         const void* pixels,
-                         size_t row_bytes) override {
+  SkData* onEncode(const SkPixmap& pixmap) override {
     SkBitmap bm;
     // The const_cast is fine, since we only read from the bitmap.
-    if (bm.installPixels(info, const_cast<void*>(pixels), row_bytes)) {
+    if (bm.installPixels(pixmap.info(),
+                         const_cast<void*>(pixmap.addr()),
+                         pixmap.rowBytes())) {
       std::vector<unsigned char> vector;
       if (gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &vector)) {
         return SkData::NewWithCopy(&vector.front(), vector.size());
diff --git a/content/renderer/gpu/queue_message_swap_promise.cc b/content/renderer/gpu/queue_message_swap_promise.cc
index ff524418..170243e8 100644
--- a/content/renderer/gpu/queue_message_swap_promise.cc
+++ b/content/renderer/gpu/queue_message_swap_promise.cc
@@ -53,14 +53,11 @@
 #if DCHECK_IS_ON()
   DCHECK(!completed_);
 #endif
-  ScopedVector<IPC::Message> messages;
+  std::vector<scoped_ptr<IPC::Message>> messages;
   message_queue_->DidNotSwap(source_frame_number_, reason, &messages);
-  for (ScopedVector<IPC::Message>::iterator i = messages.begin();
-       i != messages.end();
-       ++i) {
-    message_sender_->Send(*i);
+  for (auto& msg : messages) {
+    message_sender_->Send(msg.release());
   }
-  messages.weak_clear();
   PromiseCompleted();
 }
 
diff --git a/content/renderer/gpu/queue_message_swap_promise_unittest.cc b/content/renderer/gpu/queue_message_swap_promise_unittest.cc
index 76294fbd..7f3837f 100644
--- a/content/renderer/gpu/queue_message_swap_promise_unittest.cc
+++ b/content/renderer/gpu/queue_message_swap_promise_unittest.cc
@@ -34,16 +34,16 @@
   TestSyncMessageFilter() : IPC::SyncMessageFilter(NULL, false) {}
 
   bool Send(IPC::Message* message) override {
-    messages_.push_back(message);
+    messages_.push_back(make_scoped_ptr(message));
     return true;
   }
 
-  ScopedVector<IPC::Message>& messages() { return messages_; }
+  std::vector<scoped_ptr<IPC::Message>>& messages() { return messages_; }
 
  private:
   ~TestSyncMessageFilter() override {}
 
-  ScopedVector<IPC::Message> messages_;
+  std::vector<scoped_ptr<IPC::Message>> messages_;
 
   DISALLOW_COPY_AND_ASSIGN(TestSyncMessageFilter);
 };
@@ -71,11 +71,11 @@
                                               source_frame_number).Pass();
   }
 
-  ScopedVector<IPC::Message>& DirectSendMessages() {
+  const std::vector<scoped_ptr<IPC::Message>>& DirectSendMessages() {
     return sync_message_filter_->messages();
   }
 
-  ScopedVector<IPC::Message>& NextSwapMessages() {
+  std::vector<scoped_ptr<IPC::Message>>& NextSwapMessages() {
     next_swap_messages_.clear();
     scoped_ptr<FrameSwapMessageQueue::SendMessageScope> send_message_scope =
         frame_swap_message_queue_->AcquireSendMessageScope();
@@ -83,14 +83,12 @@
     return next_swap_messages_;
   }
 
-  bool ContainsMessage(const ScopedVector<IPC::Message>& messages,
+  bool ContainsMessage(const std::vector<scoped_ptr<IPC::Message>>& messages,
                        const IPC::Message& message) {
     if (messages.empty())
       return false;
-    for (ScopedVector<IPC::Message>::const_iterator i = messages.begin();
-         i != messages.end();
-         ++i) {
-      if ((*i)->type() == message.type())
+    for (const auto& msg : messages) {
+      if (msg->type() == message.type())
         return true;
     }
     return false;
@@ -133,7 +131,7 @@
   ScopedVector<cc::SwapPromise> promises_;
 
  private:
-  ScopedVector<IPC::Message> next_swap_messages_;
+  std::vector<scoped_ptr<IPC::Message>> next_swap_messages_;
 
   DISALLOW_COPY_AND_ASSIGN(QueueMessageSwapPromiseTest);
 };
@@ -253,7 +251,7 @@
   promises_[0]->DidActivate();
   promises_[0]->DidSwap(NULL);
   ASSERT_FALSE(promises_[1]);
-  ScopedVector<IPC::Message> messages;
+  std::vector<scoped_ptr<IPC::Message>> messages;
   messages.swap(NextSwapMessages());
   EXPECT_EQ(2u, messages.size());
   EXPECT_TRUE(ContainsMessage(messages, messages_[0]));
diff --git a/content/renderer/media/media_stream_dispatcher.cc b/content/renderer/media/media_stream_dispatcher.cc
index c5123f1..86f508f 100644
--- a/content/renderer/media/media_stream_dispatcher.cc
+++ b/content/renderer/media/media_stream_dispatcher.cc
@@ -71,14 +71,14 @@
 void MediaStreamDispatcher::GenerateStream(
     int request_id,
     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler,
-    const StreamOptions& components,
+    const StreamControls& controls,
     const GURL& security_origin) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DVLOG(1) << "MediaStreamDispatcher::GenerateStream(" << request_id << ")";
 
   requests_.push_back(Request(event_handler, request_id, next_ipc_id_));
   Send(new MediaStreamHostMsg_GenerateStream(
-      routing_id(), next_ipc_id_++, components, security_origin,
+      routing_id(), next_ipc_id_++, controls, security_origin,
       blink::WebUserGestureIndicator::isProcessingUserGesture()));
 }
 
diff --git a/content/renderer/media/media_stream_dispatcher.h b/content/renderer/media/media_stream_dispatcher.h
index ebc7784..d451ccc 100644
--- a/content/renderer/media/media_stream_dispatcher.h
+++ b/content/renderer/media/media_stream_dispatcher.h
@@ -39,7 +39,7 @@
   virtual void GenerateStream(
       int request_id,
       const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler,
-      const StreamOptions& components,
+      const StreamControls& controls,
       const GURL& security_origin);
 
   // Cancel the request for a new media stream to be created.
diff --git a/content/renderer/media/media_stream_dispatcher_unittest.cc b/content/renderer/media/media_stream_dispatcher_unittest.cc
index eb68780b..d4dbec6 100644
--- a/content/renderer/media/media_stream_dispatcher_unittest.cc
+++ b/content/renderer/media/media_stream_dispatcher_unittest.cc
@@ -120,20 +120,21 @@
   // Generates a request for a MediaStream and returns the request id that is
   // used in IPC. Use this returned id in CompleteGenerateStream to identify
   // the request.
-  int GenerateStream(const StreamOptions& options, int request_id) {
+  int GenerateStream(const StreamControls& controls, int request_id) {
     int next_ipc_id = dispatcher_->GetNextIpcIdForTest();
     dispatcher_->GenerateStream(request_id, handler_.get()->AsWeakPtr(),
-                                options, security_origin_);
+                                controls, security_origin_);
     return next_ipc_id;
   }
 
   // CompleteGenerateStream create a MediaStreamMsg_StreamGenerated instance
   // and call the MediaStreamDispathcer::OnMessageReceived. |ipc_id| must be the
   // the id returned by GenerateStream.
-  std::string CompleteGenerateStream(int ipc_id, const StreamOptions& options,
+  std::string CompleteGenerateStream(int ipc_id,
+                                     const StreamControls& controls,
                                      int request_id) {
-    StreamDeviceInfoArray audio_device_array(options.audio_requested ? 1 : 0);
-    if (options.audio_requested) {
+    StreamDeviceInfoArray audio_device_array(controls.audio.requested ? 1 : 0);
+    if (controls.audio.requested) {
       StreamDeviceInfo audio_device_info;
       audio_device_info.device.name = "Microphone";
       audio_device_info.device.type = kAudioType;
@@ -141,8 +142,8 @@
       audio_device_array[0] = audio_device_info;
     }
 
-    StreamDeviceInfoArray video_device_array(options.video_requested ? 1 : 0);
-    if (options.video_requested) {
+    StreamDeviceInfoArray video_device_array(controls.video.requested ? 1 : 0);
+    if (controls.video.requested) {
       StreamDeviceInfo video_device_info;
       video_device_info.device.name = "Camera";
       video_device_info.device.type = kVideoType;
@@ -160,10 +161,10 @@
     EXPECT_EQ(handler_->request_id_, request_id);
     EXPECT_EQ(handler_->label_, label);
 
-    if (options.audio_requested)
+    if (controls.audio.requested)
       EXPECT_EQ(dispatcher_->audio_session_id(label, 0), kAudioSessionId);
 
-    if (options.video_requested)
+    if (controls.video.requested)
       EXPECT_EQ(dispatcher_->video_session_id(label, 0), kVideoSessionId);
 
     return label;
@@ -180,19 +181,19 @@
 }  // namespace
 
 TEST_F(MediaStreamDispatcherTest, GenerateStreamAndStopDevices) {
-  StreamOptions options(true, true);
+  StreamControls controls(true, true);
 
-  int ipc_request_id1 = GenerateStream(options, kRequestId1);
-  int ipc_request_id2 = GenerateStream(options, kRequestId2);
+  int ipc_request_id1 = GenerateStream(controls, kRequestId1);
+  int ipc_request_id2 = GenerateStream(controls, kRequestId2);
   EXPECT_NE(ipc_request_id1, ipc_request_id2);
 
   // Complete the creation of stream1.
-  const std::string& label1 = CompleteGenerateStream(ipc_request_id1, options,
-                                                     kRequestId1);
+  const std::string& label1 =
+      CompleteGenerateStream(ipc_request_id1, controls, kRequestId1);
 
   // Complete the creation of stream2.
-  const std::string& label2 = CompleteGenerateStream(ipc_request_id2, options,
-                                                     kRequestId2);
+  const std::string& label2 =
+      CompleteGenerateStream(ipc_request_id2, controls, kRequestId2);
 
   // Stop the actual audio device and verify that there is no valid
   // |session_id|.
@@ -304,7 +305,7 @@
   scoped_ptr<MediaStreamDispatcher> dispatcher(new MediaStreamDispatcher(NULL));
   scoped_ptr<MockMediaStreamDispatcherEventHandler>
       handler(new MockMediaStreamDispatcherEventHandler);
-  StreamOptions components(true, true);
+  StreamControls components(true, true);
   GURL security_origin;
 
   // Test failure when creating a stream.
@@ -351,7 +352,7 @@
   scoped_ptr<MediaStreamDispatcher> dispatcher(new MediaStreamDispatcher(NULL));
   scoped_ptr<MockMediaStreamDispatcherEventHandler>
       handler(new MockMediaStreamDispatcherEventHandler);
-  StreamOptions components(true, true);
+  StreamControls components(true, true);
   int ipc_request_id1 = dispatcher->next_ipc_id_;
 
   dispatcher->GenerateStream(kRequestId1, handler.get()->AsWeakPtr(),
@@ -390,11 +391,11 @@
 // Test that the MediaStreamDispatcherEventHandler is notified when the message
 // MediaStreamMsg_DeviceStopped is received.
 TEST_F(MediaStreamDispatcherTest, DeviceClosed) {
-  StreamOptions options(true, true);
+  StreamControls controls(true, true);
 
-  int ipc_request_id = GenerateStream(options, kRequestId1);
-  const std::string& label = CompleteGenerateStream(ipc_request_id, options,
-                                                    kRequestId1);
+  int ipc_request_id = GenerateStream(controls, kRequestId1);
+  const std::string& label =
+      CompleteGenerateStream(ipc_request_id, controls, kRequestId1);
 
   dispatcher_->OnMessageReceived(
       MediaStreamMsg_DeviceStopped(kRouteId, label, handler_->video_device_));
diff --git a/content/renderer/media/mock_media_stream_dispatcher.cc b/content/renderer/media/mock_media_stream_dispatcher.cc
index 4c5becfd..887c117 100644
--- a/content/renderer/media/mock_media_stream_dispatcher.cc
+++ b/content/renderer/media/mock_media_stream_dispatcher.cc
@@ -30,7 +30,7 @@
 void MockMediaStreamDispatcher::GenerateStream(
     int request_id,
     const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler,
-    const StreamOptions& components,
+    const StreamControls& controls,
     const GURL& url) {
   // Audio and video share the same request so we use |audio_input_request_id_|
   // only.
@@ -40,10 +40,10 @@
   audio_input_array_.clear();
   video_array_.clear();
 
-  if (components.audio_requested) {
+  if (controls.audio.requested) {
     AddAudioInputDeviceToArray(false);
   }
-  if (components.video_requested) {
+  if (controls.video.requested) {
     AddVideoDeviceToArray(true);
   }
   ++request_stream_counter_;
diff --git a/content/renderer/media/mock_media_stream_dispatcher.h b/content/renderer/media/mock_media_stream_dispatcher.h
index d77327a..ffe9fb0d 100644
--- a/content/renderer/media/mock_media_stream_dispatcher.h
+++ b/content/renderer/media/mock_media_stream_dispatcher.h
@@ -21,7 +21,7 @@
   void GenerateStream(
       int request_id,
       const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler,
-      const StreamOptions& components,
+      const StreamControls& controls,
       const GURL& url) override;
   void CancelGenerateStream(
       int request_id,
diff --git a/content/renderer/media/rtc_certificate.cc b/content/renderer/media/rtc_certificate.cc
index 518e27c0..67ff071 100644
--- a/content/renderer/media/rtc_certificate.cc
+++ b/content/renderer/media/rtc_certificate.cc
@@ -28,7 +28,9 @@
 }
 
 double RTCCertificate::expires() const {
-  return static_cast<double>(certificate_->expires_timestamp_ns());
+  // TODO(hbos): A webrtc CL needs to land and roll and then we can use
+  // rtc::RTCCertificate::Expires here.
+  return 0.0;
 }
 
 const rtc::scoped_refptr<rtc::RTCCertificate>&
diff --git a/content/renderer/media/user_media_client_impl.cc b/content/renderer/media/user_media_client_impl.cc
index a324a5b..5d0afa5 100644
--- a/content/renderer/media/user_media_client_impl.cc
+++ b/content/renderer/media/user_media_client_impl.cc
@@ -37,24 +37,80 @@
 namespace content {
 namespace {
 
-void CopyStreamConstraints(const blink::WebMediaConstraints& constraints,
-                           StreamOptions::Constraints* mandatory,
-                           StreamOptions::Constraints* optional) {
-  blink::WebVector<blink::WebMediaConstraint> mandatory_constraints;
-  constraints.getMandatoryConstraints(mandatory_constraints);
-  for (size_t i = 0; i < mandatory_constraints.size(); i++) {
-    mandatory->push_back(StreamOptions::Constraint(
-        mandatory_constraints[i].m_name.utf8(),
-        mandatory_constraints[i].m_value.utf8()));
-  }
+bool GetMandatory(const blink::WebMediaConstraints& constraints,
+                  const std::string& name,
+                  std::string* value) {
+  if (constraints.isNull())
+    return false;
+  blink::WebString temp;
+  bool found =
+      constraints.getMandatoryConstraintValue(base::UTF8ToUTF16(name), temp);
+  if (found)
+    *value = temp.utf8();
+  return found;
+}
 
-  blink::WebVector<blink::WebMediaConstraint> optional_constraints;
-  constraints.getOptionalConstraints(optional_constraints);
-  for (size_t i = 0; i < optional_constraints.size(); i++) {
-    optional->push_back(StreamOptions::Constraint(
-        optional_constraints[i].m_name.utf8(),
-        optional_constraints[i].m_value.utf8()));
+void GetMandatoryList(const blink::WebMediaConstraints& constraints,
+                      const std::string& name,
+                      std::vector<std::string>* values) {
+  if (constraints.isNull()) {
+    return;
   }
+  blink::WebString temp;
+  bool found =
+      constraints.getMandatoryConstraintValue(base::UTF8ToUTF16(name), temp);
+  if (found) {
+    values->push_back(temp.utf8());
+  }
+}
+
+void GetOptionalList(const blink::WebMediaConstraints constraints,
+                     const std::string& name,
+                     std::vector<std::string>* values) {
+  if (constraints.isNull()) {
+    return;
+  }
+  blink::WebVector<blink::WebMediaConstraint> constraint_list;
+  constraints.getOptionalConstraints(constraint_list);
+  blink::WebString web_name = base::UTF8ToUTF16(name);
+  for (const auto& pair : constraint_list) {
+    if (pair.m_name == web_name) {
+      values->push_back(pair.m_value.utf8());
+    }
+  }
+}
+
+void CopyBlinkRequestToStreamControls(const blink::WebUserMediaRequest& request,
+                                      StreamControls* controls) {
+  if (request.isNull()) {
+    return;
+  }
+  GetMandatory(request.audioConstraints(), kMediaStreamSource,
+               &controls->audio.stream_source);
+  GetMandatory(request.videoConstraints(), kMediaStreamSource,
+               &controls->video.stream_source);
+  GetMandatoryList(request.audioConstraints(), kMediaStreamSourceInfoId,
+                   &controls->audio.device_ids);
+  GetMandatoryList(request.videoConstraints(), kMediaStreamSourceInfoId,
+                   &controls->video.device_ids);
+  GetOptionalList(request.audioConstraints(), kMediaStreamSourceInfoId,
+                  &controls->audio.alternate_device_ids);
+  GetOptionalList(request.videoConstraints(), kMediaStreamSourceInfoId,
+                  &controls->video.alternate_device_ids);
+  GetMandatoryList(request.audioConstraints(), kMediaStreamSourceId,
+                   &controls->audio.device_ids);
+  GetMandatoryList(request.videoConstraints(), kMediaStreamSourceId,
+                   &controls->video.device_ids);
+  std::string hotword_string;
+  GetMandatory(request.audioConstraints(), kMediaStreamAudioHotword,
+               &hotword_string);
+  if (hotword_string == "true")
+    controls->hotword_enabled = true;
+  // DCHECK for some combinations that seem to be unusual/useless
+  // It should not be possible to have both MediaStreamSourceId
+  // and MediaStreamSourceInfoId on the same request.
+  DCHECK(controls->video.device_ids.size() <= 1);
+  DCHECK(controls->audio.device_ids.size() <= 1);
 }
 
 static int g_next_request_id  = 0;
@@ -138,7 +194,7 @@
   }
 
   int request_id = g_next_request_id++;
-  StreamOptions options;
+  StreamControls controls;
   GURL security_origin;
   bool enable_automatic_output_device_selection = false;
 
@@ -146,30 +202,24 @@
   // if it isNull.
   if (user_media_request.isNull()) {
     // We are in a test.
-    options.audio_requested = true;
-    options.video_requested = true;
+    controls.audio.requested = true;
+    controls.video.requested = true;
   } else {
     if (user_media_request.audio()) {
-      options.audio_requested = true;
-      CopyStreamConstraints(user_media_request.audioConstraints(),
-                            &options.mandatory_audio,
-                            &options.optional_audio);
-
+      controls.audio.requested = true;
       // Check if this input device should be used to select a matching output
       // device for audio rendering.
       std::string enable;
-      if (options.GetFirstAudioConstraintByName(
-              kMediaStreamRenderToAssociatedSink, &enable, NULL) &&
+      if (GetMandatory(user_media_request.audioConstraints(),
+                       kMediaStreamRenderToAssociatedSink, &enable) &&
           base::LowerCaseEqualsASCII(enable, "true")) {
         enable_automatic_output_device_selection = true;
       }
     }
     if (user_media_request.video()) {
-      options.video_requested = true;
-      CopyStreamConstraints(user_media_request.videoConstraints(),
-                            &options.mandatory_video,
-                            &options.optional_video);
+      controls.video.requested = true;
     }
+    CopyBlinkRequestToStreamControls(user_media_request, &controls);
 
     security_origin = GURL(user_media_request.securityOrigin().toString());
     DCHECK(render_frame()->GetWebFrame() ==
@@ -178,40 +228,50 @@
   }
 
   DVLOG(1) << "UserMediaClientImpl::requestUserMedia(" << request_id << ", [ "
-           << "audio=" << (options.audio_requested)
+           << "audio=" << (controls.audio.requested)
            << " select associated sink: "
            << enable_automatic_output_device_selection
-           << ", video=" << (options.video_requested) << " ], "
+           << ", video=" << (controls.video.requested) << " ], "
            << security_origin.spec() << ")";
 
-  std::string audio_device_id;
-  bool mandatory_audio;
-  options.GetFirstAudioConstraintByName(kMediaStreamSourceInfoId,
-                                        &audio_device_id, &mandatory_audio);
-  std::string video_device_id;
-  bool mandatory_video;
-  options.GetFirstVideoConstraintByName(kMediaStreamSourceInfoId,
-                                        &video_device_id, &mandatory_video);
+  blink::WebString audio_device_id;
+  bool mandatory_audio = false;
+  if (!user_media_request.isNull() && user_media_request.audio()) {
+    mandatory_audio =
+        user_media_request.audioConstraints().getMandatoryConstraintValue(
+            base::UTF8ToUTF16(kMediaStreamSourceInfoId), audio_device_id);
+    if (!mandatory_audio) {
+      user_media_request.audioConstraints().getOptionalConstraintValue(
+          base::UTF8ToUTF16(kMediaStreamSourceInfoId), audio_device_id);
+    }
+  }
+
+  blink::WebString video_device_id;
+  bool mandatory_video = false;
+  if (!user_media_request.isNull() && user_media_request.video()) {
+    mandatory_video =
+        user_media_request.videoConstraints().getMandatoryConstraintValue(
+            base::UTF8ToUTF16(kMediaStreamSourceInfoId), video_device_id);
+    if (!mandatory_video) {
+      user_media_request.videoConstraints().getOptionalConstraintValue(
+          base::UTF8ToUTF16(kMediaStreamSourceInfoId), video_device_id);
+    }
+  }
 
   WebRtcLogMessage(base::StringPrintf(
       "MSI::requestUserMedia. request_id=%d"
       ", audio source id=%s mandatory= %s "
       ", video source id=%s mandatory= %s",
-      request_id,
-      audio_device_id.c_str(),
-      mandatory_audio ? "true":"false",
-      video_device_id.c_str(),
-      mandatory_video ? "true":"false"));
+      request_id, audio_device_id.utf8().c_str(),
+      mandatory_audio ? "true" : "false", video_device_id.utf8().c_str(),
+      mandatory_video ? "true" : "false"));
 
   user_media_requests_.push_back(
       new UserMediaRequestInfo(request_id, user_media_request,
                                enable_automatic_output_device_selection));
 
   media_stream_dispatcher_->GenerateStream(
-      request_id,
-      weak_factory_.GetWeakPtr(),
-      options,
-      security_origin);
+      request_id, weak_factory_.GetWeakPtr(), controls, security_origin);
 }
 
 void UserMediaClientImpl::cancelUserMediaRequest(
diff --git a/content/renderer/mojo_bindings_controller.cc b/content/renderer/mojo_bindings_controller.cc
index 4db0df04..08abcf5 100644
--- a/content/renderer/mojo_bindings_controller.cc
+++ b/content/renderer/mojo_bindings_controller.cc
@@ -26,34 +26,9 @@
 
 }  // namespace
 
-MojoBindingsController::MainFrameObserver::MainFrameObserver(
-    MojoBindingsController* mojo_bindings_controller)
-    : RenderFrameObserver(RenderFrame::FromWebFrame(
-          mojo_bindings_controller->render_view()->GetWebView()->mainFrame())),
-      mojo_bindings_controller_(mojo_bindings_controller) {
-}
-
-MojoBindingsController::MainFrameObserver::~MainFrameObserver() {
-}
-
-void MojoBindingsController::MainFrameObserver::WillReleaseScriptContext(
-    v8::Local<v8::Context> context,
-    int world_id) {
-  mojo_bindings_controller_->DestroyContextState(context);
-}
-
-void MojoBindingsController::MainFrameObserver::DidFinishDocumentLoad() {
-  mojo_bindings_controller_->OnDidFinishDocumentLoad();
-}
-
-void MojoBindingsController::MainFrameObserver::OnDestruct() {
-}
-
-MojoBindingsController::MojoBindingsController(RenderView* render_view)
-    : RenderViewObserver(render_view),
-      RenderViewObserverTracker<MojoBindingsController>(render_view),
-      main_frame_observer_(this) {
-}
+MojoBindingsController::MojoBindingsController(RenderFrame* render_frame)
+    : RenderFrameObserver(render_frame),
+      RenderFrameObserverTracker<MojoBindingsController>(render_frame) {}
 
 MojoBindingsController::~MojoBindingsController() {
 }
@@ -61,12 +36,11 @@
 void MojoBindingsController::CreateContextState() {
   v8::HandleScope handle_scope(blink::mainThreadIsolate());
   blink::WebLocalFrame* frame =
-      render_view()->GetWebView()->mainFrame()->toWebLocalFrame();
+      render_frame()->GetWebFrame()->toWebLocalFrame();
   v8::Local<v8::Context> context = frame->mainWorldScriptContext();
   gin::PerContextData* context_data = gin::PerContextData::From(context);
   MojoContextStateData* data = new MojoContextStateData;
-  data->state.reset(
-      new MojoContextState(render_view()->GetWebView()->mainFrame(), context));
+  data->state.reset(new MojoContextState(frame, context));
   context_data->SetUserData(kMojoContextStateKey, data);
 }
 
@@ -78,18 +52,10 @@
   context_data->RemoveUserData(kMojoContextStateKey);
 }
 
-void MojoBindingsController::OnDidFinishDocumentLoad() {
-  v8::HandleScope handle_scope(blink::mainThreadIsolate());
-  MojoContextState* state = GetContextState();
-  if (state)
-    state->Run();
-}
-
 MojoContextState* MojoBindingsController::GetContextState() {
-  blink::WebLocalFrame* frame =
-      render_view()->GetWebView()->mainFrame()->toWebLocalFrame();
   v8::HandleScope handle_scope(blink::mainThreadIsolate());
-  v8::Local<v8::Context> context = frame->mainWorldScriptContext();
+  v8::Local<v8::Context> context =
+      render_frame()->GetWebFrame()->mainWorldScriptContext();
   gin::PerContextData* context_data = gin::PerContextData::From(context);
   if (!context_data)
     return NULL;
@@ -98,15 +64,24 @@
   return context_state ? context_state->state.get() : NULL;
 }
 
-void MojoBindingsController::DidCreateDocumentElement(
-    blink::WebLocalFrame* frame) {
+void MojoBindingsController::WillReleaseScriptContext(
+    v8::Local<v8::Context> context,
+    int world_id) {
+  DestroyContextState(context);
+}
+
+void MojoBindingsController::DidFinishDocumentLoad() {
+  v8::HandleScope handle_scope(blink::mainThreadIsolate());
+  MojoContextState* state = GetContextState();
+  if (state)
+    state->Run();
+}
+
+void MojoBindingsController::DidCreateDocumentElement() {
   CreateContextState();
 }
 
-void MojoBindingsController::DidClearWindowObject(blink::WebLocalFrame* frame) {
-  if (frame != render_view()->GetWebView()->mainFrame())
-    return;
-
+void MojoBindingsController::DidClearWindowObject() {
   // NOTE: this function may be called early on twice. From the constructor
   // mainWorldScriptContext() may trigger this to be called. If we are created
   // before the page is loaded (which is very likely), then on first load this
@@ -119,7 +94,7 @@
     return;
 
   v8::HandleScope handle_scope(blink::mainThreadIsolate());
-  DestroyContextState(frame->mainWorldScriptContext());
+  DestroyContextState(render_frame()->GetWebFrame()->mainWorldScriptContext());
 }
 
 }  // namespace content
diff --git a/content/renderer/mojo_bindings_controller.h b/content/renderer/mojo_bindings_controller.h
index 46ee9c14..3ebb744c 100644
--- a/content/renderer/mojo_bindings_controller.h
+++ b/content/renderer/mojo_bindings_controller.h
@@ -9,8 +9,7 @@
 
 #include "base/macros.h"
 #include "content/public/renderer/render_frame_observer.h"
-#include "content/public/renderer/render_view_observer.h"
-#include "content/public/renderer/render_view_observer_tracker.h"
+#include "content/public/renderer/render_frame_observer_tracker.h"
 #include "mojo/public/cpp/system/core.h"
 
 namespace gin {
@@ -24,51 +23,26 @@
 // MojoBindingsController is responsible for enabling the renderer side of mojo
 // bindings. It creates (and destroys) a MojoContextState at the appropriate
 // times and handles the necessary browser messages. MojoBindingsController
-// destroys itself when the RendererView it is created with is destroyed.
+// destroys itself when the RendererFrame it is created with is destroyed.
 class MojoBindingsController
-    : public RenderViewObserver,
-      public RenderViewObserverTracker<MojoBindingsController> {
+    : public RenderFrameObserver,
+      public RenderFrameObserverTracker<MojoBindingsController> {
  public:
-  explicit MojoBindingsController(RenderView* render_view);
+  explicit MojoBindingsController(RenderFrame* render_frame);
 
  private:
-  class MainFrameObserver : public RenderFrameObserver {
-   public:
-    explicit MainFrameObserver(MojoBindingsController* web_ui_mojo);
-    ~MainFrameObserver() override;
-
-    // RenderFrameObserver overrides:
-    void WillReleaseScriptContext(v8::Local<v8::Context> context,
-                                  int world_id) override;
-    void DidFinishDocumentLoad() override;
-    // MainFrameObserver is inline owned by MojoBindingsController and should
-    // not be destroyed when the main RenderFrame is deleted. Overriding the
-    // OnDestruct method allows this object to remain alive and be cleaned
-    // up as part of MojoBindingsController deletion.
-    void OnDestruct() override;
-
-   private:
-    MojoBindingsController* mojo_bindings_controller_;
-
-    DISALLOW_COPY_AND_ASSIGN(MainFrameObserver);
-  };
-
   ~MojoBindingsController() override;
 
   void CreateContextState();
   void DestroyContextState(v8::Local<v8::Context> context);
-
-  // Invoked when the frame finishes loading. Invokes Run() on the
-  // MojoContextState.
-  void OnDidFinishDocumentLoad();
-
   MojoContextState* GetContextState();
 
-  // RenderViewObserver overrides:
-  void DidCreateDocumentElement(blink::WebLocalFrame* frame) override;
-  void DidClearWindowObject(blink::WebLocalFrame* frame) override;
-
-  MainFrameObserver main_frame_observer_;
+  // RenderFrameObserver overrides:
+  void WillReleaseScriptContext(v8::Local<v8::Context> context,
+                                int world_id) override;
+  void DidFinishDocumentLoad() override;
+  void DidCreateDocumentElement() override;
+  void DidClearWindowObject() override;
 
   DISALLOW_COPY_AND_ASSIGN(MojoBindingsController);
 };
diff --git a/content/renderer/p2p/ipc_network_manager_unittest.cc b/content/renderer/p2p/ipc_network_manager_unittest.cc
index d38db7b..7baaaf25 100644
--- a/content/renderer/p2p/ipc_network_manager_unittest.cc
+++ b/content/renderer/p2p/ipc_network_manager_unittest.cc
@@ -30,9 +30,10 @@
 
 // 2 IPv6 addresses with only last digit different.
 static const char kIPv6PublicAddrString1[] =
-    "2401:fa00:4:1000:be30:5bff:fee5:c3";
+    "2401:fa00:4:1000:be30:5b30:50e5:c3";
 static const char kIPv6PublicAddrString2[] =
-    "2401:fa00:4:1000:be30:5bff:fee5:c4";
+    "2401:fa00:4:1000:be30:5b30:50e5:c4";
+static const char kIPv4MappedAddrString[] = "::ffff:38.32.0.0";
 
 class IpcNetworkManagerTest : public testing::Test {
  public:
@@ -51,7 +52,7 @@
 // IpcNetworkManager in addition to MergeNetworkList.
 // TODO(guoweis): disable this test case for now until fix for webrtc
 // issue 19249005 integrated into chromium
-TEST_F(IpcNetworkManagerTest, DISABLED_TestMergeNetworkList) {
+TEST_F(IpcNetworkManagerTest, TestMergeNetworkList) {
   net::NetworkInterfaceList list;
   net::IPAddressNumber ip_number;
   std::vector<rtc::Network*> networks;
@@ -96,8 +97,13 @@
                             48,
                             net::IP_ADDRESS_ATTRIBUTE_NONE));
 
+  // Push an unknown address as the default address.
+  EXPECT_TRUE(net::ParseIPLiteralToNumber(kIPv4MappedAddrString, &ip_number));
   network_manager_->OnNetworkListChanged(list, net::IPAddressNumber(),
-                                         net::IPAddressNumber());
+                                         ip_number);
+
+  // The unknown default address should be ignored.
+  EXPECT_FALSE(network_manager_->GetDefaultLocalAddress(AF_INET6, &ip_address));
 
   network_manager_->GetNetworks(&networks);
 
diff --git a/content/renderer/pepper/plugin_object.cc b/content/renderer/pepper/plugin_object.cc
index 2c82c3f..1943b10 100644
--- a/content/renderer/pepper/plugin_object.cc
+++ b/content/renderer/pepper/plugin_object.cc
@@ -74,6 +74,8 @@
   V8VarConverter var_converter(instance->pp_instance(),
                                V8VarConverter::kAllowObjectVars);
   PepperTryCatchVar try_catch(instance, &var_converter, NULL);
+  // TODO(raymes): Remove this line once crbug.com/560120 is diagnosed.
+  CHECK(!instance->GetMainWorldContext().IsEmpty());
   gin::Handle<PluginObject> object =
       gin::CreateHandle(instance->GetIsolate(),
                         new PluginObject(instance, ppp_class, ppp_class_data));
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 314fe7b..9e432ba9 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -48,6 +48,7 @@
 #include "content/common/savable_subframe.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/common/site_isolation_policy.h"
+#include "content/common/ssl_status_serialization.h"
 #include "content/common/swapped_out_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/common/bindings_policy.h"
@@ -98,6 +99,7 @@
 #include "content/renderer/media/webmediaplayer_ms.h"
 #include "content/renderer/memory_benchmarking_extension.h"
 #include "content/renderer/mojo/service_registry_js_wrapper.h"
+#include "content/renderer/mojo_bindings_controller.h"
 #include "content/renderer/navigation_state_impl.h"
 #include "content/renderer/notification_permission_dispatcher.h"
 #include "content/renderer/npapi/plugin_channel_host.h"
@@ -116,6 +118,7 @@
 #include "content/renderer/shared_worker_repository.h"
 #include "content/renderer/skia_benchmarking_extension.h"
 #include "content/renderer/stats_collection_controller.h"
+#include "content/renderer/usb/web_usb_client_impl.h"
 #include "content/renderer/wake_lock/wake_lock_dispatcher.h"
 #include "content/renderer/web_frame_utils.h"
 #include "content/renderer/web_ui_extension.h"
@@ -190,7 +193,6 @@
 #include "content/renderer/media/android/webmediasession_android.h"
 #else
 #include "cc/blink/context_provider_web_context.h"
-#include "content/renderer/usb/web_usb_client_impl.h"
 #include "device/devices_app/public/cpp/constants.h"
 #endif
 
@@ -567,6 +569,45 @@
 
 void OnGotContentHandlerID(uint32_t content_handler_id) {}
 
+WebString ConvertRelativePathToHtmlAttribute(const base::FilePath& path) {
+  DCHECK(!path.IsAbsolute());
+  return WebString::fromUTF8(
+      std::string("./") +
+      path.NormalizePathSeparatorsTo(FILE_PATH_LITERAL('/')).AsUTF8Unsafe());
+}
+
+bool IsContentWithCertificateErrorsRelevantToUI(
+    const blink::WebURL& url,
+    const blink::WebCString& security_info,
+    const blink::WebURL& main_resource_url,
+    const blink::WebCString& main_resource_security_info) {
+  content::SSLStatus ssl_status;
+  content::SSLStatus main_resource_ssl_status;
+  CHECK(DeserializeSecurityInfo(security_info, &ssl_status));
+  CHECK(DeserializeSecurityInfo(main_resource_security_info,
+                                &main_resource_ssl_status));
+
+  if (!GURL(main_resource_url).SchemeIsCryptographic())
+    return false;
+
+  // Do not handle subresource certificate errors if they are the same
+  // as errors that occured during the main page load. This compares
+  // most, but not all, fields of SSLStatus. For example, this check
+  // does not compare |content_status| because the navigation entry
+  // might have mixed content but also have the exact same SSL
+  // connection properties as the subresource, thereby making the
+  // subresource errors duplicative.
+  return (!url::Origin(GURL(url))
+               .IsSameOriginWith(url::Origin(GURL(main_resource_url))) ||
+          main_resource_ssl_status.security_style !=
+              ssl_status.security_style ||
+          main_resource_ssl_status.cert_id != ssl_status.cert_id ||
+          main_resource_ssl_status.cert_status != ssl_status.cert_status ||
+          main_resource_ssl_status.security_bits != ssl_status.security_bits ||
+          main_resource_ssl_status.connection_status !=
+              ssl_status.connection_status);
+}
+
 }  // namespace
 
 // static
@@ -891,6 +932,11 @@
                  "parent", parent_id);
   }
 
+  if (IsMainFrame() &&
+      RenderProcess::current()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI) {
+    EnableMojoBindings();
+  }
+
 #if defined(ENABLE_PLUGINS)
   new PepperBrowserConnection(this);
 #endif
@@ -910,14 +956,8 @@
 }
 
 RenderWidget* RenderFrameImpl::GetRenderWidget() {
-  RenderFrameImpl* local_root = this;
-
-  // By definition, a local frame without a widget must have a local frame
-  // ancestor with a widget. Keep iterating until we find the local root's
-  // widget.
-  while (!local_root->render_widget_)
-    local_root = RenderFrameImpl::FromWebFrame(local_root->frame_->parent());
-
+  RenderFrameImpl* local_root =
+      RenderFrameImpl::FromWebFrame(frame_->localRoot());
   return local_root->render_widget_.get();
 }
 
@@ -3673,12 +3713,38 @@
     const blink::WebSecurityOrigin& origin,
     const blink::WebURL& target) {
   Send(new FrameHostMsg_DidRunInsecureContent(
-      routing_id_, origin.toString().utf8(), target));
+      routing_id_, GURL(origin.toString().utf8()), target));
   GetContentClient()->renderer()->RecordRapporURL(
       "ContentSettings.MixedScript.RanMixedScript",
       GURL(origin.toString().utf8()));
 }
 
+void RenderFrameImpl::didDisplayContentWithCertificateErrors(
+    const blink::WebURL& url,
+    const blink::WebCString& security_info,
+    const blink::WebURL& main_resource_url,
+    const blink::WebCString& main_resource_security_info) {
+  if (!IsContentWithCertificateErrorsRelevantToUI(
+          url, security_info, main_resource_url, main_resource_security_info)) {
+    return;
+  }
+  Send(new FrameHostMsg_DidDisplayContentWithCertificateErrors(routing_id_, url,
+                                                               security_info));
+}
+
+void RenderFrameImpl::didRunContentWithCertificateErrors(
+    const blink::WebURL& url,
+    const blink::WebCString& security_info,
+    const blink::WebURL& main_resource_url,
+    const blink::WebCString& main_resource_security_info) {
+  if (!IsContentWithCertificateErrorsRelevantToUI(
+          url, security_info, main_resource_url, main_resource_security_info)) {
+    return;
+  }
+  Send(new FrameHostMsg_DidRunContentWithCertificateErrors(
+      routing_id_, GURL(main_resource_url).GetOrigin(), url, security_info));
+}
+
 void RenderFrameImpl::didChangePerformanceTiming() {
   FOR_EACH_OBSERVER(RenderFrameObserver,
                     observers_,
@@ -4030,11 +4096,9 @@
 }
 
 blink::WebUSBClient* RenderFrameImpl::usbClient() {
-#if !defined(OS_ANDROID)
-  if (!usb_client_) {
+  if (!usb_client_)
     usb_client_.reset(new WebUSBClientImpl(GetServiceRegistry()));
-  }
-#endif
+
   return usb_client_.get();
 }
 
@@ -4633,25 +4697,20 @@
 }
 
 void RenderFrameImpl::OnGetSerializedHtmlWithLocalLinks(
-    std::vector<GURL> original_urls,
-    std::vector<base::FilePath> equivalent_local_paths,
-    base::FilePath local_directory_path) {
-  // Only DCHECK, since the message comes from the trusted browser process.
-  DCHECK(original_urls.size() == equivalent_local_paths.size());
-
-  // Convert std::vector of GURLs to WebVector<WebURL>
-  WebVector<WebURL> weburl_links(original_urls);
-
-  // Convert std::vector of base::FilePath to WebVector<WebString>
-  WebVector<WebString> webstring_paths(equivalent_local_paths.size());
-  for (size_t i = 0; i < equivalent_local_paths.size(); i++)
-    webstring_paths[i] = equivalent_local_paths[i].AsUTF16Unsafe();
+    const std::map<GURL, base::FilePath>& url_to_local_path) {
+  // Convert input to the canonical way of passing a map into a Blink API.
+  std::vector<std::pair<WebURL, WebString>> weburl_to_local_path;
+  for (const auto& it : url_to_local_path) {
+    const GURL& url = it.first;
+    const base::FilePath& local_path = it.second;
+    weburl_to_local_path.push_back(std::make_pair(
+        WebURL(url), ConvertRelativePathToHtmlAttribute(local_path)));
+  }
 
   // Serialize the frame (without recursing into subframes).
   WebPageSerializer::serialize(GetWebFrame(),
-                               this,   // WebPageSerializerClient.
-                               weburl_links, webstring_paths,
-                               local_directory_path.AsUTF16Unsafe());
+                               this,  // WebPageSerializerClient.
+                               weburl_to_local_path);
 }
 
 void RenderFrameImpl::OpenURL(const GURL& url,
@@ -4734,6 +4793,11 @@
     cache_policy = WebURLRequest::ReloadIgnoringCacheData;
   }
 
+  // If the navigation is for "view source", the WebLocalFrame needs to be put
+  // in a special mode.
+  if (request_params.is_view_source)
+    frame_->enableViewSourceMode(true);
+
   pending_navigation_params_.reset(
       new NavigationParams(common_params, start_params, request_params));
 
@@ -5159,6 +5223,14 @@
       routing_id_, SingleHistoryItemToPageState(current_history_item_)));
 }
 
+void RenderFrameImpl::EnableMojoBindings() {
+  // If an MojoBindingsController already exists for this RenderFrameImpl, avoid
+  // creating another one. It is not kept as a member, as it deletes itself when
+  // the frame is destroyed.
+  if (!RenderFrameObserverTracker<MojoBindingsController>::Get(this))
+    new MojoBindingsController(this);
+}
+
 void RenderFrameImpl::SendFailedProvisionalLoad(
     const blink::WebURLRequest& request,
     const blink::WebURLError& error,
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index baed47f..9da61e04 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -522,6 +522,16 @@
   void didDisplayInsecureContent() override;
   void didRunInsecureContent(const blink::WebSecurityOrigin& origin,
                              const blink::WebURL& target) override;
+  void didDisplayContentWithCertificateErrors(
+      const blink::WebURL& url,
+      const blink::WebCString& security_info,
+      const blink::WebURL& main_resource_url,
+      const blink::WebCString& main_resource_security_info) override;
+  void didRunContentWithCertificateErrors(
+      const blink::WebURL& url,
+      const blink::WebCString& security_info,
+      const blink::WebURL& main_resource_url,
+      const blink::WebCString& main_resource_security_info) override;
   void didChangePerformanceTiming() override;
   void didCreateScriptContext(blink::WebLocalFrame* frame,
                               v8::Local<v8::Context> context,
@@ -621,6 +631,10 @@
   // Sends the current frame's navigation state to the browser.
   void SendUpdateState();
 
+  // Creates a MojoBindingsController to allow WebUI documents to communicate
+  // with the browser process.
+  void EnableMojoBindings();
+
  protected:
   explicit RenderFrameImpl(const CreateParams& params);
 
@@ -759,9 +773,7 @@
                           int error_code);
   void OnGetSavableResourceLinks();
   void OnGetSerializedHtmlWithLocalLinks(
-      std::vector<GURL> original_urls,
-      std::vector<base::FilePath> equivalent_local_paths,
-      base::FilePath local_directory_path);
+      const std::map<GURL, base::FilePath>& url_to_local_path);
 
   // Requests that the browser process navigates to |url|. If
   // |is_history_navigation_in_new_child| is true, the browser process should
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index a5aa817..d74f0773 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -86,7 +86,6 @@
 #include "content/renderer/media/audio_device_factory.h"
 #include "content/renderer/media/video_capture_impl_manager.h"
 #include "content/renderer/mhtml_generator.h"
-#include "content/renderer/mojo_bindings_controller.h"
 #include "content/renderer/navigation_state_impl.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_frame_proxy.h"
@@ -2541,8 +2540,9 @@
       !(enabled_bindings_ & BINDINGS_POLICY_WEB_UI)) {
     // WebUIExtensionData deletes itself when we're destroyed.
     new WebUIExtensionData(this);
-    // MojoBindingsController deletes itself when we're destroyed.
-    new MojoBindingsController(this);
+
+    if (main_render_frame_)
+      main_render_frame_->EnableMojoBindings();
   }
 
   enabled_bindings_ |= enabled_bindings_flags;
diff --git a/content/renderer/shared_worker_repository.cc b/content/renderer/shared_worker_repository.cc
index 357cc951..3c1e73cb 100644
--- a/content/renderer/shared_worker_repository.cc
+++ b/content/renderer/shared_worker_repository.cc
@@ -27,6 +27,7 @@
     DocumentID document_id,
     const blink::WebString& content_security_policy,
     blink::WebContentSecurityPolicyType security_policy_type,
+    blink::WebSharedWorkerCreationContextType creation_context_type,
     blink::WebWorkerCreationError* error) {
   ViewHostMsg_CreateWorker_Params params;
   params.url = url;
@@ -35,6 +36,7 @@
   params.security_policy_type = security_policy_type;
   params.document_id = document_id;
   params.render_frame_route_id = render_frame()->GetRoutingID();
+  params.creation_context_type = creation_context_type;
   ViewHostMsg_CreateWorker_Reply reply;
   Send(new ViewHostMsg_CreateWorker(params, &reply));
   if (reply.route_id == MSG_ROUTING_NONE) {
diff --git a/content/renderer/shared_worker_repository.h b/content/renderer/shared_worker_repository.h
index 004398d3..c245fec 100644
--- a/content/renderer/shared_worker_repository.h
+++ b/content/renderer/shared_worker_repository.h
@@ -10,6 +10,7 @@
 #include "base/basictypes.h"
 #include "content/public/renderer/render_frame_observer.h"
 #include "third_party/WebKit/public/web/WebContentSecurityPolicy.h"
+#include "third_party/WebKit/public/web/WebSharedWorkerCreationContextType.h"
 #include "third_party/WebKit/public/web/WebSharedWorkerRepositoryClient.h"
 
 namespace content {
@@ -29,6 +30,7 @@
       DocumentID document_id,
       const blink::WebString& content_security_policy,
       blink::WebContentSecurityPolicyType,
+      blink::WebSharedWorkerCreationContextType,
       blink::WebWorkerCreationError* error) override;
   void documentDetached(DocumentID document_id) override;
 
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc
index 8b0ca65..19a60b6 100644
--- a/content/shell/browser/shell_content_browser_client.cc
+++ b/content/shell/browser/shell_content_browser_client.cc
@@ -9,6 +9,7 @@
 #include "base/files/file.h"
 #include "base/files/file_util.h"
 #include "base/path_service.h"
+#include "base/strings/pattern.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/public/browser/client_certificate_delegate.h"
 #include "content/public/browser/page_navigator.h"
@@ -35,6 +36,7 @@
 #include "content/shell/common/shell_switches.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "url/gurl.h"
+#include "url/origin.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/apk_assets.h"
@@ -146,6 +148,19 @@
   return shell_browser_main_parts_;
 }
 
+bool ShellContentBrowserClient::DoesSiteRequireDedicatedProcess(
+    BrowserContext* browser_context,
+    const GURL& effective_url) {
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  DCHECK(command_line->HasSwitch(switches::kIsolateSitesForTesting));
+  std::string pattern =
+      command_line->GetSwitchValueASCII(switches::kIsolateSitesForTesting);
+  // Practically |origin| is the same as |effective_url.spec()|, except Origin
+  // serialization strips the trailing "/", which makes for cleaner patterns.
+  std::string origin = url::Origin(effective_url).Serialize();
+  return base::MatchPattern(origin, pattern);
+}
+
 net::URLRequestContextGetter* ShellContentBrowserClient::CreateRequestContext(
     BrowserContext* content_browser_context,
     ProtocolHandlerMap* protocol_handlers,
@@ -252,6 +267,13 @@
             switches::kEnableLeakDetection));
   }
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kIsolateSitesForTesting)) {
+    command_line->AppendSwitchASCII(
+        switches::kIsolateSitesForTesting,
+        base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+            switches::kIsolateSitesForTesting));
+  }
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kRegisterFontFiles)) {
     command_line->AppendSwitchASCII(
         switches::kRegisterFontFiles,
diff --git a/content/shell/browser/shell_content_browser_client.h b/content/shell/browser/shell_content_browser_client.h
index d10ca3a..2a28c3c9 100644
--- a/content/shell/browser/shell_content_browser_client.h
+++ b/content/shell/browser/shell_content_browser_client.h
@@ -32,6 +32,8 @@
   // ContentBrowserClient overrides.
   BrowserMainParts* CreateBrowserMainParts(
       const MainFunctionParams& parameters) override;
+  bool DoesSiteRequireDedicatedProcess(BrowserContext* browser_context,
+                                       const GURL& effective_url) override;
   net::URLRequestContextGetter* CreateRequestContext(
       BrowserContext* browser_context,
       ProtocolHandlerMap* protocol_handlers,
diff --git a/content/shell/browser/shell_web_contents_view_delegate_win.cc b/content/shell/browser/shell_web_contents_view_delegate_win.cc
index d5a16baa..d71bf0d 100644
--- a/content/shell/browser/shell_web_contents_view_delegate_win.cc
+++ b/content/shell/browser/shell_web_contents_view_delegate_win.cc
@@ -82,7 +82,8 @@
 
   HMENU menu = CreateMenu();
   HMENU sub_menu = CreatePopupMenu();
-  AppendMenu(menu, MF_STRING | MF_POPUP, (UINT)sub_menu, L"");
+  AppendMenu(menu, MF_STRING | MF_POPUP, reinterpret_cast<UINT_PTR>(sub_menu),
+             L"");
 
   int index = 0;
   if (params_.media_type == WebContextMenuData::MediaTypeNone &&
diff --git a/content/shell/common/shell_content_client.cc b/content/shell/common/shell_content_client.cc
index 2e420895..b9b9712 100644
--- a/content/shell/common/shell_content_client.cc
+++ b/content/shell/common/shell_content_client.cc
@@ -91,4 +91,9 @@
   return ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id);
 }
 
+bool ShellContentClient::IsSupplementarySiteIsolationModeEnabled() {
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kIsolateSitesForTesting);
+}
+
 }  // namespace content
diff --git a/content/shell/common/shell_content_client.h b/content/shell/common/shell_content_client.h
index 9ea4fb5b..ceebc52 100644
--- a/content/shell/common/shell_content_client.h
+++ b/content/shell/common/shell_content_client.h
@@ -27,6 +27,7 @@
   base::RefCountedStaticMemory* GetDataResourceBytes(
       int resource_id) const override;
   gfx::Image& GetNativeImageNamed(int resource_id) const override;
+  bool IsSupplementarySiteIsolationModeEnabled() override;
 };
 
 }  // namespace content
diff --git a/content/shell/common/shell_switches.cc b/content/shell/common/shell_switches.cc
index ab5ad9ab..25c1070 100644
--- a/content/shell/common/shell_switches.cc
+++ b/content/shell/common/shell_switches.cc
@@ -52,6 +52,14 @@
 // and debugging of layout tests that rely on it.
 const char kExposeInternalsForTesting[] = "expose-internals-for-testing";
 
+// Enable site isolation (--site-per-process style isolation) for a subset of
+// sites. The argument is a wildcard pattern which will be matched against the
+// site URL to determine which sites to isolate. This can be used to isolate
+// just one top-level domain, or just one scheme. Example usages:
+//     --isolate-sites-for-testing=*.com
+//     --isolate-sites-for-testing=https://*
+const char kIsolateSitesForTesting[] = "isolate-sites-for-testing";
+
 // Registers additional font files on Windows (for fonts outside the usual
 // %WINDIR%\Fonts location). Multiple files can be used by separating them
 // with a semicolon (;).
diff --git a/content/shell/common/shell_switches.h b/content/shell/common/shell_switches.h
index bc24fab..db78614 100644
--- a/content/shell/common/shell_switches.h
+++ b/content/shell/common/shell_switches.h
@@ -25,6 +25,7 @@
 extern const char kEnableLeakDetection[];
 extern const char kEncodeBinary[];
 extern const char kExposeInternalsForTesting[];
+extern const char kIsolateSitesForTesting[];
 extern const char kRegisterFontFiles[];
 extern const char kRunLayoutTest[];
 extern const char kStableReleaseMode[];
diff --git a/content/test/data/accessibility/aria/aria-progressbar-expected-win.txt b/content/test/data/accessibility/aria/aria-progressbar-expected-win.txt
index 9bc65344..3285084 100644
--- a/content/test/data/accessibility/aria/aria-progressbar-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-progressbar-expected-win.txt
@@ -1,3 +1,3 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++ROLE_SYSTEM_PROGRESSBAR READONLY xml-roles:progressbar valuetext:3 currentValue=3.00 minimumValue=1.00 maximumValue=37.00
-++ROLE_SYSTEM_PROGRESSBAR READONLY xml-roles:progressbar valuetext:three currentValue=0.00 minimumValue=1.00 maximumValue=96.00
+++ROLE_SYSTEM_PROGRESSBAR value='3' READONLY xml-roles:progressbar valuetext:3 currentValue=3.00 minimumValue=1.00 maximumValue=37.00
+++ROLE_SYSTEM_PROGRESSBAR value='three' READONLY xml-roles:progressbar valuetext:three currentValue=0.00 minimumValue=1.00 maximumValue=96.00
diff --git a/content/test/data/accessibility/aria/aria-progressbar.html b/content/test/data/accessibility/aria/aria-progressbar.html
index d2295d63..96ff4ab 100644
--- a/content/test/data/accessibility/aria/aria-progressbar.html
+++ b/content/test/data/accessibility/aria/aria-progressbar.html
@@ -8,6 +8,8 @@
 @WIN-ALLOW:minimumValue=*
 @WIN-ALLOW:maximumValue=*
 @WIN-DENY:name=''
+@WIN-ALLOW:value*
+@WIN-DENY:value='file://*'
 @WIN-ALLOW:xml-roles*
 -->
 <!DOCTYPE html>
diff --git a/content/test/data/accessibility/aria/aria-scrollbar-expected-win.txt b/content/test/data/accessibility/aria/aria-scrollbar-expected-win.txt
index 20c3360..15dfc04f 100644
--- a/content/test/data/accessibility/aria/aria-scrollbar-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-scrollbar-expected-win.txt
@@ -1,3 +1,3 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0><obj1>'
-++ROLE_SYSTEM_SCROLLBAR FOCUSABLE IA2_STATE_VERTICAL xml-roles:scrollbar currentValue=55.00
-++ROLE_SYSTEM_SCROLLBAR FOCUSABLE IA2_STATE_HORIZONTAL xml-roles:scrollbar currentValue=55.00
+++ROLE_SYSTEM_SCROLLBAR value='55' FOCUSABLE IA2_STATE_VERTICAL xml-roles:scrollbar valuetext:55 currentValue=55.00
+++ROLE_SYSTEM_SCROLLBAR value='55' FOCUSABLE IA2_STATE_HORIZONTAL xml-roles:scrollbar valuetext:55 currentValue=55.00
diff --git a/content/test/data/accessibility/aria/aria-scrollbar.html b/content/test/data/accessibility/aria/aria-scrollbar.html
index 16e71a8..5e61e46 100644
--- a/content/test/data/accessibility/aria/aria-scrollbar.html
+++ b/content/test/data/accessibility/aria/aria-scrollbar.html
@@ -3,6 +3,8 @@
 @WIN-ALLOW:currentValue*
 @WIN-ALLOW:ia2_hypertext=*
 @WIN-ALLOW:IA2_STATE*
+@WIN-ALLOW:value*
+@WIN-DENY:value='file://*'
 @WIN-ALLOW:xml-roles:*
 -->
 <!DOCTYPE html>
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 1b9c772..279def2 100644
--- a/content/test/data/accessibility/aria/aria-searchbox-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-searchbox-expected-win.txt
@@ -1,2 +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_TEXT value='ARIA role searchbox.' FOCUSABLE xml-roles:searchbox ia2_hypertext='ARIA role searchbox.' caret_offset=0 n_selections=0
diff --git a/content/test/data/accessibility/aria/aria-searchbox.html b/content/test/data/accessibility/aria/aria-searchbox.html
index 2be4998..48ab02af 100644
--- a/content/test/data/accessibility/aria/aria-searchbox.html
+++ b/content/test/data/accessibility/aria/aria-searchbox.html
@@ -7,6 +7,8 @@
 @WIN-ALLOW:n_selections*
 @WIN-ALLOW:selection_start*
 @WIN-ALLOW:selection_end*
+@WIN-ALLOW:value*
+@WIN-DENY:value='file://*'
 @WIN-ALLOW:xml-roles*
 -->
 <!DOCTYPE html>
diff --git a/content/test/data/accessibility/aria/aria-slider-expected-win.txt b/content/test/data/accessibility/aria/aria-slider-expected-win.txt
index 01cdc33c4..2265f9e9 100644
--- a/content/test/data/accessibility/aria/aria-slider-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-slider-expected-win.txt
@@ -1,2 +1,2 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0>'
-++ROLE_SYSTEM_SLIDER xml-roles:slider currentValue=5.00 minimumValue=1.00 maximumValue=10.00
+++ROLE_SYSTEM_SLIDER value='5' xml-roles:slider valuetext:5 currentValue=5.00 minimumValue=1.00 maximumValue=10.00
diff --git a/content/test/data/accessibility/aria/aria-slider.html b/content/test/data/accessibility/aria/aria-slider.html
index 40c76b2..5047a0d 100644
--- a/content/test/data/accessibility/aria/aria-slider.html
+++ b/content/test/data/accessibility/aria/aria-slider.html
@@ -5,6 +5,8 @@
 @WIN-ALLOW:ia2_hypertext=*
 @WIN-ALLOW:maximumValue*
 @WIN-ALLOW:minimumValue*
+@WIN-ALLOW:value*
+@WIN-DENY:value='file://*'
 @WIN-ALLOW:xml-roles:*
 -->
 <!DOCTYPE html>
diff --git a/content/test/data/accessibility/aria/aria-textbox-expected-win.txt b/content/test/data/accessibility/aria/aria-textbox-expected-win.txt
index a8ac67d..e63d5abd9 100644
--- a/content/test/data/accessibility/aria/aria-textbox-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-textbox-expected-win.txt
@@ -1,3 +1,3 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0><obj1>' n_selections=0
-++ROLE_SYSTEM_TEXT IA2_STATE_SINGLE_LINE xml-roles:textbox ia2_hypertext='TextBox1' caret_offset=0 n_selections=0
-++ROLE_SYSTEM_TEXT IA2_STATE_MULTI_LINE xml-roles:textbox ia2_hypertext='TextBox2' caret_offset=0 n_selections=0
+++ROLE_SYSTEM_TEXT value='TextBox1' IA2_STATE_SINGLE_LINE xml-roles:textbox ia2_hypertext='TextBox1' caret_offset=0 n_selections=0
+++ROLE_SYSTEM_TEXT value='TextBox2' IA2_STATE_MULTI_LINE xml-roles:textbox ia2_hypertext='TextBox2' caret_offset=0 n_selections=0
diff --git a/content/test/data/accessibility/aria/aria-textbox.html b/content/test/data/accessibility/aria/aria-textbox.html
index 25bb225..e8cdf69 100644
--- a/content/test/data/accessibility/aria/aria-textbox.html
+++ b/content/test/data/accessibility/aria/aria-textbox.html
@@ -7,6 +7,8 @@
 @WIN-ALLOW:n_selections*
 @WIN-ALLOW:selection_start*
 @WIN-ALLOW:selection_end*
+@WIN-ALLOW:value*
+@WIN-DENY:value='file://*'
 @WIN-ALLOW:xml-roles*
 -->
 <!DOCTYPE html>
diff --git a/content/test/data/accessibility/html/input-email-expected-win.txt b/content/test/data/accessibility/html/input-email-expected-win.txt
index e0a9555..942be6a 100644
--- a/content/test/data/accessibility/html/input-email-expected-win.txt
+++ b/content/test/data/accessibility/html/input-email-expected-win.txt
@@ -1,3 +1,3 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0>' n_selections=0
 ++IA2_ROLE_SECTION ia2_hypertext='<obj0>' n_selections=0
-++++ROLE_SYSTEM_TEXT FOCUSABLE text-input-type:email ia2_hypertext='someone@example.com' caret_offset=0 n_selections=0
+++++ROLE_SYSTEM_TEXT value='someone@example.com' FOCUSABLE text-input-type:email ia2_hypertext='someone@example.com' caret_offset=0 n_selections=0
diff --git a/content/test/data/accessibility/html/input-email.html b/content/test/data/accessibility/html/input-email.html
index e4dd522f..b812b2f 100644
--- a/content/test/data/accessibility/html/input-email.html
+++ b/content/test/data/accessibility/html/input-email.html
@@ -6,6 +6,8 @@
 @WIN-ALLOW:selection_start*
 @WIN-ALLOW:selection_end*
 @WIN-ALLOW:text-input-type*
+@WIN-ALLOW:value*
+@WIN-DENY:value='file://*'
 -->
 <!DOCTYPE html>
 <html>
diff --git a/content/test/data/accessibility/html/input-tel-expected-win.txt b/content/test/data/accessibility/html/input-tel-expected-win.txt
index daab4eb..e512259 100644
--- a/content/test/data/accessibility/html/input-tel-expected-win.txt
+++ b/content/test/data/accessibility/html/input-tel-expected-win.txt
@@ -1,3 +1,3 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0>' n_selections=0
 ++IA2_ROLE_SECTION ia2_hypertext='<obj0>' n_selections=0
-++++ROLE_SYSTEM_TEXT FOCUSABLE text-input-type:tel ia2_hypertext='123-456-7890' caret_offset=0 n_selections=0
+++++ROLE_SYSTEM_TEXT value='123-456-7890' FOCUSABLE text-input-type:tel ia2_hypertext='123-456-7890' caret_offset=0 n_selections=0
diff --git a/content/test/data/accessibility/html/input-tel.html b/content/test/data/accessibility/html/input-tel.html
index 3cba879..6ae5957 100644
--- a/content/test/data/accessibility/html/input-tel.html
+++ b/content/test/data/accessibility/html/input-tel.html
@@ -5,6 +5,8 @@
 @WIN-ALLOW:selection_start*
 @WIN-ALLOW:selection_end*
 @WIN-ALLOW:text-input-type*
+@WIN-ALLOW:value*
+@WIN-DENY:value='file://*'
 -->
 <!DOCTYPE html>
 <html>
diff --git a/content/test/data/accessibility/html/input-text-expected-mac.txt b/content/test/data/accessibility/html/input-text-expected-mac.txt
index 893526f3..30397417 100644
--- a/content/test/data/accessibility/html/input-text-expected-mac.txt
+++ b/content/test/data/accessibility/html/input-text-expected-mac.txt
@@ -1,3 +1,3 @@
 AXWebArea AXRoleDescription='HTML content'
 ++AXGroup AXRoleDescription='group'
-++++AXTextField AXRoleDescription='text field' AXDescription='Name'
+++++AXTextField AXRoleDescription='text field' AXValue='Name' AXDescription='Name'
diff --git a/content/test/data/accessibility/html/input-text-expected-win.txt b/content/test/data/accessibility/html/input-text-expected-win.txt
index 291a11f..ca4608b8 100644
--- a/content/test/data/accessibility/html/input-text-expected-win.txt
+++ b/content/test/data/accessibility/html/input-text-expected-win.txt
@@ -1,3 +1,3 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0>' caret_offset=0 n_selections=0
 ++IA2_ROLE_SECTION ia2_hypertext='<obj0>' caret_offset=0 n_selections=0
-++++ROLE_SYSTEM_TEXT name='Name' FOCUSABLE IA2_STATE_EDITABLE IA2_STATE_SELECTABLE_TEXT IA2_STATE_SINGLE_LINE text-input-type:text caret_offset=0 n_selections=0
+++++ROLE_SYSTEM_TEXT name='Name' value='Name' FOCUSABLE IA2_STATE_EDITABLE IA2_STATE_SELECTABLE_TEXT IA2_STATE_SINGLE_LINE text-input-type:text ia2_hypertext='Name' caret_offset=0 n_selections=0
diff --git a/content/test/data/accessibility/html/input-text-name-calc-expected-android.txt b/content/test/data/accessibility/html/input-text-name-calc-expected-android.txt
index 849006f..994975c 100644
--- a/content/test/data/accessibility/html/input-text-name-calc-expected-android.txt
+++ b/content/test/data/accessibility/html/input-text-name-calc-expected-android.txt
@@ -5,5 +5,5 @@
 ++++android.widget.EditText clickable editable_text focusable name='AriaLabel2 Title2' input_type=1
 ++++android.widget.EditText clickable editable_text focusable name='LabelledBy3 Title3' input_type=1
 ++++android.widget.EditText clickable editable_text focusable name='Placeholder4' input_type=1
-++++android.widget.EditText clickable editable_text focusable name='Placeholder5 Title5' input_type=1
+++++android.widget.EditText clickable editable_text focusable name='Placeholder5' input_type=1
 ++++android.widget.EditText clickable editable_text focusable name='LabelledBy6 DescribedBy6' input_type=1
diff --git a/content/test/data/accessibility/html/input-text.html b/content/test/data/accessibility/html/input-text.html
index fa30bf54..bb160b98 100644
--- a/content/test/data/accessibility/html/input-text.html
+++ b/content/test/data/accessibility/html/input-text.html
@@ -8,6 +8,8 @@
 @WIN-ALLOW:selection_start*
 @WIN-ALLOW:selection_end*
 @WIN-ALLOW:text-input-type*
+@WIN-ALLOW:value*
+@WIN-DENY:value='file://*'
 -->
 <!DOCTYPE html>
 <html>
diff --git a/content/test/web_contents_observer_sanity_checker.cc b/content/test/web_contents_observer_sanity_checker.cc
index ce22bed..187f518 100644
--- a/content/test/web_contents_observer_sanity_checker.cc
+++ b/content/test/web_contents_observer_sanity_checker.cc
@@ -84,6 +84,10 @@
                  << " for which RenderFrameCreated was never called";
 #endif
   }
+
+  // All players should have been paused by this point.
+  for (const auto& id : active_media_players_)
+    CHECK_NE(id.first, render_frame_host);
 }
 
 void WebContentsObserverSanityChecker::RenderFrameForInterstitialPageCreated(
@@ -258,6 +262,24 @@
   AssertRenderFrameExists(source_render_frame_host);
 }
 
+void WebContentsObserverSanityChecker::MediaStartedPlaying(
+    const MediaPlayerId& id) {
+  CHECK(!web_contents_destroyed_);
+  CHECK(std::find(active_media_players_.begin(), active_media_players_.end(),
+                  id) == active_media_players_.end());
+  active_media_players_.push_back(id);
+}
+
+void WebContentsObserverSanityChecker::MediaStoppedPlaying(
+    const MediaPlayerId& id) {
+  CHECK(!web_contents_destroyed_);
+  CHECK(std::find(active_media_players_.begin(), active_media_players_.end(),
+                  id) != active_media_players_.end());
+  active_media_players_.erase(std::remove(active_media_players_.begin(),
+                                          active_media_players_.end(), id),
+                              active_media_players_.end());
+}
+
 bool WebContentsObserverSanityChecker::OnMessageReceived(
     const IPC::Message& message,
     RenderFrameHost* render_frame_host) {
@@ -276,6 +298,7 @@
   CHECK(!web_contents_destroyed_);
   web_contents_destroyed_ = true;
   CHECK(ongoing_navigations_.empty());
+  CHECK(active_media_players_.empty());
 }
 
 WebContentsObserverSanityChecker::WebContentsObserverSanityChecker(
diff --git a/content/test/web_contents_observer_sanity_checker.h b/content/test/web_contents_observer_sanity_checker.h
index aa7c9b2..273a2c4 100644
--- a/content/test/web_contents_observer_sanity_checker.h
+++ b/content/test/web_contents_observer_sanity_checker.h
@@ -81,6 +81,8 @@
                            const Referrer& referrer,
                            WindowOpenDisposition disposition,
                            ui::PageTransition transition) override;
+  void MediaStartedPlaying(const MediaPlayerId& id) override;
+  void MediaStoppedPlaying(const MediaPlayerId& id) override;
   bool OnMessageReceived(const IPC::Message& message,
                          RenderFrameHost* render_frame_host) override;
   void WebContentsDestroyed() override;
@@ -100,6 +102,7 @@
   std::set<std::pair<int, int>> deleted_routes_;
 
   std::set<NavigationHandle*> ongoing_navigations_;
+  std::vector<MediaPlayerId> active_media_players_;
 
   bool web_contents_destroyed_;
 
diff --git a/content/zygote/zygote_linux.cc b/content/zygote/zygote_linux.cc
index d582eb1..cb92d71 100644
--- a/content/zygote/zygote_linux.cc
+++ b/content/zygote/zygote_linux.cc
@@ -13,6 +13,7 @@
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+
 #include <utility>
 
 #include "base/command_line.h"
@@ -20,7 +21,6 @@
 #include "base/linux_util.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/memory/scoped_vector.h"
 #include "base/pickle.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/posix/global_descriptors.h"
@@ -229,7 +229,7 @@
 }
 
 bool Zygote::HandleRequestFromBrowser(int fd) {
-  ScopedVector<base::ScopedFD> fds;
+  std::vector<base::ScopedFD> fds;
   char buf[kZygoteMaxMessageLength];
   const ssize_t len = base::UnixDomainSocket::RecvMsg(
       fd, buf, sizeof(buf), &fds);
@@ -237,21 +237,18 @@
   if (len == 0 || (len == -1 && errno == ECONNRESET)) {
     // EOF from the browser. We should die.
     // TODO(earthdok): call __sanititizer_cov_dump() here to obtain code
-    // coverage  for the Zygote. Currently it's not possible because of
+    // coverage for the Zygote. Currently it's not possible because of
     // confusion over who is responsible for closing the file descriptor.
-    for (std::vector<int>::iterator it = extra_fds_.begin();
-         it < extra_fds_.end(); ++it) {
-      PCHECK(0 == IGNORE_EINTR(close(*it)));
+    for (int fd : extra_fds_) {
+      PCHECK(0 == IGNORE_EINTR(close(fd)));
     }
 #if !defined(SANITIZER_COVERAGE)
     // TODO(earthdok): add watchdog thread before using this in builds not
     // using sanitizer coverage.
     CHECK(extra_children_.empty());
 #endif
-    for (std::vector<base::ProcessHandle>::iterator it =
-             extra_children_.begin();
-         it < extra_children_.end(); ++it) {
-      PCHECK(*it == HANDLE_EINTR(waitpid(*it, NULL, 0)));
+    for (base::ProcessHandle pid : extra_children_) {
+      PCHECK(pid == HANDLE_EINTR(waitpid(pid, NULL, 0)));
     }
     _exit(0);
     return false;
@@ -270,7 +267,7 @@
     switch (kind) {
       case kZygoteCommandFork:
         // This function call can return multiple times, once per fork().
-        return HandleForkRequest(fd, iter, fds.Pass());
+        return HandleForkRequest(fd, iter, std::move(fds));
 
       case kZygoteCommandReap:
         if (!fds.empty())
@@ -505,7 +502,7 @@
   // be invalid (see below).
   base::ProcessId real_pid;
   {
-    ScopedVector<base::ScopedFD> recv_fds;
+    std::vector<base::ScopedFD> recv_fds;
     char buf[kZygoteMaxMessageLength];
     const ssize_t len = base::UnixDomainSocket::RecvMsg(
         kZygoteSocketPairFd, buf, sizeof(buf), &recv_fds);
@@ -555,7 +552,7 @@
 }
 
 base::ProcessId Zygote::ReadArgsAndFork(base::PickleIterator iter,
-                                        ScopedVector<base::ScopedFD> fds,
+                                        std::vector<base::ScopedFD> fds,
                                         std::string* uma_name,
                                         int* uma_sample,
                                         int* uma_boundary_value) {
@@ -590,14 +587,14 @@
   // First FD is the PID oracle socket.
   if (fds.size() < 1)
     return -1;
-  base::ScopedFD pid_oracle(std::move(*fds[0]));
+  base::ScopedFD pid_oracle(std::move(fds[0]));
 
   // Remaining FDs are for the global descriptor mapping.
   for (int i = 1; i < numfds; ++i) {
     base::GlobalDescriptors::Key key;
     if (!iter.ReadUInt32(&key))
       return -1;
-    mapping.push_back(base::GlobalDescriptors::Descriptor(key, fds[i]->get()));
+    mapping.push_back(base::GlobalDescriptors::Descriptor(key, fds[i].get()));
   }
 
   mapping.push_back(base::GlobalDescriptors::Descriptor(
@@ -614,9 +611,8 @@
     PCHECK(0 == IGNORE_EINTR(close(kZygoteSocketPairFd)));
 
     // Pass ownership of file descriptors from fds to GlobalDescriptors.
-    for (ScopedVector<base::ScopedFD>::iterator i = fds.begin(); i != fds.end();
-         ++i)
-      ignore_result((*i)->release());
+    for (base::ScopedFD& fd : fds)
+      ignore_result(fd.release());
     base::GlobalDescriptors::GetInstance()->Reset(mapping);
 
     // Reset the process-wide command line to our new command line.
@@ -637,12 +633,12 @@
 
 bool Zygote::HandleForkRequest(int fd,
                                base::PickleIterator iter,
-                               ScopedVector<base::ScopedFD> fds) {
+                               std::vector<base::ScopedFD> fds) {
   std::string uma_name;
   int uma_sample;
   int uma_boundary_value;
-  base::ProcessId child_pid = ReadArgsAndFork(
-      iter, fds.Pass(), &uma_name, &uma_sample, &uma_boundary_value);
+  base::ProcessId child_pid = ReadArgsAndFork(iter, std::move(fds), &uma_name,
+                                              &uma_sample, &uma_boundary_value);
   if (child_pid == 0)
     return true;
   // If there's no UMA report for this particular fork, then check if any
diff --git a/content/zygote/zygote_linux.h b/content/zygote/zygote_linux.h
index f96b906d..b1eecd6 100644
--- a/content/zygote/zygote_linux.h
+++ b/content/zygote/zygote_linux.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 
 #include <string>
+#include <vector>
 
 #include "base/containers/small_map.h"
 #include "base/files/scoped_file.h"
@@ -104,7 +105,7 @@
   // Returns -1 on error, otherwise returns twice, returning 0 to the child
   // process and the child process ID to the parent process, like fork().
   base::ProcessId ReadArgsAndFork(base::PickleIterator iter,
-                                  ScopedVector<base::ScopedFD> fds,
+                                  std::vector<base::ScopedFD> fds,
                                   std::string* uma_name,
                                   int* uma_sample,
                                   int* uma_boundary_value);
@@ -115,7 +116,7 @@
   // child_pid of -1 on error.
   bool HandleForkRequest(int fd,
                          base::PickleIterator iter,
-                         ScopedVector<base::ScopedFD> fds);
+                         std::vector<base::ScopedFD> fds);
 
   bool HandleGetSandboxStatus(int fd,
                               base::PickleIterator iter);
diff --git a/crypto/symmetric_key_win.cc b/crypto/symmetric_key_win.cc
index e2dc9b4a..efc7fe4 100644
--- a/crypto/symmetric_key_win.cc
+++ b/crypto/symmetric_key_win.cc
@@ -51,7 +51,7 @@
                   ALG_ID alg,
                   const void* key_data, size_t key_size,
                   ScopedHCRYPTKEY* key) {
-  DCHECK_GT(key_size, 0);
+  DCHECK_GT(key_size, 0u);
 
   DWORD actual_size =
       static_cast<DWORD>(sizeof(PlaintextBlobHeader) + key_size);
@@ -314,7 +314,7 @@
 // static
 SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm,
                                               size_t key_size_in_bits) {
-  DCHECK_GE(key_size_in_bits, 8);
+  DCHECK_GE(key_size_in_bits, 8u);
 
   ScopedHCRYPTPROV provider;
   ScopedHCRYPTKEY key;
@@ -412,7 +412,7 @@
 
   // 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and stop.
   size_t dkLen = key_size_in_bits / 8;
-  DCHECK_GT(dkLen, 0);
+  DCHECK_GT(dkLen, 0u);
 
   if ((dkLen / hLen) > 0xFFFFFFFF) {
     DLOG(ERROR) << "Derived key too long.";
@@ -423,7 +423,7 @@
   //    rounding up, and let r be the number of octets in the last
   //    block:
   size_t L = (dkLen + hLen - 1) / hLen;
-  DCHECK_GT(L, 0);
+  DCHECK_GT(L, 0u);
 
   size_t total_generated_size = L * hLen;
   std::vector<BYTE> generated_key(total_generated_size);
diff --git a/docs/linux_suid_sandbox.md b/docs/linux_suid_sandbox.md
index 5845662..6b144e9a 100644
--- a/docs/linux_suid_sandbox.md
+++ b/docs/linux_suid_sandbox.md
@@ -9,7 +9,7 @@
 The `SUID` helper binary is called `chrome_sandbox` and you must build it
 separately from the main 'chrome' target. To use this sandbox, you have to
 specify its path in the `linux_sandbox_path` GYP variable. When spawning the
-[zygote process](linux_zygote/md), if the `SUID` sandbox is enabled, Chromium
+[zygote process](linux_zygote.md), if the `SUID` sandbox is enabled, Chromium
 will check for the sandbox binary at the location specified by
 `linux_sandbox_path`. For Google Chrome, this is set to
 `/opt/google/chrome/chrome-sandbox`, and early version had this value hard coded
diff --git a/docs/updating_clang.md b/docs/updating_clang.md
index 02dce25c..4d6dde6 100644
--- a/docs/updating_clang.md
+++ b/docs/updating_clang.md
@@ -12,14 +12,14 @@
 1.  Upload the binaries using gsutil, they will appear at
     http://commondatastorage.googleapis.com/chromium-browser-clang/index.html
 1.  Run goma package update script to push these packages to goma, send email
-1.  `git cl try -m tryserver.chromium.mac -b mac_chromium_rel_ng -b
+1.  `git cl try &&
+    git cl try -m tryserver.chromium.mac -b mac_chromium_rel_ng -b
     mac_chromium_asan_rel_ng -b mac_chromium_gn_dbg -b ios_rel_device_ninja &&
-    git cl try -m tryserver.chromium.linux -b linux_chromium_gn_dbg -b
-    linux_chromium_chromeos_dbg_ng -b linux_chromium_asan_rel_ng -b
-    linux_chromium_chromeos_asan_rel_ng -b android_clang_dbg_recipe -b
-    linux_chromium_trusty32_rel -b linux_chromium_rel_ng -b
-    linux_chromium_msan_rel_ng && git cl try -m tryserver.blink -b
-    linux_blink_rel`
+    git cl try -m tryserver.chromium.linux -b linux_chromium_chromeos_dbg_ng
+    -b linux_chromium_asan_rel_ng -b linux_chromium_chromeos_asan_rel_ng
+    -b android_clang_dbg_recipe -b linux_chromium_rel_ng
+    -b linux_chromium_msan_rel_ng &&
+    git cl try -m tryserver.blink -b linux_blink_rel`
 1.  Commit roll CL from the first step
 1.  The bots will now pull the prebuilt binary, and goma will have a matching
     binary, too.
diff --git a/extensions/browser/api/app_runtime/app_runtime_api.cc b/extensions/browser/api/app_runtime/app_runtime_api.cc
index e2b1b630..83649a3 100644
--- a/extensions/browser/api/app_runtime/app_runtime_api.cc
+++ b/extensions/browser/api/app_runtime/app_runtime_api.cc
@@ -98,7 +98,7 @@
       return app_runtime::LAUNCH_SOURCE_EXTENSIONS_PAGE;
     case extensions::SOURCE_MANAGEMENT_API:
       return app_runtime::LAUNCH_SOURCE_MANAGEMENT_API;
-    case extensions::SOURCE_EPHEMERAL_APP_UNUSED:
+    case extensions::SOURCE_EPHEMERAL_APP_DEPRECATED:
       return app_runtime::LAUNCH_SOURCE_EPHEMERAL_APP;
     case extensions::SOURCE_BACKGROUND:
       return app_runtime::LAUNCH_SOURCE_BACKGROUND;
diff --git a/extensions/browser/api/management/management_api.cc b/extensions/browser/api/management/management_api.cc
index e4feaf5..d3d85e7 100644
--- a/extensions/browser/api/management/management_api.cc
+++ b/extensions/browser/api/management/management_api.cc
@@ -246,12 +246,6 @@
   return info.Pass();
 }
 
-bool ShouldNotBeVisible(const Extension* extension,
-                        content::BrowserContext* context) {
-  return (extension->ShouldNotBeVisible() ||
-          ExtensionPrefs::Get(context)->IsEphemeralApp(extension->id()));
-}
-
 void AddExtensionInfo(const ExtensionSet& extensions,
                       ExtensionInfoList* extension_list,
                       content::BrowserContext* context) {
@@ -259,7 +253,7 @@
        iter != extensions.end(); ++iter) {
     const Extension& extension = *iter->get();
 
-    if (ShouldNotBeVisible(&extension, context))
+    if (extension.ShouldNotBeVisible())
       continue;  // Skip built-in extensions/apps.
 
     extension_list->push_back(make_linked_ptr<management::ExtensionInfo>(
@@ -434,7 +428,7 @@
 
   const Extension* extension =
       registry->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
-  if (!extension || ShouldNotBeVisible(extension, browser_context()))
+  if (!extension || extension->ShouldNotBeVisible())
     return RespondNow(Error(keys::kNoExtensionError, extension_id_));
 
   bool enabled = params->enabled;
@@ -523,8 +517,7 @@
       extensions::ExtensionRegistry::Get(browser_context())
           ->GetExtensionById(target_extension_id_,
                              ExtensionRegistry::EVERYTHING);
-  if (!target_extension ||
-      ShouldNotBeVisible(target_extension, browser_context())) {
+  if (!target_extension || target_extension->ShouldNotBeVisible()) {
     return RespondNow(Error(keys::kNoExtensionError, target_extension_id_));
   }
 
@@ -867,7 +860,7 @@
     const Extension* extension,
     events::HistogramValue histogram_value,
     const char* event_name) {
-  if (ShouldNotBeVisible(extension, browser_context_))
+  if (extension->ShouldNotBeVisible())
     return;  // Don't dispatch events for built-in extenions.
   scoped_ptr<base::ListValue> args(new base::ListValue());
   if (event_name == management::OnUninstalled::kEventName) {
diff --git a/extensions/browser/api/runtime/runtime_api.cc b/extensions/browser/api/runtime/runtime_api.cc
index 443f936..1473a433 100644
--- a/extensions/browser/api/runtime/runtime_api.cc
+++ b/extensions/browser/api/runtime/runtime_api.cc
@@ -62,6 +62,15 @@
 // A preference key storing the url loaded when an extension is uninstalled.
 const char kUninstallUrl[] = "uninstall_url";
 
+// A preference key storing the information about an extension that was
+// installed but not loaded. We keep the pending info here so that we can send
+// chrome.runtime.onInstalled event during the extension load.
+const char kPrefPendingOnInstalledEventDispatchInfo[] =
+    "pending_on_installed_event_dispatch_info";
+
+// Previously installed version number.
+const char kPrefPreviousVersion[] = "previous_version";
+
 // The name of the directory to be returned by getPackageDirectoryEntry. This
 // particular value does not matter to user code, but is chosen for consistency
 // with the equivalent Pepper API.
@@ -182,6 +191,15 @@
 
 void RuntimeAPI::OnExtensionLoaded(content::BrowserContext* browser_context,
                                    const Extension* extension) {
+  base::Version previous_version;
+  if (ReadPendingOnInstallInfoFromPref(extension->id(), &previous_version)) {
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&RuntimeEventRouter::DispatchOnInstalledEvent,
+                   browser_context_, extension->id(), previous_version, false));
+    RemovePendingOnInstallInfoFromPref(extension->id());
+  }
+
   if (!dispatch_chrome_updated_event_)
     return;
 
@@ -199,33 +217,19 @@
     content::BrowserContext* browser_context,
     const Extension* extension,
     bool is_update,
-    bool from_ephemeral,
     const std::string& old_name) {
-  // Ephemeral apps are not considered to be installed and do not receive
-  // the onInstalled() event.
-  if (util::IsEphemeralApp(extension->id(), browser_context_))
-    return;
-
-  Version old_version = delegate_->GetPreviousExtensionVersion(extension);
-
-  // Dispatch the onInstalled event.
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&RuntimeEventRouter::DispatchOnInstalledEvent,
-                 browser_context_,
-                 extension->id(),
-                 old_version,
-                 false));
+  // This extension might be disabled before it has a chance to load, e.g. if
+  // the extension increased its permissions. So instead of trying to send the
+  // onInstalled event here, we remember the fact in prefs and fire the event
+  // when the extension is actually loaded.
+  StorePendingOnInstallInfoToPref(extension);
 }
 
 void RuntimeAPI::OnExtensionUninstalled(
     content::BrowserContext* browser_context,
     const Extension* extension,
     UninstallReason reason) {
-  // Ephemeral apps are not considered to be installed, so the uninstall URL
-  // is not invoked when they are removed.
-  if (util::IsEphemeralApp(extension->id(), browser_context_))
-    return;
+  RemovePendingOnInstallInfoFromPref(extension->id());
 
   RuntimeEventRouter::OnExtensionUninstalled(
       browser_context_, extension->id(), reason);
@@ -248,6 +252,53 @@
   RuntimeEventRouter::DispatchOnStartupEvent(browser_context_, extension->id());
 }
 
+bool RuntimeAPI::ReadPendingOnInstallInfoFromPref(
+    const ExtensionId& extension_id,
+    base::Version* previous_version) {
+  ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context_);
+  DCHECK(prefs);
+
+  const base::DictionaryValue* info = nullptr;
+  if (!prefs->ReadPrefAsDictionary(
+          extension_id, kPrefPendingOnInstalledEventDispatchInfo, &info)) {
+    return false;
+  }
+
+  std::string previous_version_string;
+  info->GetString(kPrefPreviousVersion, &previous_version_string);
+  // |previous_version_string| can be empty.
+  *previous_version = base::Version(previous_version_string);
+  return true;
+}
+
+void RuntimeAPI::RemovePendingOnInstallInfoFromPref(
+    const ExtensionId& extension_id) {
+  ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context_);
+  DCHECK(prefs);
+
+  prefs->UpdateExtensionPref(extension_id,
+                             kPrefPendingOnInstalledEventDispatchInfo, nullptr);
+}
+
+void RuntimeAPI::StorePendingOnInstallInfoToPref(const Extension* extension) {
+  ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context_);
+  DCHECK(prefs);
+
+  // |pending_on_install_info| currently only contains a version string. Instead
+  // of making the pref hold a plain string, we store it as a dictionary value
+  // so that we can add more stuff to it in the future if necessary.
+  scoped_ptr<base::DictionaryValue> pending_on_install_info(
+      new base::DictionaryValue());
+  base::Version previous_version =
+      delegate_->GetPreviousExtensionVersion(extension);
+  pending_on_install_info->SetString(
+      kPrefPreviousVersion,
+      previous_version.IsValid() ? previous_version.GetString() : "");
+  prefs->UpdateExtensionPref(extension->id(),
+                             kPrefPendingOnInstalledEventDispatchInfo,
+                             pending_on_install_info.release());
+}
+
 void RuntimeAPI::ReloadExtension(const std::string& extension_id) {
   delegate_->ReloadExtension(extension_id);
 }
diff --git a/extensions/browser/api/runtime/runtime_api.h b/extensions/browser/api/runtime/runtime_api.h
index 6adfe2d..a9ed93f 100644
--- a/extensions/browser/api/runtime/runtime_api.h
+++ b/extensions/browser/api/runtime/runtime_api.h
@@ -75,7 +75,6 @@
   void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
                                   const Extension* extension,
                                   bool is_update,
-                                  bool from_ephemeral,
                                   const std::string& old_name) override;
   void OnExtensionUninstalled(content::BrowserContext* browser_context,
                               const Extension* extension,
@@ -94,6 +93,14 @@
   // ProcessManagerObserver implementation:
   void OnBackgroundHostStartup(const Extension* extension) override;
 
+  // Pref related functions that deals with info about installed extensions that
+  // has not been loaded yet.
+  // Used to send chrome.runtime.onInstalled event upon loading the extensions.
+  bool ReadPendingOnInstallInfoFromPref(const ExtensionId& extension_id,
+                                        base::Version* previous_version);
+  void RemovePendingOnInstallInfoFromPref(const ExtensionId& extension_id);
+  void StorePendingOnInstallInfoToPref(const Extension* extension);
+
   scoped_ptr<RuntimeAPIDelegate> delegate_;
 
   content::BrowserContext* browser_context_;
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc
index 78a966f..e7436f84 100644
--- a/extensions/browser/extension_prefs.cc
+++ b/extensions/browser/extension_prefs.cc
@@ -169,9 +169,6 @@
 // A preference that indicates when an extension is last launched.
 const char kPrefLastLaunchTime[] = "last_launch_time";
 
-// A preference indicating whether the extension is an ephemeral app.
-const char kPrefEphemeralApp[] = "ephemeral_app";
-
 // Am installation parameter bundled with an extension.
 const char kPrefInstallParam[] = "install_parameter";
 
@@ -1173,12 +1170,8 @@
                              install_parameter,
                              extension_dict);
 
-  bool requires_sort_ordinal = extension->RequiresSortOrdinal() &&
-                               (install_flags & kInstallFlagIsEphemeral) == 0;
-  FinishExtensionInfoPrefs(extension->id(),
-                           install_time,
-                           requires_sort_ordinal,
-                           page_ordinal,
+  FinishExtensionInfoPrefs(extension->id(), install_time,
+                           extension->RequiresSortOrdinal(), page_ordinal,
                            extension_dict);
 }
 
@@ -1398,8 +1391,7 @@
   // Add transient data that is needed by FinishDelayedInstallInfo(), but
   // should not be in the final extension prefs. All entries here should have
   // a corresponding Remove() call in FinishDelayedInstallInfo().
-  if (extension->RequiresSortOrdinal() &&
-      (install_flags & kInstallFlagIsEphemeral) == 0) {
+  if (extension->RequiresSortOrdinal()) {
     extension_dict->SetString(
         kPrefSuggestedPageOrdinal,
         page_ordinal.IsValid() ? page_ordinal.ToInternalValue()
@@ -1450,11 +1442,6 @@
       new base::StringValue(
           base::Int64ToString(install_time.ToInternalValue())));
 
-  // Some extension pref values are written conditionally. If they are not
-  // present in the delayed install data, they should be removed when the
-  // delayed install is committed.
-  extension_dict->Remove(kPrefEphemeralApp, NULL);
-
   // Commit the delayed install data.
   for (base::DictionaryValue::Iterator it(*pending_install_dict); !it.IsAtEnd();
        it.Advance()) {
@@ -1516,33 +1503,6 @@
   return extensions_info.Pass();
 }
 
-bool ExtensionPrefs::IsEphemeralApp(const std::string& extension_id) const {
-  if (ReadPrefAsBooleanAndReturn(extension_id, kPrefEphemeralApp))
-    return true;
-
-  // Ephemerality was previously stored in the creation flags, so we must also
-  // check it for backcompatibility.
-  return (GetCreationFlags(extension_id) & Extension::IS_EPHEMERAL) != 0;
-}
-
-void ExtensionPrefs::OnEphemeralAppPromoted(const std::string& extension_id) {
-  DCHECK(IsEphemeralApp(extension_id));
-
-  UpdateExtensionPref(extension_id, kPrefEphemeralApp, NULL);
-
-  // Ephemerality was previously stored in the creation flags, so ensure the bit
-  // is cleared.
-  int creation_flags = Extension::NO_FLAGS;
-  if (ReadPrefAsInteger(extension_id, kPrefCreationFlags, &creation_flags)) {
-    if (creation_flags & Extension::IS_EPHEMERAL) {
-      creation_flags &= ~static_cast<int>(Extension::IS_EPHEMERAL);
-      UpdateExtensionPref(extension_id,
-                          kPrefCreationFlags,
-                          new base::FundamentalValue(creation_flags));
-    }
-  }
-}
-
 bool ExtensionPrefs::WasAppDraggedByUser(
     const std::string& extension_id) const {
   return ReadPrefAsBooleanAndReturn(extension_id, kPrefUserDraggedApp);
@@ -1994,11 +1954,6 @@
   if (install_flags & kInstallFlagIsBlacklistedForMalware)
     extension_dict->Set(kPrefBlacklist, new base::FundamentalValue(true));
 
-  if (install_flags & kInstallFlagIsEphemeral)
-    extension_dict->Set(kPrefEphemeralApp, new base::FundamentalValue(true));
-  else
-    extension_dict->Remove(kPrefEphemeralApp, NULL);
-
   base::FilePath::StringType path = MakePathRelative(install_directory_,
                                                      extension->path());
   extension_dict->Set(kPrefPath, new base::StringValue(path));
diff --git a/extensions/browser/extension_prefs.h b/extensions/browser/extension_prefs.h
index b2a3dd6c..1236d4e6 100644
--- a/extensions/browser/extension_prefs.h
+++ b/extensions/browser/extension_prefs.h
@@ -452,12 +452,6 @@
   // information.
   scoped_ptr<ExtensionsInfo> GetAllDelayedInstallInfo() const;
 
-  // Returns true if the extension is an ephemeral app.
-  bool IsEphemeralApp(const std::string& extension_id) const;
-
-  // Promotes an ephemeral app to a regular installed app.
-  void OnEphemeralAppPromoted(const std::string& extension_id);
-
   // Returns true if the user repositioned the app on the app launcher via drag
   // and drop.
   bool WasAppDraggedByUser(const std::string& extension_id) const;
diff --git a/extensions/browser/extension_registry.cc b/extensions/browser/extension_registry.cc
index 777ebe9f..9be2e70 100644
--- a/extensions/browser/extension_registry.cc
+++ b/extensions/browser/extension_registry.cc
@@ -75,17 +75,14 @@
 
 void ExtensionRegistry::TriggerOnWillBeInstalled(const Extension* extension,
                                                  bool is_update,
-                                                 bool from_ephemeral,
                                                  const std::string& old_name) {
   CHECK(extension);
   DCHECK_EQ(is_update,
             GenerateInstalledExtensionsSet()->Contains(extension->id()));
   DCHECK_EQ(is_update, !old_name.empty());
-  FOR_EACH_OBSERVER(
-      ExtensionRegistryObserver,
-      observers_,
-      OnExtensionWillBeInstalled(
-          browser_context_, extension, is_update, from_ephemeral, old_name));
+  FOR_EACH_OBSERVER(ExtensionRegistryObserver, observers_,
+                    OnExtensionWillBeInstalled(browser_context_, extension,
+                                               is_update, old_name));
 }
 
 void ExtensionRegistry::TriggerOnInstalled(const Extension* extension,
diff --git a/extensions/browser/extension_registry.h b/extensions/browser/extension_registry.h
index 801832ab..1b777b4 100644
--- a/extensions/browser/extension_registry.h
+++ b/extensions/browser/extension_registry.h
@@ -102,12 +102,8 @@
   // any installed extension with |extension|'s ID. If this is an update then
   // |is_update| is true and must be an installed extension with |extension|'s
   // ID, and |old_name| must be non-empty.
-  // If true, |from_ephemeral| indicates that the extension was previously
-  // installed ephemerally and has been promoted to a regular installed
-  // extension. |is_update| should also be true.
   void TriggerOnWillBeInstalled(const Extension* extension,
                                 bool is_update,
-                                bool from_ephemeral,
                                 const std::string& old_name);
 
   // Invokes the observer method OnExtensionInstalled(). The extension must be
diff --git a/extensions/browser/extension_registry_observer.h b/extensions/browser/extension_registry_observer.h
index a3bfeb3..2b98465 100644
--- a/extensions/browser/extension_registry_observer.h
+++ b/extensions/browser/extension_registry_observer.h
@@ -45,10 +45,6 @@
   // Called when |extension| is about to be installed. |is_update| is true if
   // the installation is the result of it updating, in which case |old_name| is
   // the name of the extension's previous version.
-  // If true, |from_ephemeral| indicates that the extension was previously
-  // installed ephemerally and has been promoted to a regular installed
-  // extension. |is_update| will be true, although the version has not
-  // necessarily changed.
   // The ExtensionRegistry will not be tracking |extension| at the time this
   // event is fired, but will be immediately afterwards (note: not necessarily
   // enabled; it might be installed in the disabled or even blacklisted sets,
@@ -57,13 +53,12 @@
   // (OnExtensionLoaded).
   //
   // TODO(tmdiep): We should stash the state of the previous extension version
-  // somewhere and have observers retrieve it. |is_update|, |from_ephemeral|
-  // and |old_name| can be removed when this is done.
+  // somewhere and have observers retrieve it. |is_update|, and |old_name| can
+  // be removed when this is done.
   virtual void OnExtensionWillBeInstalled(
       content::BrowserContext* browser_context,
       const Extension* extension,
       bool is_update,
-      bool from_ephemeral,
       const std::string& old_name) {}
 
   // Called when the installation of |extension| is complete. At this point the
diff --git a/extensions/browser/extension_registry_unittest.cc b/extensions/browser/extension_registry_unittest.cc
index 40cd4fd..a8bc2012 100644
--- a/extensions/browser/extension_registry_unittest.cc
+++ b/extensions/browser/extension_registry_unittest.cc
@@ -65,7 +65,6 @@
   void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
                                   const Extension* extension,
                                   bool is_update,
-                                  bool from_ephemeral,
                                   const std::string& old_name) override {
     installed_.push_back(extension);
   }
@@ -246,14 +245,13 @@
   scoped_refptr<const Extension> extension =
       test_util::CreateEmptyExtension("id");
 
-  registry.TriggerOnWillBeInstalled(extension.get(), false, false,
-                                    std::string());
+  registry.TriggerOnWillBeInstalled(extension.get(), false, std::string());
   EXPECT_TRUE(HasSingleExtension(observer.installed(), extension.get()));
 
   registry.AddEnabled(extension);
   registry.TriggerOnLoaded(extension.get());
 
-  registry.TriggerOnWillBeInstalled(extension.get(), true, false, "foo");
+  registry.TriggerOnWillBeInstalled(extension.get(), true, "foo");
 
   EXPECT_TRUE(HasSingleExtension(observer.loaded(), extension.get()));
   EXPECT_TRUE(observer.unloaded().empty());
diff --git a/extensions/browser/extension_util.cc b/extensions/browser/extension_util.cc
index 23de1305..4981790a 100644
--- a/extensions/browser/extension_util.cc
+++ b/extensions/browser/extension_util.cc
@@ -12,18 +12,6 @@
 namespace extensions {
 namespace util {
 
-bool IsExtensionInstalledPermanently(const std::string& extension_id,
-                                     content::BrowserContext* context) {
-  const Extension* extension = ExtensionRegistry::Get(context)->
-      GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
-  return extension && !IsEphemeralApp(extension_id, context);
-}
-
-bool IsEphemeralApp(const std::string& extension_id,
-                    content::BrowserContext* context) {
-  return ExtensionPrefs::Get(context)->IsEphemeralApp(extension_id);
-}
-
 bool HasIsolatedStorage(const ExtensionInfo& info) {
   if (!info.extension_manifest.get())
     return false;
diff --git a/extensions/browser/extension_util.h b/extensions/browser/extension_util.h
index b5f758e..cdd4218 100644
--- a/extensions/browser/extension_util.h
+++ b/extensions/browser/extension_util.h
@@ -19,19 +19,10 @@
 
 namespace util {
 
-// TODO(tmdiep): Move functions from
+// TODO(benwells): Move functions from
 // chrome/browser/extensions/extension_util.h/cc that are only dependent on
 // extensions/ here.
 
-// Returns true if |extension_id| identifies an extension that is installed
-// permanently and not ephemerally.
-bool IsExtensionInstalledPermanently(const std::string& extension_id,
-                                     content::BrowserContext* context);
-
-// Returns true if |extension_id| identifies an ephemeral app.
-bool IsEphemeralApp(const std::string& extension_id,
-                    content::BrowserContext* context);
-
 // Returns true if the extension has isolated storage.
 bool HasIsolatedStorage(const ExtensionInfo& info);
 
diff --git a/extensions/browser/guest_view/OWNERS b/extensions/browser/guest_view/OWNERS
index 4ca0031..0107391 100644
--- a/extensions/browser/guest_view/OWNERS
+++ b/extensions/browser/guest_view/OWNERS
@@ -1,5 +1,6 @@
 fsamuel@chromium.org
 lazyboy@chromium.org
+lfg@chromium.org
 hanxi@chromium.org
 paulmeyer@chromium.org
 wjmaclean@chromium.org
diff --git a/extensions/browser/install_flag.h b/extensions/browser/install_flag.h
index f157a6e..90850ee9 100644
--- a/extensions/browser/install_flag.h
+++ b/extensions/browser/install_flag.h
@@ -20,7 +20,7 @@
   kInstallFlagIsBlacklistedForMalware = 1 << 1,
 
   // This is an ephemeral app.
-  kInstallFlagIsEphemeral = 1 << 2,
+  kInstallFlagIsEphemeral_Deprecated = 1 << 2,
 
   // Install the extension immediately, don't wait until idle.
   kInstallFlagInstallImmediately = 1 << 3,
diff --git a/extensions/browser/mojo/keep_alive_impl_unittest.cc b/extensions/browser/mojo/keep_alive_impl_unittest.cc
index 0268358..72e61b36 100644
--- a/extensions/browser/mojo/keep_alive_impl_unittest.cc
+++ b/extensions/browser/mojo/keep_alive_impl_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "extensions/browser/mojo/keep_alive_impl.h"
 
+#include <utility>
+
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "content/public/browser/notification_service.h"
@@ -25,17 +27,16 @@
     message_loop_.reset(new base::MessageLoop);
     extension_ =
         ExtensionBuilder()
-            .SetManifest(
-                 DictionaryBuilder()
-                     .Set("name", "app")
-                     .Set("version", "1")
-                     .Set("manifest_version", 2)
-                     .Set("app",
-                          DictionaryBuilder().Set(
-                              "background",
-                              DictionaryBuilder().Set(
-                                  "scripts",
-                                  ListBuilder().Append("background.js")))))
+            .SetManifest(DictionaryBuilder()
+                             .Set("name", "app")
+                             .Set("version", "1")
+                             .Set("manifest_version", 2)
+                             .Set("app", DictionaryBuilder().Set(
+                                             "background",
+                                             DictionaryBuilder().Set(
+                                                 "scripts",
+                                                 std::move(ListBuilder().Append(
+                                                     "background.js"))))))
             .SetID("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
             .Build();
   }
@@ -107,15 +108,15 @@
   scoped_refptr<const Extension> other_extension =
       ExtensionBuilder()
           .SetManifest(
-               DictionaryBuilder()
-                   .Set("name", "app")
-                   .Set("version", "1")
-                   .Set("manifest_version", 2)
-                   .Set("app", DictionaryBuilder().Set(
-                                   "background",
-                                   DictionaryBuilder().Set(
-                                       "scripts",
-                                       ListBuilder().Append("background.js")))))
+              DictionaryBuilder()
+                  .Set("name", "app")
+                  .Set("version", "1")
+                  .Set("manifest_version", 2)
+                  .Set("app", DictionaryBuilder().Set(
+                                  "background",
+                                  DictionaryBuilder().Set(
+                                      "scripts", std::move(ListBuilder().Append(
+                                                     "background.js"))))))
           .SetID("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
           .Build();
 
diff --git a/extensions/browser/state_store.cc b/extensions/browser/state_store.cc
index 4a04d3a9..da65fd7 100644
--- a/extensions/browser/state_store.cc
+++ b/extensions/browser/state_store.cc
@@ -149,7 +149,6 @@
     content::BrowserContext* browser_context,
     const Extension* extension,
     bool is_update,
-    bool from_ephemeral,
     const std::string& old_name) {
   RemoveKeysForExtension(extension->id());
 }
diff --git a/extensions/browser/state_store.h b/extensions/browser/state_store.h
index 0cb475b..3809c1e3 100644
--- a/extensions/browser/state_store.h
+++ b/extensions/browser/state_store.h
@@ -92,7 +92,6 @@
   void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
                                   const Extension* extension,
                                   bool is_update,
-                                  bool from_ephemeral,
                                   const std::string& old_name) override;
 
   // Path to our database, on disk. Empty during testing.
diff --git a/extensions/browser/test_extension_registry_observer.cc b/extensions/browser/test_extension_registry_observer.cc
index 336c7aa1..4fb69440 100644
--- a/extensions/browser/test_extension_registry_observer.cc
+++ b/extensions/browser/test_extension_registry_observer.cc
@@ -75,7 +75,6 @@
     content::BrowserContext* browser_context,
     const Extension* extension,
     bool is_update,
-    bool from_ephemeral,
     const std::string& old_name) {
   if (extension_id_.empty() || extension->id() == extension_id_)
     will_be_installed_waiter_->OnObserved(extension);
diff --git a/extensions/browser/test_extension_registry_observer.h b/extensions/browser/test_extension_registry_observer.h
index cd422c0..910133a 100644
--- a/extensions/browser/test_extension_registry_observer.h
+++ b/extensions/browser/test_extension_registry_observer.h
@@ -38,7 +38,6 @@
   void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
                                   const Extension* extension,
                                   bool is_update,
-                                  bool from_ephemeral,
                                   const std::string& old_name) override;
   void OnExtensionUninstalled(content::BrowserContext* browser_context,
                               const Extension* extension,
diff --git a/extensions/common/api/display_source.idl b/extensions/common/api/display_source.idl
index a3821e35..f65a82a 100644
--- a/extensions/common/api/display_source.idl
+++ b/extensions/common/api/display_source.idl
@@ -89,7 +89,12 @@
 
   callback GetSinksCallback = void (SinkInfo[] result);
   callback RequestAuthenticationCallback = void (AuthenticationInfo result);
-  callback TerminateSessionCallback = void ();
+
+  // The callback is used by <code>startSession, terminateSession</code>
+  // to signal completion. The callback is called with
+  // <code>chrome.runtime.lastError</code> set to error
+  // message if the call has failed.
+  [inline_doc] callback CallCompleteCallback = void ();
  
   interface Functions {
     // Queries the list of the currently available Display sinks.
@@ -123,13 +128,15 @@
     // are required by the sink; otherwise its |data| field must contain the
     // required authentication data (e.g. PIN value) and its |method| field must
     // be the same as one obtained from ‘requestAuthentication’.
-    [nocompile] static void startSession(StartSessionInfo sessionInfo);
+    // |callback| : Called when the session is started.
+    [nocompile] static void startSession(
+        StartSessionInfo sessionInfo, optional CallCompleteCallback callback);
 
     // Terminates the active Display session.
     // |sinkId| : Id of the connected sink.
     // |callback| : Called when the session is terminated.
     [nocompile] static void terminateSession(
-        long sinkId, optional TerminateSessionCallback callback);
+        long sinkId, optional CallCompleteCallback callback);
   };
 
   interface Events {
diff --git a/extensions/common/constants.h b/extensions/common/constants.h
index a59d337..37d0085 100644
--- a/extensions/common/constants.h
+++ b/extensions/common/constants.h
@@ -126,7 +126,7 @@
   SOURCE_KEYBOARD,
   SOURCE_EXTENSIONS_PAGE,
   SOURCE_MANAGEMENT_API,
-  SOURCE_EPHEMERAL_APP_UNUSED,
+  SOURCE_EPHEMERAL_APP_DEPRECATED,
   SOURCE_BACKGROUND,
   SOURCE_KIOSK,
   SOURCE_CHROME_INTERNAL,
diff --git a/extensions/common/extension.h b/extensions/common/extension.h
index 75495fb8e..72c4396 100644
--- a/extensions/common/extension.h
+++ b/extensions/common/extension.h
@@ -102,10 +102,9 @@
     DISABLE_GREYLIST = 1 << 9,
     DISABLE_CORRUPTED = 1 << 10,
     DISABLE_REMOTE_INSTALL = 1 << 11,
-    DISABLE_INACTIVE_EPHEMERAL_APP = 1 << 12,  // Cached ephemeral apps are
-                                               // disabled to prevent activity.
-    DISABLE_EXTERNAL_EXTENSION = 1 << 13,      // External extensions might be
-                                               // disabled for user prompting.
+    // DISABLE_INACTIVE_EPHEMERAL_APP = 1 << 12,  // Deprecated.
+    DISABLE_EXTERNAL_EXTENSION = 1 << 13,  // External extensions might be
+                                           // disabled for user prompting.
     DISABLE_UPDATE_REQUIRED_BY_POLICY = 1 << 14,  // Doesn't meet minimum
                                                   // version requirement.
     DISABLE_REASON_LAST = 1 << 15,  // This should always be the last value
diff --git a/extensions/common/features/base_feature_provider_unittest.cc b/extensions/common/features/base_feature_provider_unittest.cc
index dc41366..30850a3 100644
--- a/extensions/common/features/base_feature_provider_unittest.cc
+++ b/extensions/common/features/base_feature_provider_unittest.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <set>
 #include <string>
+#include <utility>
 
 #include "base/stl_util.h"
 #include "extensions/common/extension_builder.h"
@@ -99,16 +100,16 @@
 
   scoped_refptr<const Extension> app =
       ExtensionBuilder()
-          .SetManifest(DictionaryBuilder()
-                           .Set("name", "test app")
-                           .Set("version", "1")
-                           .Set("app",
-                                DictionaryBuilder().Set(
-                                    "background",
-                                    DictionaryBuilder().Set(
-                                        "scripts",
-                                        ListBuilder().Append("background.js"))))
-                           .Set("permissions", ListBuilder().Append("power")))
+          .SetManifest(
+              DictionaryBuilder()
+                  .Set("name", "test app")
+                  .Set("version", "1")
+                  .Set("app", DictionaryBuilder().Set(
+                                  "background",
+                                  DictionaryBuilder().Set(
+                                      "scripts", std::move(ListBuilder().Append(
+                                                     "background.js")))))
+                  .Set("permissions", std::move(ListBuilder().Append("power"))))
           .Build();
   ASSERT_TRUE(app.get());
   ASSERT_TRUE(app->is_platform_app());
diff --git a/extensions/common/features/complex_feature_unittest.cc b/extensions/common/features/complex_feature_unittest.cc
index 54355aa4..d06a15a 100644
--- a/extensions/common/features/complex_feature_unittest.cc
+++ b/extensions/common/features/complex_feature_unittest.cc
@@ -5,6 +5,7 @@
 #include "extensions/common/features/complex_feature.h"
 
 #include <string>
+#include <utility>
 
 #include "extensions/common/features/simple_feature.h"
 #include "extensions/common/manifest.h"
@@ -23,18 +24,19 @@
   scoped_ptr<SimpleFeature> simple_feature(new SimpleFeature);
   scoped_ptr<base::DictionaryValue> rule(
       DictionaryBuilder()
-      .Set("whitelist", ListBuilder().Append(kIdFoo))
-      .Set("extension_types", ListBuilder()
-          .Append("extension")).Build());
+          .Set("whitelist", std::move(ListBuilder().Append(kIdFoo)))
+          .Set("extension_types", std::move(ListBuilder().Append("extension")))
+          .Build());
   simple_feature->Parse(rule.get());
   features->push_back(simple_feature.Pass());
 
   // Rule: "legacy_packaged_app", whitelist "bar".
   simple_feature.reset(new SimpleFeature);
   rule = DictionaryBuilder()
-      .Set("whitelist", ListBuilder().Append(kIdBar))
-      .Set("extension_types", ListBuilder()
-          .Append("legacy_packaged_app")).Build();
+             .Set("whitelist", std::move(ListBuilder().Append(kIdBar)))
+             .Set("extension_types",
+                  std::move(ListBuilder().Append("legacy_packaged_app")))
+             .Build();
   simple_feature->Parse(rule.get());
   features->push_back(simple_feature.Pass());
 
@@ -84,8 +86,8 @@
   scoped_ptr<SimpleFeature> simple_feature(new SimpleFeature);
   scoped_ptr<base::DictionaryValue> rule =
       DictionaryBuilder()
-          .Set("dependencies",
-               ListBuilder().Append("manifest:content_security_policy"))
+          .Set("dependencies", std::move(ListBuilder().Append(
+                                   "manifest:content_security_policy")))
           .Build();
   simple_feature->Parse(rule.get());
   features->push_back(simple_feature.Pass());
@@ -93,7 +95,8 @@
   // Rule which depends on an platform-app-only feature (serial).
   simple_feature.reset(new SimpleFeature);
   rule = DictionaryBuilder()
-             .Set("dependencies", ListBuilder().Append("permission:serial"))
+             .Set("dependencies",
+                  std::move(ListBuilder().Append("permission:serial")))
              .Build();
   simple_feature->Parse(rule.get());
   features->push_back(simple_feature.Pass());
diff --git a/extensions/common/test_util.cc b/extensions/common/test_util.cc
index dafbca23..9a9312a 100644
--- a/extensions/common/test_util.cc
+++ b/extensions/common/test_util.cc
@@ -4,6 +4,8 @@
 
 #include "extensions/common/test_util.h"
 
+#include <utility>
+
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/value_builder.h"
@@ -29,8 +31,8 @@
                extensions::DictionaryBuilder().Set(
                    "background",
                    extensions::DictionaryBuilder().Set(
-                       "scripts",
-                       extensions::ListBuilder().Append("background.js")))));
+                       "scripts", std::move(extensions::ListBuilder().Append(
+                                      "background.js"))))));
 }
 
 scoped_refptr<Extension> CreateEmptyExtension() {
diff --git a/extensions/common/value_builder.cc b/extensions/common/value_builder.cc
index a69d533..6e73f36 100644
--- a/extensions/common/value_builder.cc
+++ b/extensions/common/value_builder.cc
@@ -5,6 +5,7 @@
 #include "extensions/common/value_builder.h"
 
 #include "base/json/json_writer.h"
+#include "base/values.h"
 
 namespace extensions {
 
@@ -55,7 +56,7 @@
 }
 
 DictionaryBuilder& DictionaryBuilder::Set(const std::string& path,
-                                          ListBuilder& in_value) {
+                                          ListBuilder in_value) {
   dict_->SetWithoutPathExpansion(path, in_value.Build().Pass());
   return *this;
 }
@@ -79,6 +80,14 @@
 }
 ListBuilder::~ListBuilder() {}
 
+ListBuilder::ListBuilder(ListBuilder&& other)
+    : list_(other.Build().release()) {}
+
+ListBuilder& ListBuilder::operator=(ListBuilder&& other) {
+  list_.reset(other.Build().release());
+  return *this;
+}
+
 ListBuilder& ListBuilder::Append(int in_value) {
   list_->Append(new base::FundamentalValue(in_value));
   return *this;
@@ -100,12 +109,12 @@
 }
 
 ListBuilder& ListBuilder::Append(DictionaryBuilder& in_value) {
-  list_->Append(in_value.Build().Pass());
+  list_->Append(in_value.Build());
   return *this;
 }
 
-ListBuilder& ListBuilder::Append(ListBuilder& in_value) {
-  list_->Append(in_value.Build().Pass());
+ListBuilder& ListBuilder::Append(ListBuilder in_value) {
+  list_->Append(in_value.Build());
   return *this;
 }
 
diff --git a/extensions/common/value_builder.h b/extensions/common/value_builder.h
index 4de94b69..cc706fa 100644
--- a/extensions/common/value_builder.h
+++ b/extensions/common/value_builder.h
@@ -16,12 +16,8 @@
 // For methods that take other built types, you can pass the builder directly
 // to the setter without calling Build():
 //
-// DictionaryBuilder().Set("key", ListBuilder()
-//                         .Append("foo").Append("bar") /* No .Build() */);
-//
-// Because of limitations in C++03, and to avoid extra copies, you can't pass a
-// just-constructed Builder into another Builder's method directly. Use the
-// Pass() method.
+// DictionaryBuilder().Set("key", std::move(ListBuilder()
+//                         .Append("foo").Append("bar")) /* No .Build() */);
 //
 // The Build() method invalidates its builder, and returns ownership of the
 // built value.
@@ -35,9 +31,15 @@
 
 #include <string>
 
+#include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
-#include "base/values.h"
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+class Value;
+}
 
 namespace extensions {
 
@@ -51,6 +53,7 @@
 
   // Workaround to allow you to pass rvalue ExtensionBuilders by reference to
   // other functions.
+  // TODO(limasdf): Remove. Write move constructor instead.
   DictionaryBuilder& Pass() { return *this; }
 
   // Can only be called once, after which it's invalid to use the builder.
@@ -66,7 +69,7 @@
   DictionaryBuilder& Set(const std::string& path,
                          const base::string16& in_value);
   DictionaryBuilder& Set(const std::string& path, DictionaryBuilder& in_value);
-  DictionaryBuilder& Set(const std::string& path, ListBuilder& in_value);
+  DictionaryBuilder& Set(const std::string& path, ListBuilder in_value);
   DictionaryBuilder& Set(const std::string& path,
                          scoped_ptr<base::Value> in_value);
 
@@ -84,19 +87,19 @@
   explicit ListBuilder(const base::ListValue& init);
   ~ListBuilder();
 
-  // Workaround to allow you to pass rvalue ExtensionBuilders by reference to
-  // other functions.
-  ListBuilder& Pass() { return *this; }
+  // Move constructor and operator=.
+  ListBuilder(ListBuilder&& other);
+  ListBuilder& operator=(ListBuilder&& other);
 
   // Can only be called once, after which it's invalid to use the builder.
-  scoped_ptr<base::ListValue> Build() { return list_.Pass(); }
+  scoped_ptr<base::ListValue> Build() { return std::move(list_); }
 
   ListBuilder& Append(int in_value);
   ListBuilder& Append(double in_value);
   ListBuilder& Append(const std::string& in_value);
   ListBuilder& Append(const base::string16& in_value);
   ListBuilder& Append(DictionaryBuilder& in_value);
-  ListBuilder& Append(ListBuilder& in_value);
+  ListBuilder& Append(ListBuilder in_value);
 
   // Named differently because overload resolution is too eager to
   // convert implicitly to bool.
@@ -104,6 +107,8 @@
 
  private:
   scoped_ptr<base::ListValue> list_;
+
+  DISALLOW_COPY_AND_ASSIGN(ListBuilder);
 };
 
 }  // namespace extensions
diff --git a/extensions/common/value_builder_unittest.cc b/extensions/common/value_builder_unittest.cc
new file mode 100644
index 0000000..7c47451
--- /dev/null
+++ b/extensions/common/value_builder_unittest.cc
@@ -0,0 +1,37 @@
+// 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 <utility>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "extensions/common/value_builder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ValueBuilderTest = testing::Test;
+
+namespace extensions {
+
+TEST(ValueBuilderTest, Basic) {
+  ListBuilder permission_list;
+  permission_list.Append("tabs").Append("history");
+
+  scoped_ptr<base::DictionaryValue> settings(new base::DictionaryValue);
+
+  ASSERT_FALSE(settings->GetList("permissions", nullptr));
+  settings = DictionaryBuilder()
+                 .Set("permissions", std::move(permission_list))
+                 .Build();
+  base::ListValue* list_value;
+  ASSERT_TRUE(settings->GetList("permissions", &list_value));
+
+  ASSERT_EQ(2U, list_value->GetSize());
+  std::string permission;
+  ASSERT_TRUE(list_value->GetString(0, &permission));
+  ASSERT_EQ(permission, "tabs");
+  ASSERT_TRUE(list_value->GetString(1, &permission));
+  ASSERT_EQ(permission, "history");
+}
+
+}  // namespace extensions
diff --git a/extensions/extensions.gypi b/extensions/extensions.gypi
index 57480ee..e18e6822 100644
--- a/extensions/extensions.gypi
+++ b/extensions/extensions.gypi
@@ -850,6 +850,8 @@
       'renderer/activity_log_converter_strategy.h',
       'renderer/api/automation/automation_api_helper.cc',
       'renderer/api/automation/automation_api_helper.h',
+      'renderer/api/display_source/display_source_session.cc',
+      'renderer/api/display_source/display_source_session.h',
       'renderer/api_activity_logger.cc',
       'renderer/api_activity_logger.h',
       'renderer/api_definitions_natives.cc',
@@ -871,6 +873,8 @@
       'renderer/dispatcher.cc',
       'renderer/dispatcher.h',
       'renderer/dispatcher_delegate.h',
+      'renderer/display_source_custom_bindings.cc',
+      'renderer/display_source_custom_bindings.h',
       'renderer/document_custom_bindings.cc',
       'renderer/document_custom_bindings.h',
       'renderer/dom_activity_logger.cc',
diff --git a/extensions/extensions_tests.gypi b/extensions/extensions_tests.gypi
index 68758604..e164a8c 100644
--- a/extensions/extensions_tests.gypi
+++ b/extensions/extensions_tests.gypi
@@ -138,8 +138,9 @@
       'common/stack_frame_unittest.cc',
       'common/url_pattern_set_unittest.cc',
       'common/url_pattern_unittest.cc',
-      'common/user_script_unittest.cc',
       'common/update_manifest_unittest.cc',
+      'common/user_script_unittest.cc',
+      'common/value_builder_unittest.cc',
       'renderer/activity_log_converter_strategy_unittest.cc',
       'renderer/api/mojo_private/mojo_private_unittest.cc',
       'renderer/api/serial/data_receiver_unittest.cc',
diff --git a/extensions/renderer/api/display_source/OWNERS b/extensions/renderer/api/display_source/OWNERS
new file mode 100644
index 0000000..f7e4f6f
--- /dev/null
+++ b/extensions/renderer/api/display_source/OWNERS
@@ -0,0 +1,2 @@
+alexander.shalamov@intel.com
+mikhail.pozdnyakov@intel.com
diff --git a/extensions/renderer/api/display_source/display_source_session.cc b/extensions/renderer/api/display_source/display_source_session.cc
new file mode 100644
index 0000000..8e66b6f
--- /dev/null
+++ b/extensions/renderer/api/display_source/display_source_session.cc
@@ -0,0 +1,37 @@
+// 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 "extensions/renderer/api/display_source/display_source_session.h"
+
+namespace extensions {
+
+DisplaySourceSession::DisplaySourceSession()
+  : state_(Idle) {
+}
+
+DisplaySourceSession::~DisplaySourceSession() {
+}
+
+void DisplaySourceSession::SetCallbacks(
+    const SinkIdCallback& started_callback,
+    const SinkIdCallback& terminated_callback,
+    const ErrorCallback& error_callback) {
+  DCHECK(started_callback_.is_null());
+  DCHECK(terminated_callback_.is_null());
+  DCHECK(error_callback_.is_null());
+
+  started_callback_ = started_callback;
+  terminated_callback_ = terminated_callback;
+  error_callback_ = error_callback;
+}
+
+scoped_ptr<DisplaySourceSession> DisplaySourceSessionFactory::CreateSession(
+    int sink_id,
+    const blink::WebMediaStreamTrack& video_track,
+    const blink::WebMediaStreamTrack& audio_track,
+    scoped_ptr<DisplaySourceAuthInfo> auth_info) {
+  return nullptr;
+}
+
+}  // namespace extensions
diff --git a/extensions/renderer/api/display_source/display_source_session.h b/extensions/renderer/api/display_source/display_source_session.h
new file mode 100644
index 0000000..b10dce9
--- /dev/null
+++ b/extensions/renderer/api/display_source/display_source_session.h
@@ -0,0 +1,94 @@
+// 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 EXTENSIONS_RENDERER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_SESSION_H_
+#define EXTENSIONS_RENDERER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_SESSION_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "extensions/common/api/display_source.h"
+#include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h"
+
+namespace extensions {
+
+using DisplaySourceAuthInfo = api::display_source::AuthenticationInfo;
+using DisplaySourceErrorType = api::display_source::ErrorType;
+
+// This class represents a generic display source session interface.
+class DisplaySourceSession {
+ public:
+  using SinkIdCallback = base::Callback<void(int sink_id)>;
+  using ErrorCallback =
+      base::Callback<void(int sink_id,
+                          DisplaySourceErrorType error_type,
+                          const std::string& error_description)>;
+
+  // State flow is ether:
+  // 'Idle' -> 'Establishing' -> 'Established' -> 'Terminating' -> 'Idle'
+  // (terminated by Terminate() call)
+  //  or
+  // 'Idle' -> 'Establishing' -> 'Established' -> 'Idle'
+  // (terminated from sink device or due to an error)
+  enum State {
+    Idle,
+    Establishing,
+    Established,
+    Terminating
+  };
+
+  virtual ~DisplaySourceSession();
+
+  // Starts the session.
+  // The session state should be set to 'Establishing' immediately after this
+  // method is called.
+  virtual void Start() = 0;
+
+  // Terminates the session.
+  // The session state should be set to 'Terminating' immediately after this
+  // method is called.
+  virtual void Terminate() = 0;
+
+  State state() const { return state_; }
+
+  // Sets the callbacks invoked to inform about the session's state changes.
+  // It is required to set the callbacks before the session is started.
+  // |started_callback| : Called when the session was actually started (state
+  //                      should be set to 'Established')
+  // |terminated_callback| : Called when the session was actually started (state
+  //                         should be set to 'Idle')
+  // |error_callback| : Called if a fatal error has occured and the session
+  //                    either cannot be started (if was invoked in
+  //                    'Establishing' state) or will be terminated soon for
+  //                    emergency reasons (if was invoked in 'Established'
+  //                    state).
+  void SetCallbacks(const SinkIdCallback& started_callback,
+                    const SinkIdCallback& terminated_callback,
+                    const ErrorCallback& error_callback);
+
+ protected:
+  DisplaySourceSession();
+
+  State state_;
+  SinkIdCallback started_callback_;
+  SinkIdCallback terminated_callback_;
+  ErrorCallback error_callback_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DisplaySourceSession);
+};
+
+class DisplaySourceSessionFactory {
+ public:
+  static scoped_ptr<DisplaySourceSession> CreateSession(
+      int sink_id,
+      const blink::WebMediaStreamTrack& video_track,
+      const blink::WebMediaStreamTrack& audio_track,
+      scoped_ptr<DisplaySourceAuthInfo> auth_info);
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DisplaySourceSessionFactory);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_RENDERER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_SESSION_H_
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index 83fd54d..b6e3a1e 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -55,6 +55,7 @@
 #include "extensions/renderer/context_menus_custom_bindings.h"
 #include "extensions/renderer/css_native_handler.h"
 #include "extensions/renderer/dispatcher_delegate.h"
+#include "extensions/renderer/display_source_custom_bindings.h"
 #include "extensions/renderer/document_custom_bindings.h"
 #include "extensions/renderer/dom_activity_logger.h"
 #include "extensions/renderer/event_bindings.h"
@@ -681,6 +682,9 @@
       std::make_pair("declarativeWebRequest",
                      IDR_DECLARATIVE_WEBREQUEST_CUSTOM_BINDINGS_JS));
   resources.push_back(
+      std::make_pair("displaySource",
+                     IDR_DISPLAY_SOURCE_CUSTOM_BINDINGS_JS));
+  resources.push_back(
       std::make_pair("contextMenus", IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS));
   resources.push_back(
       std::make_pair("contextMenusHandlers", IDR_CONTEXT_MENUS_HANDLERS_JS));
@@ -824,6 +828,9 @@
       scoped_ptr<NativeHandler>(new IdGeneratorCustomBindings(context)));
   module_system->RegisterNativeHandler(
       "runtime", scoped_ptr<NativeHandler>(new RuntimeCustomBindings(context)));
+  module_system->RegisterNativeHandler(
+      "display_source",
+      scoped_ptr<NativeHandler>(new DisplaySourceCustomBindings(context)));
 }
 
 bool Dispatcher::OnControlMessageReceived(const IPC::Message& message) {
diff --git a/extensions/renderer/display_source_custom_bindings.cc b/extensions/renderer/display_source_custom_bindings.cc
new file mode 100644
index 0000000..059d2bbf
--- /dev/null
+++ b/extensions/renderer/display_source_custom_bindings.cc
@@ -0,0 +1,258 @@
+// 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 "extensions/renderer/display_source_custom_bindings.h"
+
+#include "base/bind.h"
+#include "content/public/child/v8_value_converter.h"
+#include "extensions/renderer/script_context.h"
+#include "third_party/WebKit/public/platform/WebMediaStream.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h"
+#include "v8/include/v8.h"
+
+namespace extensions {
+
+using content::V8ValueConverter;
+
+namespace {
+const char kErrorNotSupported[] = "Not supported";
+const char kInvalidStreamArgs[] = "Invalid stream arguments";
+const char kSessionAlreadyStarted[] = "The session has been already started";
+const char kSessionAlreadyTerminating[] = "The session is already terminating";
+const char kSessionNotFound[] = "Session not found";
+}  // namespace
+
+DisplaySourceCustomBindings::DisplaySourceCustomBindings(ScriptContext* context)
+    : ObjectBackedNativeHandler(context),
+      weak_factory_(this) {
+  RouteFunction("StartSession",
+                base::Bind(&DisplaySourceCustomBindings::StartSession,
+                           weak_factory_.GetWeakPtr()));
+  RouteFunction("TerminateSession",
+                base::Bind(&DisplaySourceCustomBindings::TerminateSession,
+                           weak_factory_.GetWeakPtr()));
+}
+
+DisplaySourceCustomBindings::~DisplaySourceCustomBindings() {
+}
+
+void DisplaySourceCustomBindings::Invalidate() {
+  session_map_.clear();
+  weak_factory_.InvalidateWeakPtrs();
+  ObjectBackedNativeHandler::Invalidate();
+}
+
+namespace {
+
+v8::Local<v8::Value> GetChildValue(v8::Local<v8::Object> value,
+                                   const std::string& key_name,
+                                   v8::Isolate* isolate) {
+  v8::Local<v8::Array> property_names(value->GetOwnPropertyNames());
+  for (uint32 i = 0; i < property_names->Length(); ++i) {
+    v8::Local<v8::Value> key(property_names->Get(i));
+    if (key_name == *v8::String::Utf8Value(key)) {
+      v8::TryCatch try_catch(isolate);
+      v8::Local<v8::Value> child_v8 = value->Get(key);
+      if (try_catch.HasCaught()) {
+        return v8::Null(isolate);
+      }
+      return child_v8;
+    }
+  }
+
+  return v8::Null(isolate);
+}
+
+}  // namespace
+
+void DisplaySourceCustomBindings::StartSession(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  CHECK_EQ(1, args.Length());
+  CHECK(args[0]->IsObject());
+  v8::Isolate* isolate = context()->isolate();
+  v8::Local<v8::Object> start_info = args[0].As<v8::Object>();
+
+  v8::Local<v8::Value> sink_id_val =
+      GetChildValue(start_info, "sinkId", isolate);
+  CHECK(sink_id_val->IsInt32());
+  const int sink_id = sink_id_val->ToInt32(isolate)->Value();
+  if (GetDisplaySession(sink_id)) {
+    isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
+        isolate, kSessionAlreadyStarted)));
+    return;
+  }
+
+  v8::Local<v8::Value> video_stream_val =
+      GetChildValue(start_info, "videoTrack", isolate);
+  v8::Local<v8::Value> audio_stream_val =
+      GetChildValue(start_info, "audioTrack", isolate);
+
+  if ((video_stream_val->IsNull() || video_stream_val->IsUndefined()) &&
+      (audio_stream_val->IsNull() || audio_stream_val->IsUndefined())) {
+    isolate->ThrowException(v8::Exception::Error(
+        v8::String::NewFromUtf8(isolate, kInvalidStreamArgs)));
+    return;
+  }
+
+  blink::WebMediaStreamTrack audio_track, video_track;
+
+  if (!video_stream_val->IsNull() && !video_stream_val->IsUndefined()) {
+    CHECK(video_stream_val->IsObject());
+    video_track =
+        blink::WebDOMMediaStreamTrack::fromV8Value(
+            video_stream_val).component();
+    if (video_track.isNull()) {
+      isolate->ThrowException(v8::Exception::Error(
+          v8::String::NewFromUtf8(isolate, kInvalidStreamArgs)));
+      return;
+    }
+  }
+  if (!audio_stream_val->IsNull() && !audio_stream_val->IsUndefined()) {
+    CHECK(audio_stream_val->IsObject());
+    audio_track =
+        blink::WebDOMMediaStreamTrack::fromV8Value(
+            audio_stream_val).component();
+    if (audio_track.isNull()) {
+      isolate->ThrowException(v8::Exception::Error(
+          v8::String::NewFromUtf8(isolate, kInvalidStreamArgs)));
+      return;
+    }
+  }
+
+  scoped_ptr<DisplaySourceAuthInfo> auth_info;
+  v8::Local<v8::Value> auth_info_v8_val =
+      GetChildValue(start_info, "authenticationInfo", isolate);
+  if (!auth_info_v8_val->IsNull()) {
+    CHECK(auth_info_v8_val->IsObject());
+    scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
+    scoped_ptr<base::Value> auth_info_val(
+        converter->FromV8Value(auth_info_v8_val, context()->v8_context()));
+    CHECK(auth_info_val);
+    auth_info = DisplaySourceAuthInfo::FromValue(*auth_info_val);
+  }
+
+  scoped_ptr<DisplaySourceSession> session =
+      DisplaySourceSessionFactory::CreateSession(
+          sink_id, video_track, audio_track, std::move(auth_info));
+  if (!session) {
+    isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
+        isolate, kErrorNotSupported)));
+    return;
+  }
+
+  auto on_started_callback = base::Bind(
+      &DisplaySourceCustomBindings::OnSessionStarted,
+      weak_factory_.GetWeakPtr());
+  auto on_terminated_callback = base::Bind(
+      &DisplaySourceCustomBindings::OnSessionTerminated,
+      weak_factory_.GetWeakPtr());
+  auto on_error_callback = base::Bind(
+      &DisplaySourceCustomBindings::OnSessionError,
+      weak_factory_.GetWeakPtr());
+  session->SetCallbacks(on_started_callback,
+                        on_terminated_callback,
+                        on_error_callback);
+  session_map_.insert(std::make_pair(sink_id, std::move(session)));
+  session->Start();
+}
+
+void DisplaySourceCustomBindings::TerminateSession(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  CHECK_EQ(1, args.Length());
+  CHECK(args[0]->IsInt32());
+
+  v8::Isolate* isolate = context()->isolate();
+  int sink_id = args[0]->ToInt32(args.GetIsolate())->Value();
+  DisplaySourceSession* session = GetDisplaySession(sink_id);
+  if (!session) {
+    isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
+        isolate, kSessionNotFound)));
+    return;
+  }
+
+  if (session->state() == DisplaySourceSession::Terminating) {
+    isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
+        isolate, kSessionAlreadyTerminating)));
+    return;
+  }
+  // The session will get removed from session_map_ in OnSessionTerminated.
+  session->Terminate();
+}
+
+void DisplaySourceCustomBindings::DispatchSessionStarted(int sink_id) const {
+  v8::Isolate* isolate = context()->isolate();
+  v8::HandleScope handle_scope(isolate);
+  v8::Context::Scope context_scope(context()->v8_context());
+  v8::Local<v8::Array> event_args = v8::Array::New(isolate, 1);
+  event_args->Set(0, v8::Integer::New(isolate, sink_id));
+  context()->DispatchEvent("displaySource.onSessionStarted", event_args);
+}
+
+void DisplaySourceCustomBindings::DispatchSessionTerminated(int sink_id) const {
+  v8::Isolate* isolate = context()->isolate();
+  v8::HandleScope handle_scope(isolate);
+  v8::Context::Scope context_scope(context()->v8_context());
+  v8::Local<v8::Array> event_args = v8::Array::New(isolate, 1);
+  event_args->Set(0, v8::Integer::New(isolate, sink_id));
+  context()->DispatchEvent("displaySource.onSessionTerminated", event_args);
+}
+
+void DisplaySourceCustomBindings::DispatchSessionError(
+    int sink_id,
+    DisplaySourceErrorType type,
+    const std::string& message) const {
+  v8::Isolate* isolate = context()->isolate();
+  v8::HandleScope handle_scope(isolate);
+  v8::Context::Scope context_scope(context()->v8_context());
+
+  api::display_source::ErrorInfo error_info;
+  error_info.type = type;
+  if (!message.empty())
+    error_info.description.reset(new std::string(message));
+
+  scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
+  v8::Local<v8::Value> info_arg =
+      converter->ToV8Value(error_info.ToValue().get(),
+                           context()->v8_context());
+
+  v8::Local<v8::Array> event_args = v8::Array::New(isolate, 2);
+  event_args->Set(0, v8::Integer::New(isolate, sink_id));
+  event_args->Set(1, info_arg);
+  context()->DispatchEvent("displaySource.onSessionErrorOccured", event_args);
+}
+
+DisplaySourceSession* DisplaySourceCustomBindings::GetDisplaySession(
+    int sink_id) const {
+  auto iter = session_map_.find(sink_id);
+  if (iter != session_map_.end())
+    return iter->second.get();
+  return nullptr;
+}
+
+void DisplaySourceCustomBindings::OnSessionStarted(int sink_id) {
+  DispatchSessionStarted(sink_id);
+}
+
+void DisplaySourceCustomBindings::OnSessionTerminated(int sink_id) {
+  DisplaySourceSession* session = GetDisplaySession(sink_id);
+  CHECK(session);
+  session_map_.erase(sink_id);
+  DispatchSessionTerminated(sink_id);
+}
+
+void DisplaySourceCustomBindings::OnSessionError(int sink_id,
+                                                 DisplaySourceErrorType type,
+                                                 const std::string& message) {
+  DisplaySourceSession* session = GetDisplaySession(sink_id);
+  CHECK(session);
+  if (session->state() == DisplaySourceSession::Establishing) {
+    // Error has occured before the session has actually started.
+    session_map_.erase(sink_id);
+  }
+
+  DispatchSessionError(sink_id, type, message);
+}
+
+}  // extensions
diff --git a/extensions/renderer/display_source_custom_bindings.h b/extensions/renderer/display_source_custom_bindings.h
new file mode 100644
index 0000000..199f199b
--- /dev/null
+++ b/extensions/renderer/display_source_custom_bindings.h
@@ -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.
+
+#ifndef EXTENSIONS_RENDERER_DISPLAY_SOURCE_CUSTOM_BINDINGS_H_
+#define EXTENSIONS_RENDERER_DISPLAY_SOURCE_CUSTOM_BINDINGS_H_
+
+#include "base/macros.h"
+#include "extensions/common/api/display_source.h"
+#include "extensions/renderer/api/display_source/display_source_session.h"
+#include "extensions/renderer/object_backed_native_handler.h"
+#include "v8/include/v8.h"
+
+namespace extensions {
+class ScriptContext;
+
+// Implements custom bindings for the displaySource API.
+class DisplaySourceCustomBindings : public ObjectBackedNativeHandler {
+ public:
+  explicit DisplaySourceCustomBindings(ScriptContext* context);
+
+  ~DisplaySourceCustomBindings() override;
+
+ private:
+  //  ObjectBackedNativeHandler override.
+  void Invalidate() override;
+
+  void StartSession(
+      const v8::FunctionCallbackInfo<v8::Value>& args);
+  void TerminateSession(
+      const v8::FunctionCallbackInfo<v8::Value>& args);
+
+  void DispatchSessionStarted(int sink_id) const;
+  void DispatchSessionTerminated(int sink_id) const;
+  void DispatchSessionError(int sink_id,
+                            DisplaySourceErrorType type,
+                            const std::string& message) const;
+
+  // DisplaySession callbacks.
+  void OnSessionStarted(int sink_id);
+  void OnSessionTerminated(int sink_id);
+  void OnSessionError(int sink_id,
+                      DisplaySourceErrorType type,
+                      const std::string& message);
+
+  DisplaySourceSession* GetDisplaySession(int sink_id) const;
+
+  std::map<int, scoped_ptr<DisplaySourceSession>> session_map_;
+  base::WeakPtrFactory<DisplaySourceCustomBindings> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(DisplaySourceCustomBindings);
+};
+
+}  // extensions
+
+#endif  // EXTENSIONS_RENDERER_DISPLAY_SOURCE_CUSTOM_BINDINGS_H_
diff --git a/extensions/renderer/guest_view/OWNERS b/extensions/renderer/guest_view/OWNERS
index f63f04f..51bd17210 100644
--- a/extensions/renderer/guest_view/OWNERS
+++ b/extensions/renderer/guest_view/OWNERS
@@ -1,4 +1,5 @@
 fsamuel@chromium.org
 lazyboy@chromium.org
+lfg@chromium.org
 hanxi@chromium.org
 wjmaclean@chromium.org
diff --git a/extensions/renderer/resources/display_source_custom_bindings.js b/extensions/renderer/resources/display_source_custom_bindings.js
new file mode 100644
index 0000000..13e8167
--- /dev/null
+++ b/extensions/renderer/resources/display_source_custom_bindings.js
@@ -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.
+
+// Custom binding for the Display Source API.
+
+var binding = require('binding').Binding.create('displaySource');
+var chrome = requireNative('chrome').GetChrome();
+var lastError = require('lastError');
+var natives = requireNative('display_source');
+
+binding.registerCustomHook(function(bindingsAPI, extensionId) {
+  var apiFunctions = bindingsAPI.apiFunctions;
+  apiFunctions.setHandleRequest('startSession',
+      function(sessionInfo, callback) {
+        try {
+          natives.StartSession(sessionInfo);
+        } catch (e) {
+          lastError.set('displaySource.startSession', e.message, null, chrome);
+        } finally {
+           if (callback !== undefined)
+             callback();
+           lastError.clear(chrome);
+        }
+  });
+  apiFunctions.setHandleRequest('terminateSession',
+      function(sink_id, callback) {
+        try {
+          natives.TerminateSession(sink_id);
+        } catch (e) {
+          lastError.set(
+              'displaySource.terminateSession', e.message, null, chrome);
+        } finally {
+           if (callback !== undefined)
+             callback();
+           lastError.clear(chrome);
+        }
+  });
+});
+
+exports.$set('binding', binding.generate());
diff --git a/extensions/renderer/resources/extensions_renderer_resources.grd b/extensions/renderer/resources/extensions_renderer_resources.grd
index 8a087059..bad8e29 100644
--- a/extensions/renderer/resources/extensions_renderer_resources.grd
+++ b/extensions/renderer/resources/extensions_renderer_resources.grd
@@ -72,6 +72,7 @@
       <include name="IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS" file="context_menus_custom_bindings.js" type="BINDATA" />
       <include name="IDR_CONTEXT_MENUS_HANDLERS_JS" file="context_menus_handlers.js" type="BINDATA" />
       <include name="IDR_DECLARATIVE_WEBREQUEST_CUSTOM_BINDINGS_JS" file="declarative_webrequest_custom_bindings.js" type="BINDATA" />
+      <include name="IDR_DISPLAY_SOURCE_CUSTOM_BINDINGS_JS" file="display_source_custom_bindings.js" type="BINDATA" />
       <include name="IDR_EXTENSION_CUSTOM_BINDINGS_JS" file="extension_custom_bindings.js" type="BINDATA" />
       <include name="IDR_GREASEMONKEY_API_JS" file="greasemonkey_api.js" type="BINDATA" />
       <include name="IDR_I18N_CUSTOM_BINDINGS_JS" file="i18n_custom_bindings.js" type="BINDATA" />
diff --git a/extensions/shell/app/shell_main_delegate.h b/extensions/shell/app/shell_main_delegate.h
index 587de92..4a616df 100644
--- a/extensions/shell/app/shell_main_delegate.h
+++ b/extensions/shell/app/shell_main_delegate.h
@@ -7,6 +7,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
 #include "content/public/app/content_main_delegate.h"
 
 namespace content {
diff --git a/extensions/shell/browser/api/identity/identity_api_unittest.cc b/extensions/shell/browser/api/identity/identity_api_unittest.cc
index 03e6f71..1802fdb 100644
--- a/extensions/shell/browser/api/identity/identity_api_unittest.cc
+++ b/extensions/shell/browser/api/identity/identity_api_unittest.cc
@@ -5,6 +5,7 @@
 #include "extensions/shell/browser/api/identity/identity_api.h"
 
 #include <string>
+#include <utility>
 
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
@@ -65,18 +66,18 @@
     set_extension(
         ExtensionBuilder()
             .SetManifest(
-                 DictionaryBuilder()
-                     .Set("name", "Test")
-                     .Set("version", "1.0")
-                     .Set(
-                         "oauth2",
-                         DictionaryBuilder()
-                             .Set("client_id",
-                                  "123456.apps.googleusercontent.com")
-                             .Set(
-                                 "scopes",
-                                 ListBuilder().Append(
-                                     "https://www.googleapis.com/auth/drive"))))
+                DictionaryBuilder()
+                    .Set("name", "Test")
+                    .Set("version", "1.0")
+                    .Set(
+                        "oauth2",
+                        DictionaryBuilder()
+                            .Set("client_id",
+                                 "123456.apps.googleusercontent.com")
+                            .Set(
+                                "scopes",
+                                std::move(ListBuilder().Append(
+                                    "https://www.googleapis.com/auth/drive")))))
             .SetLocation(Manifest::UNPACKED)
             .Build());
   }
diff --git a/extensions/test/data/api_test/display_source/api/background.js b/extensions/test/data/api_test/display_source/api/background.js
index a54d6b5..a10efe45 100644
--- a/extensions/test/data/api_test/display_source/api/background.js
+++ b/extensions/test/data/api_test/display_source/api/background.js
@@ -34,6 +34,25 @@
   chrome.displaySource.requestAuthentication(1, callback);
 };
 
+var testStartSessionErrorReport = function() {
+  var callback = function() {
+    chrome.test.assertLastError('Invalid stream arguments');
+    chrome.test.succeed();
+  };
+  var session_info = { sinkId: 1, authenticationInfo: { method: "PBC" } };
+  chrome.displaySource.startSession(session_info, callback);
+};
+
+var testTerminateSessionErrorReport = function() {
+  var callback = function() {
+    chrome.test.assertLastError('Session not found');
+    chrome.test.succeed();
+  };
+  chrome.displaySource.terminateSession(1, callback);
+};
+
 chrome.test.runTests([testGetAvailableSinks,
                       testOnSinksUpdated,
-                      testRequestAuthentication]);
+                      testRequestAuthentication,
+                      testStartSessionErrorReport,
+                      testTerminateSessionErrorReport]);
diff --git a/gin/BUILD.gn b/gin/BUILD.gn
index fb16d3a2..4531cd1 100644
--- a/gin/BUILD.gn
+++ b/gin/BUILD.gn
@@ -82,10 +82,10 @@
   ]
   deps = [
     "//base/third_party/dynamic_annotations",
+    "//crypto",
   ]
   if (v8_use_external_startup_data && is_win) {
     public_deps += [ ":gin_v8_snapshot_fingerprint" ]
-    deps += [ "//crypto:crypto" ]
     sources += [ "$target_gen_dir/v8_snapshot_fingerprint.cc" ]
     defines += [ "V8_VERIFY_EXTERNAL_STARTUP_DATA" ]
   }
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_sync_point.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_sync_point.txt
index 1d73261..83948470 100644
--- a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_sync_point.txt
+++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_sync_point.txt
@@ -85,6 +85,20 @@
 
     The command
 
+        void VerifySyncTokensCHROMIUM(GLbyte **sync_tokens, GLsizei count)
+
+    verifies array <sync_tokens> of length <count> and ensures that these
+    sync tokens have all been verified. The generated sync token did not have
+    to be generated from the same context but it must be from a context which
+    flush order guarantee is enough to guarantee order. For example, contexts
+    which live on the same channel may verify sync tokens for one another.
+    If a sync token was generated by GenUnverifiedSyncTokenCHROMIUM and the
+    corresponding context is unable to verify it, an INVALID_OPERATION error
+    is generated. Sync tokens which have already been verified are ignored, if
+    all sync tokens were already verified then nothing will be done.
+
+    The command
+
         void WaitSyncTokenCHROMIUM(const GLbyte *sync_token)
 
     causes the current context to stop submitting commands until the specified
@@ -92,7 +106,7 @@
     <sync_token> is a sync token generated by GenSyncTokenCHROMIUM. If
     <sync_token> was generated by GenUnverifiedSyncTokenCHROMIUM and the
     corresponding fence sync context required more than just flush ordering
-    to guarantee synchronization, a INVALID_OPERATION error is generated. If
+    to guarantee synchronization, an INVALID_OPERATION error is generated. If
     <sync_token> isn't a valid sync token returned by GenSyncTokenCHROMIUM or
     GenUnverifiedSyncTokenCHROMIUM, the result is undefined.
 
@@ -119,8 +133,9 @@
     or queued to be flushed using an ordering barrier.
 
     INVALID_OPERATION is generated if the <sync_token> parameter of
-    WaitSyncTokenCHROMIUM was generated using GenUnverifiedSyncTokenCHROMIUM,
-    but the two contexts must be synchronized with more than just flush order.
+    WaitSyncTokenCHROMIUM or VerifySyncTokensCHROMIUM was generated using
+    GenUnverifiedSyncTokenCHROMIUM, but the two contexts must be synchronized
+    with more than just flush order.
 
 New State
 
@@ -137,3 +152,5 @@
 
     11/24/2015   Clarified that GenUnverifiedSyncTokenCHROMIUM only needs an
     ordering barrier and added proper error values.
+
+    11/25/2015   Added function VerifySyncTokensCHROMIUM.
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index f01a448..153472e7 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -330,6 +330,7 @@
 #define glGenSyncTokenCHROMIUM GLES2_GET_FUN(GenSyncTokenCHROMIUM)
 #define glGenUnverifiedSyncTokenCHROMIUM \
   GLES2_GET_FUN(GenUnverifiedSyncTokenCHROMIUM)
+#define glVerifySyncTokensCHROMIUM GLES2_GET_FUN(VerifySyncTokensCHROMIUM)
 #define glWaitSyncTokenCHROMIUM GLES2_GET_FUN(WaitSyncTokenCHROMIUM)
 #define glDrawBuffersEXT GLES2_GET_FUN(DrawBuffersEXT)
 #define glDiscardBackbufferCHROMIUM GLES2_GET_FUN(DiscardBackbufferCHROMIUM)
diff --git a/gpu/GLES2/gl2extchromium.h b/gpu/GLES2/gl2extchromium.h
index 8118de0..51af9dc 100644
--- a/gpu/GLES2/gl2extchromium.h
+++ b/gpu/GLES2/gl2extchromium.h
@@ -690,12 +690,20 @@
 GL_APICALL GLuint64 GL_APIENTRY glInsertFenceSyncCHROMIUM();
 GL_APICALL void GL_APIENTRY glGenSyncTokenCHROMIUM(GLuint64 fence_sync,
                                                    GLbyte* sync_token);
+GL_APICALL void GL_APIENTRY glGenUnverifiedSyncTokenCHROMIUM(
+    GLuint64 fence_sync, GLbyte* sync_token);
+GL_APICALL void GL_APIENTRY glVerifySyncTokensCHROMIUM(GLbyte **sync_tokens,
+                                                       GLsizei count);
 GL_APICALL void GL_APIENTRY glWaitSyncTokenCHROMIUM(const GLbyte* sync_token);
 #endif
 typedef GLuint (GL_APIENTRYP PFNGLINSERTSYNCPOINTCHROMIUMPROC) ();
 typedef GLuint64 (GL_APIENTRYP PFNGLINSERTFENCESYNCCHROMIUMPROC) ();
 typedef void (GL_APIENTRYP PFNGLGENSYNCTOKENCHROMIUMPROC) (GLuint64 fence_sync,
                                                            GLbyte* sync_token);
+typedef void (GL_APIENTRYP PFNGLGENUNVERIFIEDSYNCTOKENCHROMIUMPROC) (
+    GLuint64 fence_sync, GLbyte* sync_token);
+typedef void (GL_APIENTRYP PFNGLVERIFYSYNCTOKENSCHROMIUMPROC) (
+    GLbyte **sync_tokens, GLsizei count);
 typedef void (GL_APIENTRYP PFNGLWAITSYNCTOKENCHROMIUM) (
     const GLbyte* sync_tokens);
 #endif  /* GL_CHROMIUM_sync_point */
diff --git a/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.cc b/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.cc
index 4f83fa3..04af7ca 100644
--- a/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.cc
+++ b/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.cc
@@ -139,6 +139,9 @@
   real_gl_ = context_->GetImplementation();
   setGLInterface(real_gl_);
 
+  real_gl_->TraceBeginCHROMIUM("WebGraphicsContext3D",
+                               "InProcessContext");
+
   initialized_ = true;
   return true;
 }
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index d1e3531c..671cf726 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -4219,6 +4219,12 @@
     'extension': "CHROMIUM_sync_point",
     'chromium': True,
   },
+  'VerifySyncTokensCHROMIUM' : {
+    'type': 'Custom',
+    'impl_func': False,
+    'extension': "CHROMIUM_sync_point",
+    'chromium': True,
+  },
   'WaitSyncTokenCHROMIUM': {
     'type': 'Custom',
     'impl_func': False,
diff --git a/gpu/command_buffer/client/client_test_helper.h b/gpu/command_buffer/client/client_test_helper.h
index d682346..91ad50a3 100644
--- a/gpu/command_buffer/client/client_test_helper.h
+++ b/gpu/command_buffer/client/client_test_helper.h
@@ -114,6 +114,7 @@
   MOCK_METHOD0(IsGpuChannelLost, bool());
   MOCK_CONST_METHOD0(GetNamespaceID, CommandBufferNamespace());
   MOCK_CONST_METHOD0(GetCommandBufferID, uint64_t());
+  MOCK_CONST_METHOD0(GetExtraCommandBufferData, int32_t());
   MOCK_METHOD0(GenerateFenceSyncRelease, uint64_t());
   MOCK_METHOD1(IsFenceSyncRelease, bool(uint64_t release));
   MOCK_METHOD1(IsFenceSyncFlushed, bool(uint64_t release));
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index 8cb59a9..b8b4bd98 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -1490,6 +1490,10 @@
                                                      GLbyte* sync_token) {
   gles2::GetGLContext()->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token);
 }
+void GL_APIENTRY GLES2VerifySyncTokensCHROMIUM(GLbyte** sync_tokens,
+                                               GLsizei count) {
+  gles2::GetGLContext()->VerifySyncTokensCHROMIUM(sync_tokens, count);
+}
 void GL_APIENTRY GLES2WaitSyncTokenCHROMIUM(const GLbyte* sync_token) {
   gles2::GetGLContext()->WaitSyncTokenCHROMIUM(sync_token);
 }
@@ -2862,6 +2866,10 @@
             glGenUnverifiedSyncTokenCHROMIUM),
     },
     {
+        "glVerifySyncTokensCHROMIUM",
+        reinterpret_cast<GLES2FunctionPointer>(glVerifySyncTokensCHROMIUM),
+    },
+    {
         "glWaitSyncTokenCHROMIUM",
         reinterpret_cast<GLES2FunctionPointer>(glWaitSyncTokenCHROMIUM),
     },
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index b87750a..6d7fcf646 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -2790,6 +2790,16 @@
   }
 }
 
+void VerifySyncTokensCHROMIUMImmediate(GLsizei count) {
+  const uint32_t s = 0;
+  gles2::cmds::VerifySyncTokensCHROMIUMImmediate* c =
+      GetImmediateCmdSpaceTotalSize<
+          gles2::cmds::VerifySyncTokensCHROMIUMImmediate>(s);
+  if (c) {
+    c->Init(count);
+  }
+}
+
 void WaitSyncTokenCHROMIUM(GLint namespace_id,
                            GLuint64 command_buffer_id,
                            GLuint64 release_count) {
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 7c7f99d6..587a5db 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -5552,6 +5552,7 @@
 
   // Copy the data over after setting the data to ensure alignment.
   SyncToken sync_token_data(gpu_control_->GetNamespaceID(),
+                            gpu_control_->GetExtraCommandBufferData(),
                             gpu_control_->GetCommandBufferID(), fence_sync);
   sync_token_data.SetVerifyFlush();
   memcpy(sync_token, &sync_token_data, sizeof(sync_token_data));
@@ -5575,10 +5576,44 @@
 
   // Copy the data over after setting the data to ensure alignment.
   SyncToken sync_token_data(gpu_control_->GetNamespaceID(),
+                            gpu_control_->GetExtraCommandBufferData(),
                             gpu_control_->GetCommandBufferID(), fence_sync);
   memcpy(sync_token, &sync_token_data, sizeof(sync_token_data));
 }
 
+void GLES2Implementation::VerifySyncTokensCHROMIUM(GLbyte **sync_tokens,
+                                                   GLsizei count) {
+  bool sync_tokens_verified = false;
+  for (GLsizei i = 0; i < count; ++i) {
+    if (sync_tokens[i]) {
+      SyncToken sync_token;
+      memcpy(&sync_token, sync_tokens[i], sizeof(sync_token));
+
+      if (!sync_token.verified_flush()) {
+        if (!gpu_control_->CanWaitUnverifiedSyncToken(&sync_token)) {
+          SetGLError(GL_INVALID_VALUE, "glVerifySyncTokensCHROMIUM",
+                     "Cannot verify sync token using this context.");
+          return;
+        }
+        if (!sync_tokens_verified) {
+          // Insert a fence sync here and ensure it is received immediately.
+          // This will require a flush but simplifies things a bit because
+          // unverified sync tokens only need an ordering barrier.
+          const uint64_t release = gpu_control_->GenerateFenceSyncRelease();
+          FlushHelper();
+          const bool verified = gpu_control_->IsFenceSyncFlushReceived(release);
+          DCHECK(verified);
+
+          sync_tokens_verified = true;
+        }
+
+        sync_token.SetVerifyFlush();
+        memcpy(sync_tokens[i], &sync_token, sizeof(sync_token));
+      }
+    }
+  }
+}
+
 void GLES2Implementation::WaitSyncTokenCHROMIUM(const GLbyte* sync_token) {
   if (sync_token) {
     // Copy the data over before data access to ensure alignment.
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 10ebcc3..eb1b63c 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -1035,6 +1035,8 @@
 void GenUnverifiedSyncTokenCHROMIUM(GLuint64 fence_sync,
                                     GLbyte* sync_token) override;
 
+void VerifySyncTokensCHROMIUM(GLbyte** sync_tokens, GLsizei count) override;
+
 void WaitSyncTokenCHROMIUM(const GLbyte* sync_token) override;
 
 void DrawBuffersEXT(GLsizei count, const GLenum* bufs) override;
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index ef2efeb..0d6c03e 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -3782,6 +3782,8 @@
       .WillRepeatedly(testing::Return(kNamespaceId));
   EXPECT_CALL(*gpu_control_, GetCommandBufferID())
       .WillRepeatedly(testing::Return(kCommandBufferId));
+  EXPECT_CALL(*gpu_control_, GetExtraCommandBufferData())
+      .WillRepeatedly(testing::Return(0));
 
   gl_->GenSyncTokenCHROMIUM(kFenceSync, nullptr);
   EXPECT_EQ(GL_INVALID_VALUE, CheckError());
@@ -3825,6 +3827,8 @@
       .WillRepeatedly(testing::Return(kNamespaceId));
   EXPECT_CALL(*gpu_control_, GetCommandBufferID())
       .WillRepeatedly(testing::Return(kCommandBufferId));
+  EXPECT_CALL(*gpu_control_, GetExtraCommandBufferData())
+      .WillRepeatedly(testing::Return(0));
 
   gl_->GenUnverifiedSyncTokenCHROMIUM(kFenceSync, nullptr);
   EXPECT_EQ(GL_INVALID_VALUE, CheckError());
@@ -3858,6 +3862,60 @@
   EXPECT_EQ(kFenceSync, sync_token.release_count());
 }
 
+TEST_F(GLES2ImplementationTest, VerifySyncTokensCHROMIUM) {
+  ExpectedMemoryInfo result =
+      GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+  EXPECT_CALL(*command_buffer(), OnFlush())
+      .WillRepeatedly(SetMemory(result.ptr, GLuint(GL_NO_ERROR)))
+      .RetiresOnSaturation();
+
+  const CommandBufferNamespace kNamespaceId = CommandBufferNamespace::GPU_IO;
+  const GLuint64 kCommandBufferId = 234u;
+  const GLuint64 kFenceSync = 123u;
+  gpu::SyncToken sync_token;
+  GLbyte* sync_token_datas[] = { sync_token.GetData() };
+
+  EXPECT_CALL(*gpu_control_, GetNamespaceID())
+      .WillRepeatedly(testing::Return(kNamespaceId));
+  EXPECT_CALL(*gpu_control_, GetCommandBufferID())
+      .WillRepeatedly(testing::Return(kCommandBufferId));
+  EXPECT_CALL(*gpu_control_, GetExtraCommandBufferData())
+      .WillRepeatedly(testing::Return(0));
+
+  EXPECT_CALL(*gpu_control_, IsFenceSyncRelease(kFenceSync))
+      .WillOnce(testing::Return(true));
+  EXPECT_CALL(*gpu_control_, IsFenceSyncFlushed(kFenceSync))
+      .WillOnce(testing::Return(true));
+  gl_->GenUnverifiedSyncTokenCHROMIUM(kFenceSync, sync_token.GetData());
+  ASSERT_TRUE(sync_token.HasData());
+  ASSERT_FALSE(sync_token.verified_flush());
+
+  ClearCommands();
+  EXPECT_CALL(*gpu_control_, CanWaitUnverifiedSyncToken(_))
+      .WillOnce(testing::Return(false));
+  gl_->VerifySyncTokensCHROMIUM(sync_token_datas, 1);
+  EXPECT_TRUE(NoCommandsWritten());
+  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
+  EXPECT_FALSE(sync_token.verified_flush());
+
+  ClearCommands();
+  const GLuint64 kVerifyFenceSync = 234u;
+  EXPECT_CALL(*gpu_control_, CanWaitUnverifiedSyncToken(_))
+      .WillOnce(testing::Return(true));
+  EXPECT_CALL(*gpu_control_, GenerateFenceSyncRelease())
+      .WillOnce(testing::Return(kVerifyFenceSync));
+  EXPECT_CALL(*gpu_control_, IsFenceSyncFlushReceived(kVerifyFenceSync))
+      .WillOnce(testing::Return(true));
+  gl_->VerifySyncTokensCHROMIUM(sync_token_datas, 1);
+  EXPECT_TRUE(NoCommandsWritten());
+  EXPECT_EQ(GL_NO_ERROR, CheckError());
+
+  EXPECT_EQ(kNamespaceId, sync_token.namespace_id());
+  EXPECT_EQ(kCommandBufferId, sync_token.command_buffer_id());
+  EXPECT_EQ(kFenceSync, sync_token.release_count());
+  EXPECT_TRUE(sync_token.verified_flush());
+}
+
 TEST_F(GLES2ImplementationTest, WaitSyncTokenCHROMIUM) {
   const CommandBufferNamespace kNamespaceId = CommandBufferNamespace::GPU_IO;
   const GLuint64 kCommandBufferId = 234u;
@@ -3872,6 +3930,8 @@
       .WillOnce(testing::Return(kNamespaceId));
   EXPECT_CALL(*gpu_control_, GetCommandBufferID())
       .WillOnce(testing::Return(kCommandBufferId));
+  EXPECT_CALL(*gpu_control_, GetExtraCommandBufferData())
+      .WillOnce(testing::Return(0));
   gl_->GenSyncTokenCHROMIUM(kFenceSync, sync_token);
 
   struct Cmds {
@@ -3899,14 +3959,14 @@
 
   // Invalid sync tokens should produce no error and be a nop.
   ClearCommands();
-  gpu::SyncToken invalid_sync_token(CommandBufferNamespace::INVALID, 0, 0);
+  gpu::SyncToken invalid_sync_token;
   gl_->WaitSyncTokenCHROMIUM(invalid_sync_token.GetConstData());
   EXPECT_TRUE(NoCommandsWritten());
   EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError());
 
   // Unverified sync token should produce INVALID_OPERATION.
   ClearCommands();
-  gpu::SyncToken unverified_sync_token(CommandBufferNamespace::GPU_IO, 0, 0);
+  gpu::SyncToken unverified_sync_token(CommandBufferNamespace::GPU_IO, 0, 0, 0);
   EXPECT_CALL(*gpu_control_, CanWaitUnverifiedSyncToken(_))
       .WillOnce(testing::Return(false));
   gl_->WaitSyncTokenCHROMIUM(unverified_sync_token.GetConstData());
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index 374cb26..382a3717 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -766,6 +766,7 @@
 virtual void GenSyncTokenCHROMIUM(GLuint64 fence_sync, GLbyte* sync_token) = 0;
 virtual void GenUnverifiedSyncTokenCHROMIUM(GLuint64 fence_sync,
                                             GLbyte* sync_token) = 0;
+virtual void VerifySyncTokensCHROMIUM(GLbyte** sync_tokens, GLsizei count) = 0;
 virtual void WaitSyncTokenCHROMIUM(const GLbyte* sync_token) = 0;
 virtual void DrawBuffersEXT(GLsizei count, const GLenum* bufs) = 0;
 virtual void DiscardBackbufferCHROMIUM() = 0;
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index 489afa2..1bfac6a9 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -744,6 +744,7 @@
 void GenSyncTokenCHROMIUM(GLuint64 fence_sync, GLbyte* sync_token) override;
 void GenUnverifiedSyncTokenCHROMIUM(GLuint64 fence_sync,
                                     GLbyte* sync_token) override;
+void VerifySyncTokensCHROMIUM(GLbyte** sync_tokens, GLsizei count) override;
 void WaitSyncTokenCHROMIUM(const GLbyte* sync_token) override;
 void DrawBuffersEXT(GLsizei count, const GLenum* bufs) override;
 void DiscardBackbufferCHROMIUM() override;
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 148f3af..1bf15120 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -1017,6 +1017,8 @@
 void GLES2InterfaceStub::GenUnverifiedSyncTokenCHROMIUM(
     GLuint64 /* fence_sync */,
     GLbyte* /* sync_token */) {}
+void GLES2InterfaceStub::VerifySyncTokensCHROMIUM(GLbyte** /* sync_tokens */,
+                                                  GLsizei /* count */) {}
 void GLES2InterfaceStub::WaitSyncTokenCHROMIUM(const GLbyte* /* sync_token */) {
 }
 void GLES2InterfaceStub::DrawBuffersEXT(GLsizei /* count */,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index 8347572..9206943 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -744,6 +744,7 @@
 void GenSyncTokenCHROMIUM(GLuint64 fence_sync, GLbyte* sync_token) override;
 void GenUnverifiedSyncTokenCHROMIUM(GLuint64 fence_sync,
                                     GLbyte* sync_token) override;
+void VerifySyncTokensCHROMIUM(GLbyte** sync_tokens, GLsizei count) override;
 void WaitSyncTokenCHROMIUM(const GLbyte* sync_token) override;
 void DrawBuffersEXT(GLsizei count, const GLenum* bufs) override;
 void DiscardBackbufferCHROMIUM() override;
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 5f67456d..c8dea68 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -2174,6 +2174,12 @@
   gl_->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token);
 }
 
+void GLES2TraceImplementation::VerifySyncTokensCHROMIUM(GLbyte** sync_tokens,
+                                                        GLsizei count) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::VerifySyncTokensCHROMIUM");
+  gl_->VerifySyncTokensCHROMIUM(sync_tokens, count);
+}
+
 void GLES2TraceImplementation::WaitSyncTokenCHROMIUM(const GLbyte* sync_token) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::WaitSyncTokenCHROMIUM");
   gl_->WaitSyncTokenCHROMIUM(sync_token);
diff --git a/gpu/command_buffer/client/gpu_control.h b/gpu/command_buffer/client/gpu_control.h
index 9ce2db7..9e04d29 100644
--- a/gpu/command_buffer/client/gpu_control.h
+++ b/gpu/command_buffer/client/gpu_control.h
@@ -87,9 +87,13 @@
 
   // The namespace and command buffer ID forms a unique pair for all existing
   // GpuControl (on client) and matches for the corresponding command buffer
-  // (on server) in a single server process.
+  // (on server) in a single server process. The extra command buffer data can
+  // be used for extra identification purposes. One usage is to store some
+  // extra field to identify unverified sync tokens for the implementation of
+  // the CanWaitUnverifiedSyncToken() function.
   virtual CommandBufferNamespace GetNamespaceID() const = 0;
   virtual uint64_t GetCommandBufferID() const = 0;
+  virtual int32_t GetExtraCommandBufferData() const = 0;
 
   // Fence Syncs use release counters at a context level, these fence syncs
   // need to be flushed before they can be shared with other contexts across
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index 8c9baf034..ba5336a 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -309,6 +309,7 @@
 GL_APICALL GLuint64     GL_APIENTRY glInsertFenceSyncCHROMIUM (void);
 GL_APICALL void         GL_APIENTRY glGenSyncTokenCHROMIUM (GLuint64 fence_sync, GLbyte* sync_token);
 GL_APICALL void         GL_APIENTRY glGenUnverifiedSyncTokenCHROMIUM (GLuint64 fence_sync, GLbyte* sync_token);
+GL_APICALL void         GL_APIENTRY glVerifySyncTokensCHROMIUM (GLbyte** sync_tokens, GLsizei count);
 GL_APICALL void         GL_APIENTRY glWaitSyncTokenCHROMIUM (const GLbyte* sync_token);
 GL_APICALL void         GL_APIENTRY glDrawBuffersEXT (GLsizei count, const GLenum* bufs);
 GL_APICALL void         GL_APIENTRY glDiscardBackbufferCHROMIUM (void);
diff --git a/gpu/command_buffer/common/constants.h b/gpu/command_buffer/common/constants.h
index e227739..98c213fa 100644
--- a/gpu/command_buffer/common/constants.h
+++ b/gpu/command_buffer/common/constants.h
@@ -67,7 +67,7 @@
 const size_t kDefaultMaxProgramCacheMemoryBytes = 6 * 1024 * 1024;
 
 // Namespace used to separate various command buffer types.
-enum CommandBufferNamespace {
+enum CommandBufferNamespace : int8_t {
   INVALID = -1,
 
   GPU_IO,
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index ec3a09b..a9aeef0 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -13601,6 +13601,44 @@
     offsetof(GenUnverifiedSyncTokenCHROMIUMImmediate, fence_sync) == 4,
     "offset of GenUnverifiedSyncTokenCHROMIUMImmediate fence_sync should be 4");
 
+struct VerifySyncTokensCHROMIUMImmediate {
+  typedef VerifySyncTokensCHROMIUMImmediate ValueType;
+  static const CommandId kCmdId = kVerifySyncTokensCHROMIUMImmediate;
+  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize(uint32_t size_in_bytes) {
+    return static_cast<uint32_t>(sizeof(ValueType) +  // NOLINT
+                                 RoundSizeToMultipleOfEntries(size_in_bytes));
+  }
+
+  void SetHeader(uint32_t size_in_bytes) {
+    header.SetCmdByTotalSize<ValueType>(size_in_bytes);
+  }
+
+  void Init(GLsizei _count) {
+    uint32_t total_size = 0;  // WARNING: compute correct size.
+    SetHeader(total_size);
+    count = _count;
+  }
+
+  void* Set(void* cmd, GLsizei _count) {
+    uint32_t total_size = 0;  // WARNING: compute correct size.
+    static_cast<ValueType*>(cmd)->Init(_count);
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, total_size);
+  }
+
+  gpu::CommandHeader header;
+  int32_t count;
+};
+
+static_assert(sizeof(VerifySyncTokensCHROMIUMImmediate) == 8,
+              "size of VerifySyncTokensCHROMIUMImmediate should be 8");
+static_assert(offsetof(VerifySyncTokensCHROMIUMImmediate, header) == 0,
+              "offset of VerifySyncTokensCHROMIUMImmediate header should be 0");
+static_assert(offsetof(VerifySyncTokensCHROMIUMImmediate, count) == 4,
+              "offset of VerifySyncTokensCHROMIUMImmediate count should be 4");
+
 struct WaitSyncTokenCHROMIUM {
   typedef WaitSyncTokenCHROMIUM ValueType;
   static const CommandId kCmdId = kWaitSyncTokenCHROMIUM;
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
index 38dad791..b8f19a57 100644
--- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -299,42 +299,43 @@
   OP(InsertFenceSyncCHROMIUM)                     /* 540 */ \
   OP(GenSyncTokenCHROMIUMImmediate)               /* 541 */ \
   OP(GenUnverifiedSyncTokenCHROMIUMImmediate)     /* 542 */ \
-  OP(WaitSyncTokenCHROMIUM)                       /* 543 */ \
-  OP(DrawBuffersEXTImmediate)                     /* 544 */ \
-  OP(DiscardBackbufferCHROMIUM)                   /* 545 */ \
-  OP(ScheduleOverlayPlaneCHROMIUM)                /* 546 */ \
-  OP(ScheduleCALayerCHROMIUM)                     /* 547 */ \
-  OP(CommitOverlayPlanesCHROMIUM)                 /* 548 */ \
-  OP(SwapInterval)                                /* 549 */ \
-  OP(FlushDriverCachesCHROMIUM)                   /* 550 */ \
-  OP(MatrixLoadfCHROMIUMImmediate)                /* 551 */ \
-  OP(MatrixLoadIdentityCHROMIUM)                  /* 552 */ \
-  OP(GenPathsCHROMIUM)                            /* 553 */ \
-  OP(DeletePathsCHROMIUM)                         /* 554 */ \
-  OP(IsPathCHROMIUM)                              /* 555 */ \
-  OP(PathCommandsCHROMIUM)                        /* 556 */ \
-  OP(PathParameterfCHROMIUM)                      /* 557 */ \
-  OP(PathParameteriCHROMIUM)                      /* 558 */ \
-  OP(PathStencilFuncCHROMIUM)                     /* 559 */ \
-  OP(StencilFillPathCHROMIUM)                     /* 560 */ \
-  OP(StencilStrokePathCHROMIUM)                   /* 561 */ \
-  OP(CoverFillPathCHROMIUM)                       /* 562 */ \
-  OP(CoverStrokePathCHROMIUM)                     /* 563 */ \
-  OP(StencilThenCoverFillPathCHROMIUM)            /* 564 */ \
-  OP(StencilThenCoverStrokePathCHROMIUM)          /* 565 */ \
-  OP(StencilFillPathInstancedCHROMIUM)            /* 566 */ \
-  OP(StencilStrokePathInstancedCHROMIUM)          /* 567 */ \
-  OP(CoverFillPathInstancedCHROMIUM)              /* 568 */ \
-  OP(CoverStrokePathInstancedCHROMIUM)            /* 569 */ \
-  OP(StencilThenCoverFillPathInstancedCHROMIUM)   /* 570 */ \
-  OP(StencilThenCoverStrokePathInstancedCHROMIUM) /* 571 */ \
-  OP(BindFragmentInputLocationCHROMIUMBucket)     /* 572 */ \
-  OP(ProgramPathFragmentInputGenCHROMIUM)         /* 573 */ \
-  OP(BlendBarrierKHR)                             /* 574 */ \
-  OP(ApplyScreenSpaceAntialiasingCHROMIUM)        /* 575 */ \
-  OP(BindFragDataLocationIndexedEXTBucket)        /* 576 */ \
-  OP(BindFragDataLocationEXTBucket)               /* 577 */ \
-  OP(GetFragDataIndexEXT)                         /* 578 */
+  OP(VerifySyncTokensCHROMIUMImmediate)           /* 543 */ \
+  OP(WaitSyncTokenCHROMIUM)                       /* 544 */ \
+  OP(DrawBuffersEXTImmediate)                     /* 545 */ \
+  OP(DiscardBackbufferCHROMIUM)                   /* 546 */ \
+  OP(ScheduleOverlayPlaneCHROMIUM)                /* 547 */ \
+  OP(ScheduleCALayerCHROMIUM)                     /* 548 */ \
+  OP(CommitOverlayPlanesCHROMIUM)                 /* 549 */ \
+  OP(SwapInterval)                                /* 550 */ \
+  OP(FlushDriverCachesCHROMIUM)                   /* 551 */ \
+  OP(MatrixLoadfCHROMIUMImmediate)                /* 552 */ \
+  OP(MatrixLoadIdentityCHROMIUM)                  /* 553 */ \
+  OP(GenPathsCHROMIUM)                            /* 554 */ \
+  OP(DeletePathsCHROMIUM)                         /* 555 */ \
+  OP(IsPathCHROMIUM)                              /* 556 */ \
+  OP(PathCommandsCHROMIUM)                        /* 557 */ \
+  OP(PathParameterfCHROMIUM)                      /* 558 */ \
+  OP(PathParameteriCHROMIUM)                      /* 559 */ \
+  OP(PathStencilFuncCHROMIUM)                     /* 560 */ \
+  OP(StencilFillPathCHROMIUM)                     /* 561 */ \
+  OP(StencilStrokePathCHROMIUM)                   /* 562 */ \
+  OP(CoverFillPathCHROMIUM)                       /* 563 */ \
+  OP(CoverStrokePathCHROMIUM)                     /* 564 */ \
+  OP(StencilThenCoverFillPathCHROMIUM)            /* 565 */ \
+  OP(StencilThenCoverStrokePathCHROMIUM)          /* 566 */ \
+  OP(StencilFillPathInstancedCHROMIUM)            /* 567 */ \
+  OP(StencilStrokePathInstancedCHROMIUM)          /* 568 */ \
+  OP(CoverFillPathInstancedCHROMIUM)              /* 569 */ \
+  OP(CoverStrokePathInstancedCHROMIUM)            /* 570 */ \
+  OP(StencilThenCoverFillPathInstancedCHROMIUM)   /* 571 */ \
+  OP(StencilThenCoverStrokePathInstancedCHROMIUM) /* 572 */ \
+  OP(BindFragmentInputLocationCHROMIUMBucket)     /* 573 */ \
+  OP(ProgramPathFragmentInputGenCHROMIUM)         /* 574 */ \
+  OP(BlendBarrierKHR)                             /* 575 */ \
+  OP(ApplyScreenSpaceAntialiasingCHROMIUM)        /* 576 */ \
+  OP(BindFragDataLocationIndexedEXTBucket)        /* 577 */ \
+  OP(BindFragDataLocationEXTBucket)               /* 578 */ \
+  OP(GetFragDataIndexEXT)                         /* 579 */
 
 enum CommandId {
   kStartPoint = cmd::kLastCommonId,  // All GLES2 commands start after this.
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc
index 8b547fa..5367f4d1 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.cc
+++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -509,70 +509,159 @@
   return  bytes_per_element * elements_per_group;
 }
 
-bool GLES2Util::ComputeImagePaddedRowSize(
-        int width, int format, int type, int unpack_alignment,
-        uint32* padded_row_size) {
-  DCHECK(unpack_alignment == 1 || unpack_alignment == 2 ||
-         unpack_alignment == 4 || unpack_alignment == 8);
-  uint32 bytes_per_group = ComputeImageGroupSize(format, type);
+bool GLES2Util::ComputeImageRowSizeHelper(
+    int width, uint32 bytes_per_group, int alignment,
+    uint32* rt_unpadded_row_size, uint32* rt_padded_row_size) {
+  DCHECK(alignment == 1 || alignment == 2 ||
+         alignment == 4 || alignment == 8);
   uint32 unpadded_row_size;
   if (!SafeMultiplyUint32(width, bytes_per_group, &unpadded_row_size)) {
     return false;
   }
   uint32 temp;
-  if (!SafeAddUint32(unpadded_row_size, unpack_alignment - 1, &temp)) {
-      return false;
+  if (!SafeAddUint32(unpadded_row_size, alignment - 1, &temp)) {
+    return false;
   }
-  *padded_row_size = (temp / unpack_alignment) * unpack_alignment;
+  uint32 padded_row_size = (temp / alignment) * alignment;
+  if (rt_unpadded_row_size)
+    *rt_unpadded_row_size = unpadded_row_size;
+  if (rt_padded_row_size)
+    *rt_padded_row_size = padded_row_size;
   return true;
 }
 
+bool GLES2Util::ComputeImagePaddedRowSize(
+    int width, int format, int type, int alignment, uint32* padded_row_size) {
+  uint32 bytes_per_group = ComputeImageGroupSize(format, type);
+  return ComputeImageRowSizeHelper(
+      width, bytes_per_group, alignment, nullptr, padded_row_size);
+}
+
 // Returns the amount of data glTexImage*D or glTexSubImage*D will access.
 bool GLES2Util::ComputeImageDataSizes(
     int width, int height, int depth, int format, int type,
-    int unpack_alignment, uint32* size, uint32* ret_unpadded_row_size,
-    uint32* ret_padded_row_size) {
-  DCHECK(unpack_alignment == 1 || unpack_alignment == 2 ||
-         unpack_alignment == 4 || unpack_alignment == 8);
+    int alignment, uint32* size, uint32* opt_unpadded_row_size,
+    uint32* opt_padded_row_size) {
+  DCHECK(width >= 0 && height >= 0 && height >=0);
+  if (width == 0 || height == 0 || depth == 0) {
+    *size = 0;
+    return true;
+  }
+
   uint32 bytes_per_group = ComputeImageGroupSize(format, type);
-  uint32 row_size;
-  if (!SafeMultiplyUint32(width, bytes_per_group, &row_size)) {
+
+  uint32 unpadded_row_size;
+  uint32 padded_row_size;
+  if (!ComputeImageRowSizeHelper(width, bytes_per_group, alignment,
+                                 &unpadded_row_size, &padded_row_size)) {
     return false;
   }
   uint32 num_of_rows;
   if (!SafeMultiplyUint32(height, depth, &num_of_rows)) {
     return false;
   }
-  if (num_of_rows > 1) {
-    uint32 temp;
-    if (!SafeAddUint32(row_size, unpack_alignment - 1, &temp)) {
-      return false;
-    }
-    uint32 padded_row_size = (temp / unpack_alignment) * unpack_alignment;
-    uint32 size_of_all_but_last_row;
-    if (!SafeMultiplyUint32((num_of_rows - 1), padded_row_size,
-                            &size_of_all_but_last_row)) {
-      return false;
-    }
-    if (!SafeAddUint32(size_of_all_but_last_row, row_size, size)) {
-      return false;
-    }
-    if (ret_padded_row_size) {
-      *ret_padded_row_size = padded_row_size;
-    }
-  } else {
-    *size = row_size;
-    if (ret_padded_row_size) {
-      *ret_padded_row_size = row_size;
-    }
+  DCHECK(num_of_rows > 0);
+  uint32 size_of_all_but_last_row;
+  if (!SafeMultiplyUint32((num_of_rows - 1), padded_row_size,
+                          &size_of_all_but_last_row)) {
+    return false;
   }
-  if (ret_unpadded_row_size) {
-    *ret_unpadded_row_size = row_size;
+  if (!SafeAddUint32(size_of_all_but_last_row, unpadded_row_size, size)) {
+    return false;
+  }
+  if (opt_padded_row_size) {
+    if (num_of_rows > 1)
+      *opt_padded_row_size = padded_row_size;
+    else
+      *opt_padded_row_size = unpadded_row_size;
+  }
+  if (opt_unpadded_row_size) {
+    *opt_unpadded_row_size = unpadded_row_size;
   }
 
   return true;
 }
 
+bool GLES2Util::ComputeImageDataSizesES3(
+    int width, int height, int depth, int format, int type,
+    const PixelStoreParams& params,
+    uint32_t* size, uint32_t* opt_unpadded_row_size,
+    uint32_t* opt_padded_row_size, uint32_t* opt_skip_size) {
+  DCHECK(width >= 0 && height >= 0 && height >=0);
+  if (width == 0 || height == 0 || depth == 0) {
+    *size = 0;
+    return true;
+  }
+
+  uint32 bytes_per_group = ComputeImageGroupSize(format, type);
+
+  uint32 unpadded_row_size;
+  uint32 padded_row_size;
+  if (!ComputeImageRowSizeHelper(width, bytes_per_group, params.alignment,
+                                 &unpadded_row_size, &padded_row_size)) {
+    return false;
+  }
+  if (params.row_length > 0 &&
+      !ComputeImageRowSizeHelper(params.row_length, bytes_per_group,
+                                 params.alignment, nullptr, &padded_row_size)) {
+    // Here we re-compute the padded_row_size, but the unpadded_row_size
+    // isn't affected. That is, the last row isn't affected by ROW_LENGTH.
+    return false;
+  }
+
+  int image_height = params.image_height > 0 ? params.image_height : height;
+  uint32 num_of_rows;
+  if (!SafeMultiplyUint32(image_height, depth - 1, &num_of_rows) ||
+      !SafeAddUint32(num_of_rows, height, &num_of_rows)) {
+    return false;
+  }
+  DCHECK(num_of_rows > 0);
+  uint32 size_of_all_but_last_row;
+  if (!SafeMultiplyUint32((num_of_rows - 1), padded_row_size,
+                          &size_of_all_but_last_row)) {
+    return false;
+  }
+  if (!SafeAddUint32(size_of_all_but_last_row, unpadded_row_size, size)) {
+    return false;
+  }
+
+  uint32 skip_size = 0;
+  if (params.skip_images > 0) {
+    uint32 image_size;
+    if (!SafeMultiplyUint32(image_height, padded_row_size, &image_size))
+      return false;
+    if (!SafeMultiplyUint32(image_size, params.skip_images, &skip_size))
+      return false;
+  }
+  if (params.skip_rows > 0) {
+    uint32 temp;
+    if (!SafeMultiplyUint32(padded_row_size, params.skip_rows, &temp))
+      return false;
+    if (!SafeAddUint32(skip_size, temp, &skip_size))
+      return false;
+  }
+  if (params.skip_pixels > 0) {
+    uint32 temp;
+    if (!SafeMultiplyUint32(bytes_per_group, params.skip_pixels, &temp))
+      return false;
+    if (!SafeAddUint32(skip_size, temp, &skip_size))
+      return false;
+  }
+  uint32 total_size;
+  if (!SafeAddUint32(*size, skip_size, &total_size))
+    return false;
+
+  if (opt_padded_row_size) {
+    *opt_padded_row_size = padded_row_size;
+  }
+  if (opt_unpadded_row_size) {
+    *opt_unpadded_row_size = unpadded_row_size;
+  }
+  if (opt_skip_size)
+    *opt_skip_size = skip_size;
+  return true;
+}
+
 size_t GLES2Util::RenderbufferBytesPerPixel(int format) {
   switch (format) {
     case GL_STENCIL_INDEX8:
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.h b/gpu/command_buffer/common/gles2_cmd_utils.h
index 3aa0299..e3b82b8 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils.h
@@ -52,6 +52,24 @@
   return checked.IsValid();
 }
 
+struct GLES2_UTILS_EXPORT PixelStoreParams {
+  PixelStoreParams()
+      : alignment(4),
+        row_length(0),
+        image_height(0),
+        skip_pixels(0),
+        skip_rows(0),
+        skip_images(0) {
+  }
+
+  int32_t alignment;
+  int32_t row_length;
+  int32_t image_height;
+  int32_t skip_pixels;
+  int32_t skip_rows;
+  int32_t skip_images;
+};
+
 // Utilties for GLES2 support.
 class GLES2_UTILS_EXPORT GLES2Util {
  public:
@@ -105,17 +123,26 @@
 
   // Computes the size of an image row including alignment padding
   static bool ComputeImagePaddedRowSize(
-      int width, int format, int type, int unpack_alignment,
+      int width, int format, int type, int alignment,
       uint32_t* padded_row_size);
 
   // Computes the size of image data for TexImage2D and TexSubImage2D.
-  // Optionally the unpadded and padded row sizes can be returned. If height < 2
-  // then the padded_row_size will be the same as the unpadded_row_size since
-  // padding is not necessary.
+  // Optionally the unpadded and padded row sizes can be returned.
   static bool ComputeImageDataSizes(
       int width, int height, int depth, int format, int type,
-      int unpack_alignment, uint32_t* size, uint32_t* unpadded_row_size,
-      uint32_t* padded_row_size);
+      int alignment, uint32_t* size, uint32_t* opt_unpadded_row_size,
+      uint32_t* opt_padded_row_size);
+
+  // Similar to the above function, but taking into consideration all ES3
+  // pixel pack/unpack parameters.
+  // Optionally the skipped bytes in the beginning can be returned.
+  // Note the returned |size| does NOT include |skip_size|.
+  // TODO(zmo): merging ComputeImageDataSize and ComputeImageDataSizeES3.
+  static bool ComputeImageDataSizesES3(
+      int width, int height, int depth, int format, int type,
+      const PixelStoreParams& params,
+      uint32_t* size, uint32_t* opt_unpadded_row_size,
+      uint32_t* opt_padded_row_size, uint32_t* opt_skip_size);
 
   static size_t RenderbufferBytesPerPixel(int format);
 
@@ -192,6 +219,10 @@
   static std::string GetQualifiedEnumString(
       const EnumToString* table, size_t count, uint32_t value);
 
+  static bool ComputeImageRowSizeHelper(
+      int width, uint32 bytes_per_group, int alignment,
+      uint32* rt_unpadded_row_size, uint32* rt_padded_row_size);
+
   static const EnumToString* const enum_to_string_table_;
   static const size_t enum_to_string_table_len_;
 
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_unittest.cc b/gpu/command_buffer/common/gles2_cmd_utils_unittest.cc
index 3eb2a38..a435f28a 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_unittest.cc
+++ b/gpu/command_buffer/common/gles2_cmd_utils_unittest.cc
@@ -320,6 +320,123 @@
   EXPECT_EQ(kWidth * 3 + 7, padded_row_size);
 }
 
+TEST_F(GLES2UtilTest, ComputeImageDataSizePixelStoreParams) {
+  const uint32_t kWidth = 3;
+  const uint32_t kHeight = 3;
+  const uint32_t kDepth = 3;
+  uint32_t size;
+  uint32_t unpadded_row_size;
+  uint32_t padded_row_size;
+  uint32_t skip_size;
+
+  {  // Default
+    PixelStoreParams params;
+    EXPECT_TRUE(GLES2Util::ComputeImageDataSizesES3(
+        kWidth, kHeight, kDepth, GL_RGB, GL_UNSIGNED_BYTE, params,
+        &size, &unpadded_row_size, &padded_row_size, &skip_size));
+    EXPECT_EQ(kWidth * 3, unpadded_row_size);
+    EXPECT_EQ(kWidth * 3 + 3, padded_row_size);
+    EXPECT_EQ(padded_row_size * (kHeight * kDepth - 1) + unpadded_row_size,
+              size);
+    EXPECT_EQ(0u, skip_size);
+  }
+
+  {  // row_length > width
+    PixelStoreParams params;
+    params.row_length = kWidth + 2;
+    uint32_t kPadding = 1;  // 5 * 3 = 15 -> 16
+    EXPECT_TRUE(GLES2Util::ComputeImageDataSizesES3(
+        kWidth, kHeight, kDepth, GL_RGB, GL_UNSIGNED_BYTE, params,
+        &size, &unpadded_row_size, &padded_row_size, &skip_size));
+    EXPECT_EQ(static_cast<uint32_t>(kWidth * 3), unpadded_row_size);
+    EXPECT_EQ(static_cast<uint32_t>(params.row_length * 3 + kPadding),
+              padded_row_size);
+    EXPECT_EQ(padded_row_size * (kHeight * kDepth - 1) + unpadded_row_size,
+              size);
+    EXPECT_EQ(0u, skip_size);
+  }
+
+  {  // row_length < width
+    PixelStoreParams params;
+    params.row_length = kWidth - 1;
+    uint32_t kPadding = 2;  // 2 * 3 = 6 -> 8
+    EXPECT_TRUE(GLES2Util::ComputeImageDataSizesES3(
+        kWidth, kHeight, kDepth, GL_RGB, GL_UNSIGNED_BYTE, params,
+        &size, &unpadded_row_size, &padded_row_size, &skip_size));
+    EXPECT_EQ(static_cast<uint32_t>(kWidth * 3), unpadded_row_size);
+    EXPECT_EQ(static_cast<uint32_t>(params.row_length * 3 + kPadding),
+              padded_row_size);
+    EXPECT_EQ(padded_row_size * (kHeight * kDepth - 1) + unpadded_row_size,
+              size);
+    EXPECT_EQ(0u, skip_size);
+  }
+
+  {  // image_height > height
+    PixelStoreParams params;
+    params.image_height = kHeight + 1;
+    uint32_t kPadding = 3; // 3 * 3 = 9 -> 21
+    EXPECT_TRUE(GLES2Util::ComputeImageDataSizesES3(
+        kWidth, kHeight, kDepth, GL_RGB, GL_UNSIGNED_BYTE, params,
+        &size, &unpadded_row_size, &padded_row_size, &skip_size));
+    EXPECT_EQ(kWidth * 3, unpadded_row_size);
+    EXPECT_EQ(kWidth * 3 + kPadding, padded_row_size);
+    EXPECT_EQ((params.image_height * (kDepth - 1) + kHeight - 1) *
+              padded_row_size + unpadded_row_size, size);
+    EXPECT_EQ(0u, skip_size);
+  }
+
+  {  // image_height < height
+    PixelStoreParams params;
+    params.image_height = kHeight - 1;
+    uint32_t kPadding = 3; // 3 * 3 = 9 -> 12
+    EXPECT_TRUE(GLES2Util::ComputeImageDataSizesES3(
+        kWidth, kHeight, kDepth, GL_RGB, GL_UNSIGNED_BYTE, params,
+        &size, &unpadded_row_size, &padded_row_size, &skip_size));
+    EXPECT_EQ(kWidth * 3, unpadded_row_size);
+    EXPECT_EQ(kWidth * 3 + kPadding, padded_row_size);
+    EXPECT_EQ((params.image_height * (kDepth - 1) + kHeight - 1) *
+              padded_row_size + unpadded_row_size, size);
+    EXPECT_EQ(0u, skip_size);
+  }
+
+  {  // skip_pixels, skip_rows, skip_images, alignment = 4, RGB
+    PixelStoreParams params;
+    params.skip_pixels = 1;
+    params.skip_rows = 10;
+    params.skip_images = 2;
+    uint32_t kPadding = 3; // 3 * 3 = 9 -> 12
+    EXPECT_TRUE(GLES2Util::ComputeImageDataSizesES3(
+        kWidth, kHeight, kDepth, GL_RGB, GL_UNSIGNED_BYTE, params,
+        &size, &unpadded_row_size, &padded_row_size, &skip_size));
+    EXPECT_EQ(kWidth * 3, unpadded_row_size);
+    EXPECT_EQ(kWidth * 3 + kPadding, padded_row_size);
+    EXPECT_EQ(padded_row_size * kHeight * params.skip_images +
+              padded_row_size * params.skip_rows + 3 * params.skip_pixels,
+              skip_size);
+    EXPECT_EQ(padded_row_size * (kWidth * kDepth - 1) + unpadded_row_size,
+              size);
+  }
+
+  {  // skip_pixels, skip_rows, skip_images, alignment = 8, RGBA
+    PixelStoreParams params;
+    params.skip_pixels = 1;
+    params.skip_rows = 10;
+    params.skip_images = 2;
+    params.alignment = 8;
+    uint32_t kPadding = 4; // 3 * 4 = 12 -> 16
+    EXPECT_TRUE(GLES2Util::ComputeImageDataSizesES3(
+        kWidth, kHeight, kDepth, GL_RGBA, GL_UNSIGNED_BYTE, params,
+        &size, &unpadded_row_size, &padded_row_size, &skip_size));
+    EXPECT_EQ(kWidth * 4, unpadded_row_size);
+    EXPECT_EQ(kWidth * 4 + kPadding, padded_row_size);
+    EXPECT_EQ(padded_row_size * kHeight * params.skip_images +
+              padded_row_size * params.skip_rows + 4 * params.skip_pixels,
+              skip_size);
+    EXPECT_EQ(padded_row_size * (kWidth * kDepth - 1) + unpadded_row_size,
+              size);
+  }
+}
+
 TEST_F(GLES2UtilTest, RenderbufferBytesPerPixel) {
    EXPECT_EQ(1u, GLES2Util::RenderbufferBytesPerPixel(GL_STENCIL_INDEX8));
    EXPECT_EQ(2u, GLES2Util::RenderbufferBytesPerPixel(GL_RGBA4));
diff --git a/gpu/command_buffer/common/sync_token.h b/gpu/command_buffer/common/sync_token.h
index 11af396..14f7256 100644
--- a/gpu/command_buffer/common/sync_token.h
+++ b/gpu/command_buffer/common/sync_token.h
@@ -26,6 +26,7 @@
   SyncToken()
       : verified_flush_(false),
         namespace_id_(CommandBufferNamespace::INVALID),
+        extra_data_field_(0),
         command_buffer_id_(0),
         release_count_(0) {}
 
@@ -36,21 +37,26 @@
       : verified_flush_(sync_point ? true : false),
         namespace_id_(sync_point ? gpu::CommandBufferNamespace::OLD_SYNC_POINTS
                                  : gpu::CommandBufferNamespace::INVALID),
+        extra_data_field_(0),
         command_buffer_id_(0),
         release_count_(sync_point) {}
 
   SyncToken(CommandBufferNamespace namespace_id,
+            int32_t extra_data_field,
             uint64_t command_buffer_id,
             uint64_t release_count)
       : verified_flush_(false),
         namespace_id_(namespace_id),
+        extra_data_field_(extra_data_field),
         command_buffer_id_(command_buffer_id),
         release_count_(release_count) {}
 
   void Set(CommandBufferNamespace namespace_id,
+           int32_t extra_data_field,
            uint64_t command_buffer_id,
            uint64_t release_count) {
     namespace_id_ = namespace_id;
+    extra_data_field_ = extra_data_field;
     command_buffer_id_ = command_buffer_id;
     release_count_ = release_count;
   }
@@ -58,6 +64,7 @@
   void Clear() {
     verified_flush_ = false;
     namespace_id_ = CommandBufferNamespace::INVALID;
+    extra_data_field_ = 0;
     command_buffer_id_ = 0;
     release_count_ = 0;
   }
@@ -81,6 +88,12 @@
   uint64_t command_buffer_id() const { return command_buffer_id_; }
   uint64_t release_count() const { return release_count_; }
 
+  // This extra data field can be used by command buffers to add extra
+  // information to identify unverified sync tokens. The current purpose
+  // of this field is only for unverified sync tokens which only exist within
+  // the same process so this information will not survive cross-process IPCs.
+  int32_t extra_data_field() const { return extra_data_field_; }
+
   bool operator<(const SyncToken& other) const {
     // TODO(dyen): Once all our compilers support c++11, we can replace this
     // long list of comparisons with std::tie().
@@ -94,6 +107,7 @@
   bool operator==(const SyncToken& other) const {
     return verified_flush_ == other.verified_flush() &&
            namespace_id_ == other.namespace_id() &&
+           extra_data_field_ == other.extra_data_field() &&
            command_buffer_id_ == other.command_buffer_id() &&
            release_count_ == other.release_count();
   }
@@ -103,6 +117,7 @@
  private:
   bool verified_flush_;
   CommandBufferNamespace namespace_id_;
+  int32_t extra_data_field_;
   uint64_t command_buffer_id_;
   uint64_t release_count_;
 };
diff --git a/gpu/command_buffer/service/context_state.cc b/gpu/command_buffer/service/context_state.cc
index b93a372..4cbf2941 100644
--- a/gpu/command_buffer/service/context_state.cc
+++ b/gpu/command_buffer/service/context_state.cc
@@ -594,6 +594,28 @@
   }
 }
 
+PixelStoreParams ContextState::GetPackParams() {
+  PixelStoreParams params;
+  params.alignment = pack_alignment;
+  params.row_length = pack_row_length;
+  params.skip_pixels = pack_skip_pixels;
+  params.skip_rows = pack_skip_rows;
+  return params;
+}
+
+PixelStoreParams ContextState::GetUnpackParams(Dimension dimension) {
+  PixelStoreParams params;
+  params.alignment = unpack_alignment;
+  params.row_length = unpack_row_length;
+  params.skip_pixels = unpack_skip_pixels;
+  params.skip_rows = unpack_skip_rows;
+  if (dimension == k3D) {
+    params.image_height = unpack_image_height;
+    params.skip_images = unpack_skip_images;
+  }
+  return params;
+}
+
 // Include the auto-generated part of this file. We split this because it means
 // we can easily edit the non-auto generated parts right here in this file
 // instead of having to edit some template or the code generator.
diff --git a/gpu/command_buffer/service/context_state.h b/gpu/command_buffer/service/context_state.h
index 5f154c2..e1fa4a4 100644
--- a/gpu/command_buffer/service/context_state.h
+++ b/gpu/command_buffer/service/context_state.h
@@ -138,6 +138,11 @@
 GPU_EXPORT void Vec4::SetValues<GLuint>(const GLuint* values);
 
 struct GPU_EXPORT ContextState {
+  enum Dimension {
+    k2D,
+    k3D
+  };
+
   ContextState(FeatureInfo* feature_info,
                ErrorStateClient* error_state_client,
                Logger* logger);
@@ -220,6 +225,9 @@
   void UnbindTexture(TextureRef* texture);
   void UnbindSampler(Sampler* sampler);
 
+  PixelStoreParams GetPackParams();
+  PixelStoreParams GetUnpackParams(Dimension dimension);
+
   #include "gpu/command_buffer/service/context_state_autogen.h"
 
   EnableFlags enable_flags;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index d1235e10..e8bbe588 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -12578,6 +12578,12 @@
   return error::kUnknownCommand;
 }
 
+error::Error GLES2DecoderImpl::HandleVerifySyncTokensCHROMIUMImmediate(
+    uint32 immediate_data_size,
+    const void* cmd_data) {
+  return error::kUnknownCommand;
+}
+
 error::Error GLES2DecoderImpl::HandleWaitSyncTokenCHROMIUM(
     uint32 immediate_data_size,
     const void* cmd_data) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
index e8b9eb6..5cda2e1 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
@@ -394,12 +394,4 @@
            kInvalidSharedMemoryOffset);
   EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
 }
-
-TEST_P(GLES2DecoderTest3, SwapIntervalValidArgs) {
-  SpecializedSetup<cmds::SwapInterval, 0>(true);
-  cmds::SwapInterval cmd;
-  cmd.Init(1);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-}
 #endif  // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_4_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_4_autogen.h
index 9abba52..166ced9 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_4_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_4_autogen.h
@@ -12,4 +12,11 @@
 #ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_4_AUTOGEN_H_
 #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_4_AUTOGEN_H_
 
+TEST_P(GLES2DecoderTest4, SwapIntervalValidArgs) {
+  SpecializedSetup<cmds::SwapInterval, 0>(true);
+  cmds::SwapInterval cmd;
+  cmd.Init(1);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
 #endif  // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_4_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/in_process_command_buffer.cc b/gpu/command_buffer/service/in_process_command_buffer.cc
index 4931e30..12b0d15 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.cc
+++ b/gpu/command_buffer/service/in_process_command_buffer.cc
@@ -706,7 +706,8 @@
 
   if (fence_sync) {
     flushed_fence_sync_release_ = fence_sync;
-    SyncToken sync_token(GetNamespaceID(), GetCommandBufferID(), fence_sync);
+    SyncToken sync_token(GetNamespaceID(), GetExtraCommandBufferData(),
+                         GetCommandBufferID(), fence_sync);
     sync_token.SetVerifyFlush();
     gpu_memory_buffer_manager_->SetDestructionSyncToken(gpu_memory_buffer,
                                                         sync_token);
@@ -852,7 +853,8 @@
       // We can simply use the GPUIO namespace with 0 for the command buffer ID
       // (under normal circumstances 0 is  invalid so  will not be used) until
       // the old sync points are replaced.
-      SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0, sync_point);
+      SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0, 0,
+                           sync_point);
       mailbox_manager->PushTextureUpdates(sync_token);
     }
   }
@@ -873,7 +875,7 @@
   // We can simply use the GPUIO namespace with 0 for the command buffer ID
   // (under normal circumstances 0 is  invalid so  will not be used) until
   // the old sync points are replaced.
-  SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0, sync_point);
+  SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0, 0, sync_point);
   mailbox_manager->PullTextureUpdates(sync_token);
   return true;
 }
@@ -889,7 +891,8 @@
       make_current_success = MakeCurrent();
     }
     if (make_current_success) {
-      SyncToken sync_token(GetNamespaceID(), GetCommandBufferID(), release);
+      SyncToken sync_token(GetNamespaceID(), GetExtraCommandBufferData(),
+                           GetCommandBufferID(), release);
       mailbox_manager->PushTextureUpdates(sync_token);
     }
   }
@@ -922,7 +925,7 @@
 
   gles2::MailboxManager* mailbox_manager =
       decoder_->GetContextGroup()->mailbox_manager();
-  SyncToken sync_token(namespace_id, command_buffer_id, release);
+  SyncToken sync_token(namespace_id, 0, command_buffer_id, release);
   mailbox_manager->PullTextureUpdates(sync_token);
   return true;
 }
@@ -984,6 +987,10 @@
   return command_buffer_id_;
 }
 
+int32_t InProcessCommandBuffer::GetExtraCommandBufferData() const {
+  return 0;
+}
+
 uint64_t InProcessCommandBuffer::GenerateFenceSyncRelease() {
   return next_fence_sync_release_++;
 }
diff --git a/gpu/command_buffer/service/in_process_command_buffer.h b/gpu/command_buffer/service/in_process_command_buffer.h
index 5f2b644..91ecd74 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.h
+++ b/gpu/command_buffer/service/in_process_command_buffer.h
@@ -128,6 +128,7 @@
   bool IsGpuChannelLost() override;
   CommandBufferNamespace GetNamespaceID() const override;
   uint64_t GetCommandBufferID() const override;
+  int32_t GetExtraCommandBufferData() const override;
   uint64_t GenerateFenceSyncRelease() override;
   bool IsFenceSyncRelease(uint64_t release) override;
   bool IsFenceSyncFlushed(uint64_t release) override;
diff --git a/gpu/command_buffer/service/mailbox_manager_unittest.cc b/gpu/command_buffer/service/mailbox_manager_unittest.cc
index 81979d0..e6ce523 100644
--- a/gpu/command_buffer/service/mailbox_manager_unittest.cc
+++ b/gpu/command_buffer/service/mailbox_manager_unittest.cc
@@ -19,6 +19,7 @@
 using namespace ::testing;
 
 static const SyncToken g_sync_token(gpu::CommandBufferNamespace::GPU_IO,
+                                    0,
                                     123,
                                     0);
 
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index 3053abd..d72994b 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -505,6 +505,10 @@
   return command_buffer_id_;
 }
 
+int32_t GLManager::GetExtraCommandBufferData() const {
+  return 0;
+}
+
 uint64_t GLManager::GenerateFenceSyncRelease() {
   return next_fence_sync_release_++;
 }
diff --git a/gpu/command_buffer/tests/gl_manager.h b/gpu/command_buffer/tests/gl_manager.h
index 378bb69..3ae38ea 100644
--- a/gpu/command_buffer/tests/gl_manager.h
+++ b/gpu/command_buffer/tests/gl_manager.h
@@ -132,6 +132,7 @@
   bool IsGpuChannelLost() override;
   gpu::CommandBufferNamespace GetNamespaceID() const override;
   uint64_t GetCommandBufferID() const override;
+  int32_t GetExtraCommandBufferData() const override;
   uint64_t GenerateFenceSyncRelease() override;
   bool IsFenceSyncRelease(uint64_t release) override;
   bool IsFenceSyncFlushed(uint64_t release) override;
diff --git a/gpu/config/gpu_control_list.cc b/gpu/config/gpu_control_list.cc
index 2e44e3d..5433b61 100644
--- a/gpu/config/gpu_control_list.cc
+++ b/gpu/config/gpu_control_list.cc
@@ -796,7 +796,7 @@
       disabled_(false),
       vendor_id_(0),
       multi_gpu_style_(kMultiGpuStyleNone),
-      multi_gpu_category_(kMultiGpuCategoryPrimary),
+      multi_gpu_category_(kMultiGpuCategoryActive),
       gl_type_(kGLTypeNone) {
 }
 
@@ -1146,7 +1146,7 @@
         candidates.push_back(gpu_info.gpu);
         break;
       case kMultiGpuCategoryActive:
-        if (gpu_info.gpu.active)
+        if (gpu_info.gpu.active || gpu_info.secondary_gpus.empty())
           candidates.push_back(gpu_info.gpu);
         for (size_t ii = 0; ii < gpu_info.secondary_gpus.size(); ++ii) {
           if (gpu_info.secondary_gpus[ii].active)
diff --git a/gpu/config/gpu_control_list_entry_unittest.cc b/gpu/config/gpu_control_list_entry_unittest.cc
index 13c30a2..011c30a 100644
--- a/gpu/config/gpu_control_list_entry_unittest.cc
+++ b/gpu/config/gpu_control_list_entry_unittest.cc
@@ -1148,8 +1148,8 @@
         ]
       }
   );
-  // Default is primary.
-  EntryShouldNotApply(json_default);
+  // Default is active, and the secondary Intel GPU is active.
+  EntryShouldApply(json_default);
 }
 
 TEST_F(GpuControlListEntryDualGPUTest, ActiveSecondaryGPU) {
diff --git a/gpu/config/gpu_control_list_format.txt b/gpu/config/gpu_control_list_format.txt
index 584ad72..ae812bb 100644
--- a/gpu/config/gpu_control_list_format.txt
+++ b/gpu/config/gpu_control_list_format.txt
@@ -30,7 +30,7 @@
 //      d) "amd_switchable_discrete": AMD dual GPU, discrete GPU is active
 //    c) and d) are only valid on Win, as on Mac we can switch GPU on the fly.
 // 6. "multi_gpu_category" is a string, valid values include "any", "primary",
-//    "secondary", and "active". If unspecified, the default value is "primary".
+//    "secondary", and "active". If unspecified, the default value is "active".
 //    See gpu_control_list.h for more details on the meanings of the strings.
 // 7. "driver_vendor" is a string pattern.
 // 8. "driver_version" is a VERSION structure (defined below).
diff --git a/gpu/config/gpu_info_collector.cc b/gpu/config/gpu_info_collector.cc
index beda6fd..20630c6 100644
--- a/gpu/config/gpu_info_collector.cc
+++ b/gpu/config/gpu_info_collector.cc
@@ -13,6 +13,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
 #include "base/trace_event/trace_event.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
@@ -78,6 +79,20 @@
   return std::string();
 }
 
+// Return the array index of the found name, or return -1.
+int StringContainsName(
+    const std::string& str, const std::string* names, size_t num_names) {
+  std::vector<std::string> tokens = base::SplitString(
+      str, " .,()-_", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+  for (size_t ii = 0; ii < tokens.size(); ++ii) {
+    for (size_t name_index = 0; name_index < num_names; ++name_index) {
+      if (tokens[ii] == names[name_index])
+        return name_index;
+    }
+  }
+  return -1;
+}
+
 }  // namespace anonymous
 
 namespace gpu {
@@ -149,12 +164,17 @@
   gpu_info->pixel_shader_version = glsl_version;
   gpu_info->vertex_shader_version = glsl_version;
 
+  IdentifyActiveGPU(gpu_info);
   return CollectDriverInfoGL(gpu_info);
 }
 
 void MergeGPUInfoGL(GPUInfo* basic_gpu_info,
                     const GPUInfo& context_gpu_info) {
   DCHECK(basic_gpu_info);
+  // Copy over GPUs because which one is active could change.
+  basic_gpu_info->gpu = context_gpu_info.gpu;
+  basic_gpu_info->secondary_gpus = context_gpu_info.secondary_gpus;
+
   basic_gpu_info->gl_renderer = context_gpu_info.gl_renderer;
   basic_gpu_info->gl_vendor = context_gpu_info.gl_vendor;
   basic_gpu_info->gl_version = context_gpu_info.gl_version;
@@ -190,5 +210,63 @@
       context_gpu_info.jpeg_decode_accelerator_supported;
 }
 
+void IdentifyActiveGPU(GPUInfo* gpu_info) {
+  const std::string kNVidiaName = "nvidia";
+  const std::string kIntelName = "intel";
+  const std::string kAMDName = "amd";
+  const std::string kATIName = "ati";
+  const std::string kVendorNames[] = {
+      kNVidiaName, kIntelName, kAMDName, kATIName};
+
+  const uint32 kNVidiaID = 0x10de;
+  const uint32 kIntelID = 0x8086;
+  const uint32 kAMDID = 0x1002;
+  const uint32 kATIID = 0x1002;
+  const uint32 kVendorIDs[] = {
+      kNVidiaID, kIntelID, kAMDID, kATIID};
+
+  DCHECK(gpu_info);
+  if (gpu_info->secondary_gpus.size() == 0)
+    return;
+
+  uint32 active_vendor_id = 0;
+  if (!gpu_info->gl_vendor.empty()) {
+    std::string gl_vendor_lower = base::ToLowerASCII(gpu_info->gl_vendor);
+    int index = StringContainsName(
+        gl_vendor_lower, kVendorNames, arraysize(kVendorNames));
+    if (index >= 0) {
+      active_vendor_id = kVendorIDs[index];
+    }
+  }
+  if (active_vendor_id == 0 && !gpu_info->gl_renderer.empty()) {
+    std::string gl_renderer_lower = base::ToLowerASCII(gpu_info->gl_renderer);
+    int index = StringContainsName(
+        gl_renderer_lower, kVendorNames, arraysize(kVendorNames));
+    if (index >= 0) {
+      active_vendor_id = kVendorIDs[index];
+    }
+  }
+  if (active_vendor_id == 0) {
+    // We fail to identify the GPU vendor through GL_VENDOR/GL_RENDERER.
+    return;
+  }
+  gpu_info->gpu.active = false;
+  for (size_t ii = 0; ii < gpu_info->secondary_gpus.size(); ++ii)
+    gpu_info->secondary_gpus[ii].active = false;
+
+  // TODO(zmo): if two GPUs are from the same vendor, this code will always
+  // set the first GPU as active, which could be wrong.
+  if (active_vendor_id == gpu_info->gpu.vendor_id) {
+    gpu_info->gpu.active = true;
+    return;
+  }
+  for (size_t ii = 0; ii < gpu_info->secondary_gpus.size(); ++ii) {
+    if (active_vendor_id == gpu_info->secondary_gpus[ii].vendor_id) {
+      gpu_info->secondary_gpus[ii].active = true;
+      return;
+    }
+  }
+}
+
 }  // namespace gpu
 
diff --git a/gpu/config/gpu_info_collector.h b/gpu/config/gpu_info_collector.h
index ad3ae95..0fda54b 100644
--- a/gpu/config/gpu_info_collector.h
+++ b/gpu/config/gpu_info_collector.h
@@ -46,6 +46,10 @@
 GPU_EXPORT void MergeGPUInfoGL(GPUInfo* basic_gpu_info,
                                const GPUInfo& context_gpu_info);
 
+// If more than one GPUs are identified, and GL strings are available,
+// identify the active GPU based on GL strings.
+GPU_EXPORT void IdentifyActiveGPU(GPUInfo* gpu_info);
+
 }  // namespace gpu
 
 #endif  // GPU_CONFIG_GPU_INFO_COLLECTOR_H_
diff --git a/gpu/config/gpu_info_collector_unittest.cc b/gpu/config/gpu_info_collector_unittest.cc
index 76fc31b2..9f038a98 100644
--- a/gpu/config/gpu_info_collector_unittest.cc
+++ b/gpu/config/gpu_info_collector_unittest.cc
@@ -302,5 +302,57 @@
   }
 }
 
+TEST(MultiGPUsTest, IdentifyActiveGPU) {
+  GPUInfo::GPUDevice nvidia_gpu;
+  nvidia_gpu.vendor_id = 0x10de;
+  nvidia_gpu.device_id = 0x0df8;
+  GPUInfo::GPUDevice intel_gpu;
+  intel_gpu.vendor_id = 0x8086;
+  intel_gpu.device_id = 0x0416;
+
+  GPUInfo gpu_info;
+  gpu_info.gpu = nvidia_gpu;
+  gpu_info.secondary_gpus.push_back(intel_gpu);
+
+  EXPECT_FALSE(gpu_info.gpu.active);
+  EXPECT_FALSE(gpu_info.secondary_gpus[0].active);
+
+  IdentifyActiveGPU(&gpu_info);
+  EXPECT_FALSE(gpu_info.gpu.active);
+  EXPECT_FALSE(gpu_info.secondary_gpus[0].active);
+
+  gpu_info.gl_vendor = "Intel Open Source Technology Center";
+  gpu_info.gl_renderer = "Mesa DRI Intel(R) Haswell Mobile";
+  IdentifyActiveGPU(&gpu_info);
+  EXPECT_FALSE(gpu_info.gpu.active);
+  EXPECT_TRUE(gpu_info.secondary_gpus[0].active);
+
+  gpu_info.gl_vendor = "NVIDIA Corporation";
+  gpu_info.gl_renderer = "Quadro 600/PCIe/SSE2";
+  IdentifyActiveGPU(&gpu_info);
+  EXPECT_TRUE(gpu_info.gpu.active);
+  EXPECT_FALSE(gpu_info.secondary_gpus[0].active);
+}
+
+TEST(MultiGPUsTest, IdentifyActiveGPUAvoidFalseMatch) {
+  // Verify that "Corporation" won't be matched with "ati".
+  GPUInfo::GPUDevice amd_gpu;
+  amd_gpu.vendor_id = 0x1002;
+  amd_gpu.device_id = 0x0df8;
+  GPUInfo::GPUDevice intel_gpu;
+  intel_gpu.vendor_id = 0x8086;
+  intel_gpu.device_id = 0x0416;
+
+  GPUInfo gpu_info;
+  gpu_info.gpu = amd_gpu;
+  gpu_info.secondary_gpus.push_back(intel_gpu);
+
+  gpu_info.gl_vendor = "Google Corporation";
+  gpu_info.gl_renderer = "Chrome GPU Team";
+  IdentifyActiveGPU(&gpu_info);
+  EXPECT_FALSE(gpu_info.gpu.active);
+  EXPECT_FALSE(gpu_info.secondary_gpus[0].active);
+}
+
 }  // namespace gpu
 
diff --git a/gpu/config/software_rendering_list_json.cc b/gpu/config/software_rendering_list_json.cc
index 6dd06c20..cb9948d 100644
--- a/gpu/config/software_rendering_list_json.cc
+++ b/gpu/config/software_rendering_list_json.cc
@@ -29,6 +29,7 @@
       },
       "vendor_id": "0x1002",
       "device_id": ["0x7249"],
+      "multi_gpu_category": "any",
       "features": [
         "webgl",
         "flash_3d",
@@ -114,6 +115,7 @@
       },
       "vendor_id": "0x10de",
       "device_id": ["0x0393"],
+      "multi_gpu_category": "any",
       "features": [
         "webgl",
         "flash_3d",
@@ -394,6 +396,7 @@
       },
       "vendor_id": "0x10de",
       "device_id": ["0x0863"],
+      "multi_gpu_category": "any",
       "features": [
         "accelerated_2d_canvas"
       ]
@@ -411,6 +414,7 @@
       },
       "vendor_id": "0x1002",
       "device_id": ["0x6760", "0x6720"],
+      "multi_gpu_category": "any",
       "features": [
         "webgl"
       ]
@@ -506,6 +510,7 @@
       "multi_gpu_style": "optimus",
       "vendor_id": "0x10de",
       "device_id": ["0x0fd5"],
+      "multi_gpu_category": "any",
       "features": [
         "flash_3d",
         "flash_stage3d"
@@ -707,6 +712,7 @@
       },
       "vendor_id": "0x10de",
       "device_id": ["0x0a29", "0x0861", "0x0863"],
+      "multi_gpu_category": "any",
       "features": [
         "webgl"
       ]
@@ -797,6 +803,7 @@
         }
       },
       "vendor_id": "0x15ad",
+      "multi_gpu_category": "any",
       "features": [
         "all"
       ]
@@ -1107,6 +1114,7 @@
       },
       "vendor_id": "0x8086",
       "device_id": ["0x2a02"],
+      "multi_gpu_category": "any",
       "features": [
         "all"
       ]
diff --git a/gpu/gles2_conform_support/egl/display.cc b/gpu/gles2_conform_support/egl/display.cc
index 3b20d81..f79a453 100644
--- a/gpu/gles2_conform_support/egl/display.cc
+++ b/gpu/gles2_conform_support/egl/display.cc
@@ -345,6 +345,10 @@
   return 0;
 }
 
+int32_t Display::GetExtraCommandBufferData() const {
+  return 0;
+}
+
 uint64_t Display::GenerateFenceSyncRelease() {
   return next_fence_sync_release_++;
 }
diff --git a/gpu/gles2_conform_support/egl/display.h b/gpu/gles2_conform_support/egl/display.h
index da966bdc..ffc96c4d 100644
--- a/gpu/gles2_conform_support/egl/display.h
+++ b/gpu/gles2_conform_support/egl/display.h
@@ -98,6 +98,7 @@
   bool IsGpuChannelLost() override;
   gpu::CommandBufferNamespace GetNamespaceID() const override;
   uint64_t GetCommandBufferID() const override;
+  int32_t GetExtraCommandBufferData() const override;
   uint64_t GenerateFenceSyncRelease() override;
   bool IsFenceSyncRelease(uint64_t release) override;
   bool IsFenceSyncFlushed(uint64_t release) override;
diff --git a/gpu/ipc/gpu_command_buffer_traits.cc b/gpu/ipc/gpu_command_buffer_traits.cc
index a1932eed..faed0e2 100644
--- a/gpu/ipc/gpu_command_buffer_traits.cc
+++ b/gpu/ipc/gpu_command_buffer_traits.cc
@@ -79,7 +79,7 @@
     return false;
   }
 
-  p->Set(namespace_id, command_buffer_id, release_count);
+  p->Set(namespace_id, 0, command_buffer_id, release_count);
   if (p->HasData()) {
     if (!verified_flush)
       return false;
diff --git a/ios/chrome/browser/application_context.h b/ios/chrome/browser/application_context.h
index 8e5fd05..5fcc187 100644
--- a/ios/chrome/browser/application_context.h
+++ b/ios/chrome/browser/application_context.h
@@ -54,6 +54,7 @@
 }
 
 class ApplicationContext;
+class CRLSetFetcher;
 class IOSChromeIOThread;
 class PrefService;
 
@@ -123,6 +124,9 @@
   virtual component_updater::ComponentUpdateService*
   GetComponentUpdateService() = 0;
 
+  // Gets the CRLSetFetcher.
+  virtual CRLSetFetcher* GetCRLSetFetcher() = 0;
+
  protected:
   // Sets the global ApplicationContext instance.
   static void SetApplicationContext(ApplicationContext* context);
diff --git a/ios/chrome/browser/application_context_impl.cc b/ios/chrome/browser/application_context_impl.cc
index 57dc77b..c629eff 100644
--- a/ios/chrome/browser/application_context_impl.cc
+++ b/ios/chrome/browser/application_context_impl.cc
@@ -39,6 +39,7 @@
 #include "ios/chrome/browser/history/history_service_factory.h"
 #include "ios/chrome/browser/ios_chrome_io_thread.h"
 #include "ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.h"
+#include "ios/chrome/browser/net/crl_set_fetcher.h"
 #include "ios/chrome/browser/pref_names.h"
 #include "ios/chrome/browser/prefs/browser_prefs.h"
 #include "ios/chrome/browser/prefs/ios_chrome_pref_service_factory.h"
@@ -311,6 +312,14 @@
   return component_updater_.get();
 }
 
+CRLSetFetcher* ApplicationContextImpl::GetCRLSetFetcher() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (!crl_set_fetcher_) {
+    crl_set_fetcher_ = new CRLSetFetcher;
+  }
+  return crl_set_fetcher_.get();
+}
+
 void ApplicationContextImpl::SetApplicationLocale(const std::string& locale) {
   DCHECK(thread_checker_.CalledOnValidThread());
   application_locale_ = locale;
diff --git a/ios/chrome/browser/application_context_impl.h b/ios/chrome/browser/application_context_impl.h
index a86fa1b..4317e76 100644
--- a/ios/chrome/browser/application_context_impl.h
+++ b/ios/chrome/browser/application_context_impl.h
@@ -64,6 +64,7 @@
   web_resource::PromoResourceService* GetPromoResourceService() override;
   component_updater::ComponentUpdateService* GetComponentUpdateService()
       override;
+  CRLSetFetcher* GetCRLSetFetcher() override;
 
  private:
   // Sets the locale used by the application.
@@ -85,6 +86,7 @@
   scoped_ptr<gcm::GCMDriver> gcm_driver_;
   scoped_ptr<web_resource::PromoResourceService> promo_resource_service_;
   scoped_ptr<component_updater::ComponentUpdateService> component_updater_;
+  scoped_refptr<CRLSetFetcher> crl_set_fetcher_;
   std::string application_locale_;
 
   // Sequenced task runner for local state related I/O tasks.
diff --git a/ios/chrome/browser/data_reduction_proxy/ios_chrome_data_reduction_proxy_io_data.cc b/ios/chrome/browser/data_reduction_proxy/ios_chrome_data_reduction_proxy_io_data.cc
index 1acaa69e..e5e8e72 100644
--- a/ios/chrome/browser/data_reduction_proxy/ios_chrome_data_reduction_proxy_io_data.cc
+++ b/ios/chrome/browser/data_reduction_proxy/ios_chrome_data_reduction_proxy_io_data.cc
@@ -9,8 +9,8 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_experiments_stats.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
 #include "ios/chrome/browser/data_reduction_proxy/ios_chrome_data_reduction_proxy_settings.h"
+#include "ios/chrome/browser/pref_names.h"
 #include "ios/web/public/web_client.h"
 
 using data_reduction_proxy::DataReductionProxyParams;
@@ -33,8 +33,7 @@
     flags |= DataReductionProxyParams::kHoldback;
 
   bool enabled =
-      prefs->GetBoolean(
-          data_reduction_proxy::prefs::kDataReductionProxyEnabled) ||
+      prefs->GetBoolean(prefs::kDataSaverEnabled) ||
       data_reduction_proxy::params::ShouldForceEnableDataReductionProxy();
   scoped_ptr<data_reduction_proxy::DataReductionProxyIOData>
       data_reduction_proxy_io_data(
diff --git a/ios/chrome/browser/data_reduction_proxy/ios_chrome_data_reduction_proxy_settings.cc b/ios/chrome/browser/data_reduction_proxy/ios_chrome_data_reduction_proxy_settings.cc
index 0d2a64a..7e4951ad 100644
--- a/ios/chrome/browser/data_reduction_proxy/ios_chrome_data_reduction_proxy_settings.cc
+++ b/ios/chrome/browser/data_reduction_proxy/ios_chrome_data_reduction_proxy_settings.cc
@@ -24,6 +24,7 @@
 #include "components/proxy_config/proxy_config_pref_names.h"
 #include "components/proxy_config/proxy_prefs.h"
 #include "ios/chrome/browser/metrics/ios_chrome_metrics_service_accessor.h"
+#include "ios/chrome/browser/pref_names.h"
 #include "net/base/host_port_pair.h"
 #include "net/proxy/proxy_config.h"
 #include "net/proxy/proxy_list.h"
@@ -193,7 +194,8 @@
           ui_task_runner, io_data->io_task_runner(), db_task_runner,
           commit_delay));
   data_reduction_proxy::DataReductionProxySettings::
-      InitDataReductionProxySettings(profile_prefs, io_data, service.Pass());
+      InitDataReductionProxySettings(prefs::kDataSaverEnabled, profile_prefs,
+                                     io_data, service.Pass());
   io_data->SetDataReductionProxyService(
       data_reduction_proxy_service()->GetWeakPtr());
 
diff --git a/ios/chrome/browser/geolocation/omnibox_geolocation_local_state.mm b/ios/chrome/browser/geolocation/omnibox_geolocation_local_state.mm
index b951399..e4daa63 100644
--- a/ios/chrome/browser/geolocation/omnibox_geolocation_local_state.mm
+++ b/ios/chrome/browser/geolocation/omnibox_geolocation_local_state.mm
@@ -81,7 +81,7 @@
       authorizationState = geolocation::kAuthorizationStateDenied;
       break;
 
-    case kCLAuthorizationStatusAuthorized:
+    case kCLAuthorizationStatusAuthorizedAlways:
     case kCLAuthorizationStatusAuthorizedWhenInUse:
       break;
   }
diff --git a/ios/chrome/browser/pref_names.cc b/ios/chrome/browser/pref_names.cc
index 42fb4d0..4cea40c1 100644
--- a/ios/chrome/browser/pref_names.cc
+++ b/ios/chrome/browser/pref_names.cc
@@ -43,6 +43,11 @@
 // "true" - opt-in (enabled)
 const char kContextualSearchEnabled[] = "search.contextual_search_enabled";
 
+// Boolean that is true when Data Saver is enabled.
+// TODO(bengr): Migrate the preference string to "data_saver.enabled"
+// (crbug.com/564207).
+const char kDataSaverEnabled[] = "spdy_proxy.enabled";
+
 // The default character encoding to assume for a web page in the
 // absence of MIME charset specification
 const char kDefaultCharset[] = "intl.charset_default";
diff --git a/ios/chrome/browser/pref_names.h b/ios/chrome/browser/pref_names.h
index cb7e280..36768f18 100644
--- a/ios/chrome/browser/pref_names.h
+++ b/ios/chrome/browser/pref_names.h
@@ -16,6 +16,7 @@
 extern const char kBrowserStatesNumCreated[];
 extern const char kBrowsingDataMigrationHasBeenPossible[];
 extern const char kContextualSearchEnabled[];
+extern const char kDataSaverEnabled[];
 extern const char kDefaultCharset[];
 extern const char kEnableDoNotTrack[];
 extern const char kHttpServerProperties[];
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm
index 55644a9..1628d325 100644
--- a/ios/chrome/browser/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -69,6 +69,7 @@
   [OmniboxGeolocationLocalState registerLocalState:registry];
   [MemoryDebuggerManager registerLocalState:registry];
 
+  registry->RegisterBooleanPref(prefs::kDataSaverEnabled, false);
   data_reduction_proxy::RegisterPrefs(registry);
 
   // TODO(shreyasv): Remove this in M49 as almost all users would have the
@@ -123,10 +124,10 @@
   registry->RegisterBooleanPref(
       prefs::kSearchSuggestEnabled, true,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
-  registry->RegisterBooleanPref(prefs::kSigninAllowed, true);
   registry->RegisterBooleanPref(prefs::kSavingBrowserHistoryDisabled, false);
   registry->RegisterBooleanPref(prefs::kAllowDeletingBrowserHistory, true);
   registry->RegisterIntegerPref(prefs::kNtpShownPage, 1 << 10);
+
   // This comes from components/bookmarks/core/browser/bookmark_model.h
   // Defaults to 3, which is the id of bookmarkModel_->mobile_node()
   registry->RegisterInt64Pref(prefs::kNtpShownBookmarksFolder, 3);
diff --git a/ios/chrome/browser/procedural_block_types.h b/ios/chrome/browser/procedural_block_types.h
index b5e7386..760d666 100644
--- a/ios/chrome/browser/procedural_block_types.h
+++ b/ios/chrome/browser/procedural_block_types.h
@@ -5,9 +5,15 @@
 #ifndef IOS_CHROME_BROWSER_PROCEDURAL_BLOCK_TYPES_H_
 #define IOS_CHROME_BROWSER_PROCEDURAL_BLOCK_TYPES_H_
 
+#include <Foundation/Foundation.h>
+
 class GURL;
 
 // A generic procedural block type that takes a |GURL| and returns nothing.
 typedef void (^ProceduralBlockWithURL)(const GURL&);
 
+// A block that takes a bool and returns nothing, as used for UIView animation
+// completion.
+typedef void (^ProceduralBlockWithBool)(BOOL);
+
 #endif  // IOS_CHROME_BROWSER_PROCEDURAL_BLOCK_TYPES_H_
diff --git a/ios/chrome/browser/translate/after_translate_infobar_controller.mm b/ios/chrome/browser/translate/after_translate_infobar_controller.mm
index 2ae014e..6364976f 100644
--- a/ios/chrome/browser/translate/after_translate_infobar_controller.mm
+++ b/ios/chrome/browser/translate/after_translate_infobar_controller.mm
@@ -44,8 +44,8 @@
     [infoBarView addLeftIcon:icon.ToUIImage()];
   // Main text.
   const bool autodeterminedSourceLanguage =
-      _translateInfoBarDelegate->original_language_index() ==
-      translate::TranslateInfoBarDelegate::kNoIndex;
+      _translateInfoBarDelegate->original_language_code() ==
+      translate::kUnknownLanguageCode;
   bool swappedLanguageButtons;
   std::vector<base::string16> strings;
   translate::TranslateInfoBarDelegate::GetAfterTranslateStrings(
@@ -56,12 +56,11 @@
   NSString* label3 = autodeterminedSourceLanguage
                          ? @""
                          : base::SysUTF16ToNSString(strings[2]);
-  base::string16 stdOriginal = _translateInfoBarDelegate->language_name_at(
-      _translateInfoBarDelegate->original_language_index());
+  base::string16 stdOriginal =
+      _translateInfoBarDelegate->original_language_name();
   NSString* original = base::SysUTF16ToNSString(stdOriginal);
-  NSString* target =
-      base::SysUTF16ToNSString(_translateInfoBarDelegate->language_name_at(
-          _translateInfoBarDelegate->target_language_index()));
+  NSString* target = base::SysUTF16ToNSString(
+      _translateInfoBarDelegate->target_language_name());
   base::scoped_nsobject<NSString> label(
       [[NSString alloc] initWithFormat:@"%@ %@ %@%@ %@.", label1, original,
                                        label2, label3, target]);
diff --git a/ios/chrome/browser/translate/before_translate_infobar_controller.mm b/ios/chrome/browser/translate/before_translate_infobar_controller.mm
index c2588d21..78cfaec6 100644
--- a/ios/chrome/browser/translate/before_translate_infobar_controller.mm
+++ b/ios/chrome/browser/translate/before_translate_infobar_controller.mm
@@ -158,12 +158,10 @@
 }
 
 - (void)updateInfobarLabelOnView:(UIView<InfoBarViewProtocol>*)view {
-  NSString* originalLanguage =
-      base::SysUTF16ToNSString(_translateInfoBarDelegate->language_name_at(
-          _translateInfoBarDelegate->original_language_index()));
-  NSString* targetLanguage =
-      base::SysUTF16ToNSString(_translateInfoBarDelegate->language_name_at(
-          _translateInfoBarDelegate->target_language_index()));
+  NSString* originalLanguage = base::SysUTF16ToNSString(
+      _translateInfoBarDelegate->original_language_name());
+  NSString* targetLanguage = base::SysUTF16ToNSString(
+      _translateInfoBarDelegate->target_language_name());
   base::string16 originalLanguageWithLink =
       base::SysNSStringToUTF16([[view class]
           stringAsLink:originalLanguage
@@ -179,15 +177,16 @@
 
 - (void)languageSelectionDone {
   size_t selectedRow = [_languagePicker selectedRowInComponent:0];
+  std::string lang = _translateInfoBarDelegate->language_code_at(selectedRow);
   if (_languageSelectionType ==
           TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE &&
-      selectedRow != _translateInfoBarDelegate->target_language_index()) {
-    _translateInfoBarDelegate->UpdateOriginalLanguageIndex(selectedRow);
+      lang != _translateInfoBarDelegate->target_language_code()) {
+    _translateInfoBarDelegate->UpdateOriginalLanguage(lang);
   }
   if (_languageSelectionType ==
           TranslateInfoBarIOSTag::BEFORE_TARGET_LANGUAGE &&
-      selectedRow != _translateInfoBarDelegate->original_language_index()) {
-    _translateInfoBarDelegate->UpdateTargetLanguageIndex(selectedRow);
+      lang != _translateInfoBarDelegate->original_language_code()) {
+    _translateInfoBarDelegate->UpdateTargetLanguage(lang);
   }
   [self updateInfobarLabelOnView:self.view];
   [self dismissLanguageSelectionView];
@@ -310,13 +309,29 @@
   // Creates the PickerView and its controller.
   NSInteger selectedRow;
   NSInteger disabledRow;
+  NSInteger originalLanguageIndex = -1;
+  NSInteger targetLanguageIndex = -1;
+
+  for (size_t i = 0; i < _translateInfoBarDelegate->num_languages(); ++i) {
+    if (_translateInfoBarDelegate->language_code_at(i) ==
+        _translateInfoBarDelegate->original_language_code()) {
+      originalLanguageIndex = i;
+    }
+    if (_translateInfoBarDelegate->language_code_at(i) ==
+        _translateInfoBarDelegate->target_language_code()) {
+      targetLanguageIndex = i;
+    }
+  }
+  DCHECK_GT(originalLanguageIndex, -1);
+  DCHECK_GT(targetLanguageIndex, -1);
+
   if (_languageSelectionType ==
       TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE) {
-    selectedRow = _translateInfoBarDelegate->original_language_index();
-    disabledRow = _translateInfoBarDelegate->target_language_index();
+    selectedRow = originalLanguageIndex;
+    disabledRow = targetLanguageIndex;
   } else {
-    selectedRow = _translateInfoBarDelegate->target_language_index();
-    disabledRow = _translateInfoBarDelegate->original_language_index();
+    selectedRow = targetLanguageIndex;
+    disabledRow = originalLanguageIndex;
   }
   _languagePickerController.reset([[LanguagePickerController alloc]
       initWithDelegate:_translateInfoBarDelegate
diff --git a/ios/chrome/browser/translate/never_translate_infobar_controller.mm b/ios/chrome/browser/translate/never_translate_infobar_controller.mm
index 9051548..84fcfaf 100644
--- a/ios/chrome/browser/translate/never_translate_infobar_controller.mm
+++ b/ios/chrome/browser/translate/never_translate_infobar_controller.mm
@@ -42,8 +42,8 @@
   if (!icon.IsEmpty())
     [infoBarView addLeftIcon:icon.ToUIImage()];
   // Main text.
-  base::string16 originalLanguage = translateInfoBarDelegate->language_name_at(
-      translateInfoBarDelegate->original_language_index());
+  base::string16 originalLanguage =
+      translateInfoBarDelegate->original_language_name();
   [infoBarView addLabel:l10n_util::GetNSStringF(
                             IDS_TRANSLATE_INFOBAR_NEVER_MESSAGE_IOS,
                             provider->GetStringProvider()->GetProductName(),
diff --git a/ios/chrome/browser/ui/commands/ios_command_ids.h b/ios/chrome/browser/ui/commands/ios_command_ids.h
index af6cab6..aa07da18 100644
--- a/ios/chrome/browser/ui/commands/ios_command_ids.h
+++ b/ios/chrome/browser/ui/commands/ios_command_ids.h
@@ -25,6 +25,7 @@
 #define IDC_FIND_CLOSE                                 40907
 #define IDC_FIND_UPDATE                                40908
 #define IDC_CLOSE_MODALS                               40909
+#define IDC_SHOW_ADD_ACCOUNT                           40910
 #define IDC_SHOW_PAGE_INFO                             40911
 #define IDC_HIDE_PAGE_INFO                             40912
 #define IDC_SHOW_SECURITY_HELP                         40913
diff --git a/ios/chrome/browser/ui/commands/show_signin_command.h b/ios/chrome/browser/ui/commands/show_signin_command.h
index 59bada7e..7f538fd 100644
--- a/ios/chrome/browser/ui/commands/show_signin_command.h
+++ b/ios/chrome/browser/ui/commands/show_signin_command.h
@@ -10,8 +10,7 @@
 #include "ios/chrome/browser/signin/constants.h"
 #include "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 
-typedef void (^ShowSigninCommandCompletionCallback)(BOOL succeeded,
-                                                    BOOL profileWasSwapped);
+typedef void (^ShowSigninCommandCompletionCallback)(BOOL succeeded);
 
 enum AuthenticationOperation {
   // Operation to cancel the current authentication operation and dismiss any
diff --git a/ios/chrome/browser/ui/keyboard/hardware_keyboard_watcher.mm b/ios/chrome/browser/ui/keyboard/hardware_keyboard_watcher.mm
index c390c22..ccc09bb8 100644
--- a/ios/chrome/browser/ui/keyboard/hardware_keyboard_watcher.mm
+++ b/ios/chrome/browser/ui/keyboard/hardware_keyboard_watcher.mm
@@ -24,13 +24,10 @@
 @interface HardwareKeyboardWatcher () {
   base::scoped_nsobject<UIView> _accessoryView;
 }
-@property(nonatomic, assign) UIInterfaceOrientation orientation;
 @end
 
 @implementation HardwareKeyboardWatcher
 
-@synthesize orientation = _orientation;
-
 - (instancetype)init {
   NOTREACHED();
   return nil;
@@ -41,7 +38,6 @@
   self = [super init];
   if (self) {
     _accessoryView.reset([accessoryView retain]);
-    _orientation = [UIApplication sharedApplication].statusBarOrientation;
     [[NSNotificationCenter defaultCenter]
         addObserver:self
            selector:@selector(keyboardWillChangeFrame:)
@@ -61,14 +57,6 @@
   if ([_accessoryView window] == nil)
     return;
 
-  // Don't handle rotations as the reported keyboard frames are in the screen
-  // coordinates *prior* to the rotation, while the screen already has its
-  // new coordinates. http://crbug.com/511267
-  if (self.orientation !=
-      [UIApplication sharedApplication].statusBarOrientation) {
-    return;
-  }
-
   NSDictionary* userInfo = [notification userInfo];
   CGRect beginKeyboardFrame =
       [userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue];
@@ -76,6 +64,15 @@
       [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
   CGRect screenBounds = [UIScreen mainScreen].bounds;
 
+  // During rotations, the reported keyboard frames are in the screen
+  // coordinates *prior* to the rotation, while the screen already has its
+  // new coordinates. http://crbug.com/511267
+  // To alleviate that, switch the screen bounds width and height if needed.
+  if (CGRectGetHeight(screenBounds) == CGRectGetWidth(beginKeyboardFrame)) {
+    screenBounds.size =
+        CGSizeMake(CGRectGetHeight(screenBounds), CGRectGetWidth(screenBounds));
+  }
+
   // CGRectZero frames are seen when moving a split dock. Split keyboard means
   // software keyboard.
   bool hasCGRectZeroFrames =
diff --git a/ios/chrome/browser/ui/side_swipe_gesture_recognizer.mm b/ios/chrome/browser/ui/side_swipe_gesture_recognizer.mm
index bc145f3..73743c5 100644
--- a/ios/chrome/browser/ui/side_swipe_gesture_recognizer.mm
+++ b/ios/chrome/browser/ui/side_swipe_gesture_recognizer.mm
@@ -80,6 +80,13 @@
     return;
   }
 
+  // On devices that support force presses a -touchesMoved fires when |force|
+  // changes and not the location of the touch. Ignore these events.
+  if (currentPoint.x == _startPoint.x) {
+    self.state = UIGestureRecognizerStatePossible;
+    return;
+  }
+
   // Don't recognize swipe in the wrong direction.
   if ((_direction == UISwipeGestureRecognizerDirectionRight &&
        currentPoint.x - _startPoint.x < 0) ||
diff --git a/ios/chrome/browser/ui/uikit_ui_util.h b/ios/chrome/browser/ui/uikit_ui_util.h
index 2223a11..fc0e6a0 100644
--- a/ios/chrome/browser/ui/uikit_ui_util.h
+++ b/ios/chrome/browser/ui/uikit_ui_util.h
@@ -46,26 +46,36 @@
 // Adds a rounded-rectangle border shadow around a view.
 void AddRoundedBorderShadow(UIView* view, CGFloat radius, UIColor* color);
 
+enum CaptureViewOption {
+  kNoCaptureOption,      // Equivalent to calling CaptureView without options.
+  kAfterScreenUpdate,    // Require a synchronization with CA process which can
+                         // have side effects.
+  kClientSideRendering,  // Triggers a client side compositing, very slow.
+};
+
 // Captures and returns an autoreleased rendering of the |view|.
 // The |view| is assumed to be opaque and the returned image does
 // 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.
+// The CaptureViewWithOption function can be used with the |option|
+// parameter set to kAfterScreenUpdate 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.
+// Calling CaptureView without option gives the best performances. If you only
+// need to hide subviews consider selectively rendering subviews in a bitmap
+// context using drawViewHierarchyInRect:afterScreenUpdates:NO.
+// The kClientSideRendering option can be used to directly re-render the view
+// client side instead of reusing the core animation layer's backing store, this
+// is slow.
+// On iOS < 9 this function is slow and always behave as if the option was set
+// to kClientSideRendering.
 UIImage* CaptureViewWithOption(UIView* view,
                                CGFloat scale,
-                               BOOL afterScreenUpdate);
+                               CaptureViewOption option);
 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 c1c2504..afd0612 100644
--- a/ios/chrome/browser/ui/uikit_ui_util.mm
+++ b/ios/chrome/browser/ui/uikit_ui_util.mm
@@ -152,12 +152,12 @@
 
 UIImage* CaptureViewWithOption(UIView* view,
                                CGFloat scale,
-                               BOOL afterScreenUpdate) {
+                               CaptureViewOption option) {
   UIGraphicsBeginImageContextWithOptions(view.bounds.size, YES /* opaque */,
                                          scale);
-  if (base::ios::IsRunningOnIOS9OrLater()) {
+  if (base::ios::IsRunningOnIOS9OrLater() && option != kClientSideRendering) {
     [view drawViewHierarchyInRect:view.bounds
-               afterScreenUpdates:afterScreenUpdate];
+               afterScreenUpdates:option == kAfterScreenUpdate];
   } else {
     CGContext* context = UIGraphicsGetCurrentContext();
     [view.layer renderInContext:context];
@@ -168,7 +168,7 @@
 }
 
 UIImage* CaptureView(UIView* view, CGFloat scale) {
-  return CaptureViewWithOption(view, scale, NO /* afterScreenUpdate */);
+  return CaptureViewWithOption(view, scale, kNoCaptureOption);
 }
 
 UIImage* GreyImage(UIImage* image) {
diff --git a/ios/chrome/ios_chrome_resources.gyp b/ios/chrome/ios_chrome_resources.gyp
index d085be8..7c81ea0 100644
--- a/ios/chrome/ios_chrome_resources.gyp
+++ b/ios/chrome/ios_chrome_resources.gyp
@@ -49,7 +49,6 @@
           # GN version: //ios/chrome/app/strings:ios_locale_settings
           'action_name': 'generate_ios_locale_settings',
           'variables': {
-            'grit_whitelist': '',
             'grit_grd_file': 'app/strings/ios_locale_settings.grd',
           },
           'includes': [ '../../build/grit_action.gypi' ],
@@ -58,7 +57,6 @@
           # GN version: //ios/chrome/app/strings:ios_strings
           'action_name': 'generate_ios_strings',
           'variables': {
-            'grit_whitelist': '',
             'grit_grd_file': 'app/strings/ios_strings.grd',
           },
           'includes': [ '../../build/grit_action.gypi' ],
@@ -67,7 +65,6 @@
           # GN version: //ios/chrome/app/strings:ios_chromium_strings
           'action_name': 'generate_ios_chromium_strings',
           'variables': {
-            'grit_whitelist': '',
             'grit_grd_file': 'app/strings/ios_chromium_strings.grd',
           },
           'includes': [ '../../build/grit_action.gypi' ],
@@ -76,7 +73,6 @@
           # GN version: //ios/chrome/app/strings:ios_google_chrome_strings
           'action_name': 'generate_ios_google_chrome_strings',
           'variables': {
-            'grit_whitelist': '',
             'grit_grd_file': 'app/strings/ios_google_chrome_strings.grd',
           },
           'includes': [ '../../build/grit_action.gypi' ],
@@ -104,7 +100,6 @@
         {
           'action_name': 'ios_theme_resources',
           'variables': {
-            'grit_whitelist': '',
             'grit_grd_file': 'app/theme/ios_theme_resources.grd',
           },
           'includes': [ '../../build/grit_action.gypi' ],
diff --git a/ios/chrome/ios_today_extension_resources.gyp b/ios/chrome/ios_today_extension_resources.gyp
index 3af1d79..62b05a5 100644
--- a/ios/chrome/ios_today_extension_resources.gyp
+++ b/ios/chrome/ios_today_extension_resources.gyp
@@ -24,7 +24,6 @@
         {
           'action_name': 'generate_ios_today_extension_strings',
           'variables': {
-            'grit_whitelist': '',
             'grit_grd_file': 'today_extension/strings/ios_today_extension_strings.grd',
           },
           'includes': [ '../../build/grit_action.gypi' ],
diff --git a/ios/chrome/test/testing_application_context.cc b/ios/chrome/test/testing_application_context.cc
index ca14b86..dd9fa87e 100644
--- a/ios/chrome/test/testing_application_context.cc
+++ b/ios/chrome/test/testing_application_context.cc
@@ -138,3 +138,8 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   return nullptr;
 }
+
+CRLSetFetcher* TestingApplicationContext::GetCRLSetFetcher() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return nullptr;
+}
diff --git a/ios/chrome/test/testing_application_context.h b/ios/chrome/test/testing_application_context.h
index 4d539bc..3b891b18 100644
--- a/ios/chrome/test/testing_application_context.h
+++ b/ios/chrome/test/testing_application_context.h
@@ -48,6 +48,7 @@
   web_resource::PromoResourceService* GetPromoResourceService() override;
   component_updater::ComponentUpdateService* GetComponentUpdateService()
       override;
+  CRLSetFetcher* GetCRLSetFetcher() override;
 
  private:
   base::ThreadChecker thread_checker_;
diff --git a/ios/web/net/request_tracker_impl_unittest.mm b/ios/web/net/request_tracker_impl_unittest.mm
index 64da31fe..0c8e76ec 100644
--- a/ios/web/net/request_tracker_impl_unittest.mm
+++ b/ios/web/net/request_tracker_impl_unittest.mm
@@ -422,12 +422,12 @@
       const_cast<char*>(headers.data())[i] = '\0';
   }
   net::URLRequest* request = GetRequest(0);
+  // TODO(mmenke):  This is really bizarre. Do something more reasonable.
   const_cast<net::HttpResponseInfo&>(request->response_info()).headers =
       new net::HttpResponseHeaders(headers);
-  // |job| will be owned by |request| and released from its destructor.
-  net::URLRequestTestJob* job = new net::URLRequestTestJob(
-      request, request->context()->network_delegate(), headers, "", false);
-  AddInterceptorToRequest(0)->set_main_intercept_job(job);
+  scoped_ptr<net::URLRequestTestJob> job(new net::URLRequestTestJob(
+      request, request->context()->network_delegate(), headers, "", false));
+  AddInterceptorToRequest(0)->set_main_intercept_job(std::move(job));
   request->Start();
 
   tracker_->StartRequest(request);
diff --git a/ios/web/public/web_state/crw_web_user_interface_delegate.h b/ios/web/public/web_state/crw_web_user_interface_delegate.h
index f293b2d..47cfa3ed 100644
--- a/ios/web/public/web_state/crw_web_user_interface_delegate.h
+++ b/ios/web/public/web_state/crw_web_user_interface_delegate.h
@@ -49,6 +49,10 @@
                         completionHandler:
                             (void (^)(NSString* input))completionHandler;
 
+// Cancels any outstanding JavaScript dialogs requested by the functions above.
+- (void)cancelJavaScriptDialogsForWebController:
+    (CRWWebController*)webController;
+
 // Displays a context menu for DOM element. |point| and |view| represent the
 // location and UIView where the context menu was triggered by a user gesture.
 // |menuInfo| keys are defined in crw_context_menu_provider.h.
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 43b1f97..9d14095 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -691,6 +691,11 @@
   if (!self.webView)
     return;
 
+  SEL cancelDialogsSelector =
+      @selector(cancelJavaScriptDialogsForWebController:);
+  if ([self.UIDelegate respondsToSelector:cancelDialogsSelector])
+    [self.UIDelegate cancelJavaScriptDialogsForWebController:self];
+
   if (allowCache)
     _expectedReconstructionURL = [self currentNavigationURL];
   else
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index 219ed09..f624551 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -877,8 +877,6 @@
   }
 }
 
-// This test requires iOS net stack.
-#if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW)
 // Tests that presentSSLError:forSSLStatus:recoverable:callback: is called with
 // correct arguments if WKWebView fails to load a page with bad SSL cert.
 TEST_F(CRWWKWebViewWebControllerTest, SSLCertError) {
@@ -910,7 +908,6 @@
   EXPECT_FALSE([mockDelegate_ recoverable]);
   EXPECT_TRUE([mockDelegate_ shouldContinueCallback]);
 }
-#endif  // !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW)
 
 // None of the |CRWUIWebViewWebControllerTest| setup is needed;
 typedef web::WebTestWithUIWebViewWebController
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 208b01c..3d0fcc6 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
@@ -943,10 +943,13 @@
 
 - (void)webViewWebProcessDidCrash {
   _webProcessIsDead = YES;
-  if ([self.delegate respondsToSelector:
-          @selector(webControllerWebProcessDidCrash:)]) {
+  SEL cancelDialogsSelector =
+      @selector(cancelJavaScriptDialogsForWebController:);
+  if ([self.UIDelegate respondsToSelector:cancelDialogsSelector])
+    [self.UIDelegate cancelJavaScriptDialogsForWebController:self];
+  SEL rendererCrashSelector = @selector(webControllerWebProcessDidCrash:);
+  if ([self.delegate respondsToSelector:rendererCrashSelector])
     [self.delegate webControllerWebProcessDidCrash:self];
-  }
 }
 
 - (void)queryPageReferrerPolicy:(void(^)(NSString*))responseHandler {
@@ -1284,6 +1287,7 @@
 - (void)URLDidChangeWithoutDocumentChange:(const GURL&)newURL {
   DCHECK(newURL == net::GURLWithNSURL([_wkWebView URL]));
   DCHECK_EQ(_documentURL.host(), newURL.host());
+  DCHECK(_documentURL != newURL);
 
   // If called during window.history.pushState or window.history.replaceState
   // JavaScript evaluation, only update the document URL. This callback does not
@@ -1310,6 +1314,7 @@
 
   if (!_changingHistoryState) {
     [self didStartLoadingURL:_documentURL updateHistory:YES];
+    [self updateSSLStatusForCurrentNavigationItem];
     [self didFinishNavigation];
   }
 }
@@ -1596,15 +1601,29 @@
                        return;
                      }
                      GURL jsURL([result UTF8String]);
-                     // Make sure that the window location is as expected,
-                     // and re-check the origin and web view URL to prevent
-                     // race conditions.
-                     // TODO(crbug.com/563568): The third check may drop same
-                     // document URL changes if pending URL change occurs
-                     // immediately after. Revisit heuristics to prevent this.
-                     if (jsURL == url &&
-                         _documentURL.GetOrigin() == url.GetOrigin() &&
-                         net::GURLWithNSURL([_wkWebView URL]) == url) {
+                     // Check that window.location matches the new URL. If
+                     // it does not, this is a document-changing URL change as
+                     // the window location would not have changed to the new
+                     // URL when the script was called.
+                     BOOL windowLocationMatchesNewURL = jsURL == url;
+                     // Re-check origin in case navigaton has occured since
+                     // start of JavaScript evaluation.
+                     BOOL newURLOriginMatchesDocumentURLOrigin =
+                         _documentURL.GetOrigin() == url.GetOrigin();
+                     // Check that the web view URL still matches the new URL.
+                     // TODO(crbug.com/563568): webViewURLMatchesNewURL check
+                     // may drop same document URL changes if pending URL
+                     // change occurs immediately after. Revisit heuristics to
+                     // prevent this.
+                     BOOL webViewURLMatchesNewURL =
+                         net::GURLWithNSURL([_wkWebView URL]) == url;
+                     // Check that the new URL is different from the current
+                     // document URL. If not, URL change should not be reported.
+                     BOOL URLDidChangeFromDocumentURL = url != _documentURL;
+                     if (windowLocationMatchesNewURL &&
+                         newURLOriginMatchesDocumentURLOrigin &&
+                         webViewURLMatchesNewURL &&
+                         URLDidChangeFromDocumentURL) {
                        [self URLDidChangeWithoutDocumentChange:url];
                      }
                  }];
diff --git a/ipc/ipc_perftest_support.cc b/ipc/ipc_perftest_support.cc
index 3af0a1fa..2ece5e1 100644
--- a/ipc/ipc_perftest_support.cc
+++ b/ipc/ipc_perftest_support.cc
@@ -348,7 +348,7 @@
 LockThreadAffinity::LockThreadAffinity(int cpu_number)
     : affinity_set_ok_(false) {
 #if defined(OS_WIN)
-  const DWORD_PTR thread_mask = 1 << cpu_number;
+  const DWORD_PTR thread_mask = static_cast<DWORD_PTR>(1) << cpu_number;
   old_affinity_ = SetThreadAffinityMask(GetCurrentThread(), thread_mask);
   affinity_set_ok_ = old_affinity_ != 0;
 #elif defined(OS_LINUX)
diff --git a/mash/example/window_type_launcher/main.cc b/mash/example/window_type_launcher/main.cc
index 56941fc..d6b31fd 100644
--- a/mash/example/window_type_launcher/main.cc
+++ b/mash/example/window_type_launcher/main.cc
@@ -49,6 +49,7 @@
 #endif
 
   {
+    mojo::embedder::PreInitializeChildProcess();
     mojo::embedder::Init();
 
     ProcessDelegate process_delegate;
@@ -61,16 +62,14 @@
                                    io_thread.task_runner().get(),
                                    mojo::embedder::ScopedPlatformHandle());
 
+    mojo::InterfaceRequest<mojo::Application> application_request;
+    scoped_ptr<mojo::runner::RunnerConnection> connection(
+        mojo::runner::RunnerConnection::ConnectToRunner(
+            &application_request, mojo::ScopedMessagePipeHandle()));
     base::MessageLoop loop(mojo::common::MessagePumpMojo::Create());
     WindowTypeLauncher delegate;
-    {
-      mojo::InterfaceRequest<mojo::Application> application_request;
-      scoped_ptr<mojo::runner::RunnerConnection> connection(
-          mojo::runner::RunnerConnection::ConnectToRunner(
-              &application_request, mojo::ScopedMessagePipeHandle()));
-      mojo::ApplicationImpl impl(&delegate, application_request.Pass());
-      loop.Run();
-    }
+    mojo::ApplicationImpl impl(&delegate, application_request.Pass());
+    loop.Run();
 
     mojo::embedder::ShutdownIPCSupport();
   }
diff --git a/mash/wm/BUILD.gn b/mash/wm/BUILD.gn
index bfa54de7..882d3ac 100644
--- a/mash/wm/BUILD.gn
+++ b/mash/wm/BUILD.gn
@@ -154,6 +154,7 @@
 
   sources = [
     "frame/move_loop_unittest.cc",
+    "layout_manager_unittest.cc",
   ]
 
   deps = [
diff --git a/mash/wm/frame/move_event_handler.cc b/mash/wm/frame/move_event_handler.cc
index 4e9af5c2..00e83d9 100644
--- a/mash/wm/frame/move_event_handler.cc
+++ b/mash/wm/frame/move_event_handler.cc
@@ -5,6 +5,7 @@
 #include "mash/wm/frame/move_event_handler.h"
 
 #include "components/mus/public/cpp/window.h"
+#include "components/mus/public/interfaces/cursor.mojom.h"
 #include "mash/wm/frame/move_loop.h"
 #include "mojo/converters/input_events/input_events_type_converters.h"
 #include "ui/aura/window.h"
@@ -14,6 +15,32 @@
 
 namespace mash {
 namespace wm {
+namespace {
+
+mus::mojom::Cursor CursorForWindowComponent(int window_component) {
+  switch (window_component) {
+    case HTBOTTOM:
+      return mus::mojom::Cursor::CURSOR_SOUTH_RESIZE;
+    case HTBOTTOMLEFT:
+      return mus::mojom::Cursor::CURSOR_SOUTH_WEST_RESIZE;
+    case HTBOTTOMRIGHT:
+      return mus::mojom::Cursor::CURSOR_SOUTH_EAST_RESIZE;
+    case HTLEFT:
+      return mus::mojom::Cursor::CURSOR_WEST_RESIZE;
+    case HTRIGHT:
+      return mus::mojom::Cursor::CURSOR_EAST_RESIZE;
+    case HTTOP:
+      return mus::mojom::Cursor::CURSOR_NORTH_RESIZE;
+    case HTTOPLEFT:
+      return mus::mojom::Cursor::CURSOR_NORTH_WEST_RESIZE;
+    case HTTOPRIGHT:
+      return mus::mojom::Cursor::CURSOR_NORTH_EAST_RESIZE;
+    default:
+      return mus::mojom::Cursor::CURSOR_NULL;
+  }
+}
+
+}  // namespace
 
 MoveEventHandler::MoveEventHandler(mus::Window* mus_window,
                                    aura::Window* aura_window)
@@ -35,18 +62,22 @@
       move_loop_.reset();
   } else if (event->type() == ui::ET_MOUSE_PRESSED ||
              event->type() == ui::ET_TOUCH_PRESSED) {
-    const int ht_location = ShouldStartMoveLoop(event);
+    const int ht_location = GetNonClientComponentForEvent(event);
     if (ht_location != HTNOWHERE) {
       // TODO(sky): convert MoveLoop to take ui::Event.
       move_loop_ = MoveLoop::Create(mus_window_, ht_location,
                                     *mus::mojom::Event::From(*ui_event));
     }
+  } else if (event->type() == ui::ET_MOUSE_MOVED) {
+    const int ht_location = GetNonClientComponentForEvent(event);
+    mus_window_->SetPredefinedCursor(CursorForWindowComponent(ht_location));
   }
   if (had_move_loop || move_loop_)
     event->SetHandled();
 }
 
-int MoveEventHandler::ShouldStartMoveLoop(const ui::LocatedEvent* event) {
+int MoveEventHandler::GetNonClientComponentForEvent(
+    const ui::LocatedEvent* event) {
   return aura_window_->delegate()->GetNonClientComponent(event->location());
 }
 
diff --git a/mash/wm/frame/move_event_handler.h b/mash/wm/frame/move_event_handler.h
index 315e0ce..5c853b2d 100644
--- a/mash/wm/frame/move_event_handler.h
+++ b/mash/wm/frame/move_event_handler.h
@@ -35,7 +35,7 @@
 
  private:
   void ProcessLocatedEvent(ui::LocatedEvent* event);
-  int ShouldStartMoveLoop(const ui::LocatedEvent* event);
+  int GetNonClientComponentForEvent(const ui::LocatedEvent* event);
 
   // Overridden from ui::EventHandler:
   void OnMouseEvent(ui::MouseEvent* event) override;
diff --git a/mash/wm/layout_manager.cc b/mash/wm/layout_manager.cc
index cfedafa..4b72806 100644
--- a/mash/wm/layout_manager.cc
+++ b/mash/wm/layout_manager.cc
@@ -12,9 +12,7 @@
 namespace wm {
 
 LayoutManager::~LayoutManager() {
-  owner_->RemoveObserver(this);
-  for (auto child : owner_->children())
-    child->RemoveObserver(this);
+  Uninstall();
 }
 
 LayoutManager::LayoutManager(mus::Window* owner) : owner_(owner) {
@@ -22,6 +20,15 @@
   DCHECK(owner->children().empty());
 }
 
+void LayoutManager::Uninstall() {
+  if (!owner_)
+    return;
+  owner_->RemoveObserver(this);
+  for (auto child : owner_->children())
+    child->RemoveObserver(this);
+  owner_ = nullptr;
+}
+
 void LayoutManager::OnTreeChanged(
     const mus::WindowObserver::TreeChangeParams& params) {
   DCHECK(params.target);
@@ -37,6 +44,11 @@
   }
 }
 
+void LayoutManager::OnWindowDestroying(mus::Window* window) {
+  if (owner_ == window)
+    Uninstall();
+}
+
 void LayoutManager::OnWindowBoundsChanged(mus::Window* window,
                                           const gfx::Rect& old_bounds,
                                           const gfx::Rect& new_bounds) {
diff --git a/mash/wm/layout_manager.h b/mash/wm/layout_manager.h
index 3fb7299..d523c282 100644
--- a/mash/wm/layout_manager.h
+++ b/mash/wm/layout_manager.h
@@ -24,9 +24,12 @@
  protected:
   explicit LayoutManager(mus::Window* owner);
 
+  void Uninstall();
+
   // Overridden from mus::WindowObserver:
   void OnTreeChanged(
       const mus::WindowObserver::TreeChangeParams& params) override;
+  void OnWindowDestroying(mus::Window* window) override;
   void OnWindowBoundsChanged(mus::Window* window,
                              const gfx::Rect& old_bounds,
                              const gfx::Rect& new_bounds) override;
diff --git a/mash/wm/layout_manager_unittest.cc b/mash/wm/layout_manager_unittest.cc
new file mode 100644
index 0000000..76d0182
--- /dev/null
+++ b/mash/wm/layout_manager_unittest.cc
@@ -0,0 +1,63 @@
+// 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/layout_manager.h"
+
+#include "components/mus/public/cpp/tests/test_window.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mash {
+namespace wm {
+
+class TestLayoutManager : public LayoutManager {
+ public:
+  explicit TestLayoutManager(mus::Window* window)
+      : LayoutManager(window), layout_called_(false) {}
+  ~TestLayoutManager() override {}
+
+  bool GetAndResetLayoutCalled() {
+    bool was_layout_called = layout_called_;
+    layout_called_ = false;
+    return was_layout_called;
+  }
+
+ private:
+  // LayoutManager:
+  void LayoutWindow(mus::Window* window) override {
+    layout_called_ = true;
+  }
+
+  bool layout_called_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestLayoutManager);
+};
+
+// Tests that owning window can be destroyed before the layout manager.
+TEST(LayoutManagerTest, OwningWindowDestroyedFirst) {
+  scoped_ptr<mus::TestWindow> parent(new mus::TestWindow(1));
+  mus::TestWindow child(2);
+  TestLayoutManager layout_manager(parent.get());
+  parent->AddChild(&child);
+  EXPECT_TRUE(layout_manager.GetAndResetLayoutCalled());
+  parent.reset();
+  child.SetBounds(gfx::Rect(100, 200));
+}
+
+// Tests that the layout manager can be destroyed before the owning window.
+TEST(LayoutManagerTest, LayoutManagerDestroyedFirst) {
+  mus::TestWindow parent(1);
+  mus::TestWindow child(2);
+  scoped_ptr<TestLayoutManager> layout_manager(new TestLayoutManager(&parent));
+  parent.AddChild(&child);
+  EXPECT_TRUE(layout_manager->GetAndResetLayoutCalled());
+
+  parent.SetBounds(gfx::Rect(100, 200));
+  EXPECT_TRUE(layout_manager->GetAndResetLayoutCalled());
+
+  layout_manager.reset();
+  parent.SetBounds(gfx::Rect(200, 100));
+}
+
+}  // namespace wm
+}  // namespace mash
diff --git a/mash/wm/window_manager_application.cc b/mash/wm/window_manager_application.cc
index ad0d4c6..97863c4f 100644
--- a/mash/wm/window_manager_application.cc
+++ b/mash/wm/window_manager_application.cc
@@ -121,6 +121,7 @@
   window_layout_.reset(
       new WindowLayout(GetWindowForContainer(mojom::CONTAINER_USER_WINDOWS)));
   window_tree_host_->AddActivationParent(window->id());
+  window_tree_host_->SetTitle("Mash");
 
   AddAccelerators();
 
diff --git a/mash/wm/window_manager_apptest.cc b/mash/wm/window_manager_apptest.cc
index 079af7b..5e235fc 100644
--- a/mash/wm/window_manager_apptest.cc
+++ b/mash/wm/window_manager_apptest.cc
@@ -46,8 +46,7 @@
   DISALLOW_COPY_AND_ASSIGN(WindowManagerAppTest);
 };
 
-// TODO(sky): flakey, http://crbug.com/559412 .
-TEST_F(WindowManagerAppTest, DISABLED_OpenWindow) {
+TEST_F(WindowManagerAppTest, OpenWindow) {
   mus::mojom::WindowManagerPtr connection;
   ConnectToWindowManager(&connection);
 
diff --git a/media/audio/BUILD.gn b/media/audio/BUILD.gn
index 5a74312..706004cdc 100644
--- a/media/audio/BUILD.gn
+++ b/media/audio/BUILD.gn
@@ -88,6 +88,8 @@
     "audio_power_monitor.cc",
     "audio_power_monitor.h",
     "audio_source_diverter.h",
+    "audio_streams_tracker.cc",
+    "audio_streams_tracker.h",
     "clockless_audio_sink.cc",
     "clockless_audio_sink.h",
     "fake_audio_input_stream.cc",
@@ -286,6 +288,7 @@
     "audio_output_proxy_unittest.cc",
     "audio_parameters_unittest.cc",
     "audio_power_monitor_unittest.cc",
+    "audio_streams_tracker_unittest.cc",
     "fake_audio_worker_unittest.cc",
     "point_unittest.cc",
     "simple_sources_unittest.cc",
diff --git a/media/audio/audio_output_device_unittest.cc b/media/audio/audio_output_device_unittest.cc
index 1478e322..5faa119a 100644
--- a/media/audio/audio_output_device_unittest.cc
+++ b/media/audio/audio_output_device_unittest.cc
@@ -35,10 +35,9 @@
 
 namespace {
 
-const std::string kDefaultDeviceId;
-const std::string kNonDefaultDeviceId("valid-nondefault-device-id");
-const std::string kUnauthorizedDeviceId("unauthorized-device-id");
-const url::Origin kDefaultSecurityOrigin;
+const char kDefaultDeviceId[] = "";
+const char kNonDefaultDeviceId[] = "valid-nondefault-device-id";
+const char kUnauthorizedDeviceId[] = "unauthorized-device-id";
 
 class MockRenderCallback : public AudioRendererSink::RenderCallback {
  public:
@@ -136,7 +135,7 @@
   audio_output_ipc_ = new MockAudioOutputIPC();
   audio_device_ = new AudioOutputDevice(
       scoped_ptr<AudioOutputIPC>(audio_output_ipc_), io_loop_.task_runner(), 0,
-      device_id, kDefaultSecurityOrigin);
+      device_id, url::Origin());
   EXPECT_CALL(*audio_output_ipc_,
               RequestDeviceAuthorization(audio_device_.get(), 0, device_id, _));
   audio_device_->RequestDeviceAuthorization();
diff --git a/media/audio/audio_streams_tracker.cc b/media/audio/audio_streams_tracker.cc
new file mode 100644
index 0000000..97b01ca2
--- /dev/null
+++ b/media/audio/audio_streams_tracker.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 "media/audio/audio_streams_tracker.h"
+
+namespace media {
+
+AudioStreamsTracker::AudioStreamsTracker()
+    : current_stream_count_(0), max_stream_count_(0) {
+  thread_checker_.DetachFromThread();
+}
+
+AudioStreamsTracker::~AudioStreamsTracker() {
+  DCHECK_EQ(current_stream_count_, 0u);
+}
+
+void AudioStreamsTracker::IncreaseStreamCount() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_NE(current_stream_count_, SIZE_MAX);
+  ++current_stream_count_;
+  if (current_stream_count_ > max_stream_count_)
+    max_stream_count_ = current_stream_count_;
+}
+
+void AudioStreamsTracker::DecreaseStreamCount() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_NE(current_stream_count_, 0u);
+  --current_stream_count_;
+}
+
+void AudioStreamsTracker::ResetMaxStreamCount() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  max_stream_count_ = current_stream_count_;
+}
+
+size_t AudioStreamsTracker::max_stream_count() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return max_stream_count_;
+}
+
+}  // namespace media
diff --git a/media/audio/audio_streams_tracker.h b/media/audio/audio_streams_tracker.h
new file mode 100644
index 0000000..18d510d
--- /dev/null
+++ b/media/audio/audio_streams_tracker.h
@@ -0,0 +1,49 @@
+// 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_AUDIO_AUDIO_STREAMS_TRACKER_H_
+#define MEDIA_AUDIO_AUDIO_STREAMS_TRACKER_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "media/base/media_export.h"
+
+namespace media {
+
+// Tracks the maximum number of simultaneous streams that was ever registered.
+// All functions must be called on the same thread.
+class MEDIA_EXPORT AudioStreamsTracker {
+ public:
+  AudioStreamsTracker();
+  ~AudioStreamsTracker();
+
+  // Increases/decreases current stream count. Updates max stream count if
+  // current count is larger.
+  void IncreaseStreamCount();
+  void DecreaseStreamCount();
+
+  // Resets the max stream count, i.e. sets it to the current stream count.
+  void ResetMaxStreamCount();
+
+  size_t max_stream_count() const;
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(AudioStreamsTrackerTest, IncreaseAndDecreaseOnce);
+  FRIEND_TEST_ALL_PREFIXES(AudioStreamsTrackerTest,
+                           IncreaseAndDecreaseMultiple);
+
+  // Confirms single-threaded access.
+  base::ThreadChecker thread_checker_;
+
+  // Stores the current and maximum number of streams.
+  size_t current_stream_count_;
+  size_t max_stream_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioStreamsTracker);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_AUDIO_AUDIO_STREAMS_TRACKER_H_
diff --git a/media/audio/audio_streams_tracker_unittest.cc b/media/audio/audio_streams_tracker_unittest.cc
new file mode 100644
index 0000000..cd4addc
--- /dev/null
+++ b/media/audio/audio_streams_tracker_unittest.cc
@@ -0,0 +1,99 @@
+// 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/audio/audio_streams_tracker.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+TEST(AudioStreamsTrackerTest, IncreaseAndDecreaseOnce) {
+  AudioStreamsTracker audio_streams_tracker;
+  const size_t kNumberOfOperations = 5;
+
+  // Increase count.
+  for (size_t i = 1; i <= kNumberOfOperations; ++i) {
+    audio_streams_tracker.IncreaseStreamCount();
+    EXPECT_EQ(i, audio_streams_tracker.current_stream_count_);
+    EXPECT_EQ(i, audio_streams_tracker.max_stream_count());
+  }
+
+  // Reset and check max count.
+  audio_streams_tracker.ResetMaxStreamCount();
+  EXPECT_EQ(kNumberOfOperations, audio_streams_tracker.max_stream_count());
+
+  // Decrease count.
+  for (size_t i = 1; i <= kNumberOfOperations; ++i) {
+    audio_streams_tracker.DecreaseStreamCount();
+    EXPECT_EQ(kNumberOfOperations - i,
+              audio_streams_tracker.current_stream_count_);
+    EXPECT_EQ(kNumberOfOperations, audio_streams_tracker.max_stream_count());
+  }
+
+  // Reset and check max count.
+  audio_streams_tracker.ResetMaxStreamCount();
+  EXPECT_EQ(0u, audio_streams_tracker.max_stream_count());
+}
+
+TEST(AudioStreamsTrackerTest, IncreaseAndDecreaseMultiple) {
+  AudioStreamsTracker audio_streams_tracker;
+  const size_t kNumberOfOperations = 5;
+
+  // Increase 2N (N = kNumberOfOperations).
+  for (size_t i = 1; i <= 2 * kNumberOfOperations; ++i) {
+    audio_streams_tracker.IncreaseStreamCount();
+    EXPECT_EQ(i, audio_streams_tracker.current_stream_count_);
+    EXPECT_EQ(i, audio_streams_tracker.max_stream_count());
+  }
+
+  // Decrease N.
+  for (size_t i = 1; i <= kNumberOfOperations; ++i) {
+    audio_streams_tracker.DecreaseStreamCount();
+    EXPECT_EQ(2 * kNumberOfOperations - i,
+              audio_streams_tracker.current_stream_count_);
+    EXPECT_EQ(2 * kNumberOfOperations,
+              audio_streams_tracker.max_stream_count());
+  }
+
+  // Reset and check max count.
+  audio_streams_tracker.ResetMaxStreamCount();
+  EXPECT_EQ(kNumberOfOperations, audio_streams_tracker.max_stream_count());
+
+  // Increase 2N.
+  for (size_t i = 1; i <= 2 * kNumberOfOperations; ++i) {
+    audio_streams_tracker.IncreaseStreamCount();
+    EXPECT_EQ(kNumberOfOperations + i,
+              audio_streams_tracker.current_stream_count_);
+    EXPECT_EQ(kNumberOfOperations + i,
+              audio_streams_tracker.max_stream_count());
+  }
+
+  // Decrease N.
+  for (size_t i = 1; i <= kNumberOfOperations; ++i) {
+    audio_streams_tracker.DecreaseStreamCount();
+    EXPECT_EQ(3 * kNumberOfOperations - i,
+              audio_streams_tracker.current_stream_count_);
+    EXPECT_EQ(3 * kNumberOfOperations,
+              audio_streams_tracker.max_stream_count());
+  }
+
+  // Reset and check max count.
+  audio_streams_tracker.ResetMaxStreamCount();
+  EXPECT_EQ(2 * kNumberOfOperations, audio_streams_tracker.max_stream_count());
+
+  // Decrease 2N.
+  for (size_t i = 1; i <= 2 * kNumberOfOperations; ++i) {
+    audio_streams_tracker.DecreaseStreamCount();
+    EXPECT_EQ(2 * kNumberOfOperations - i,
+              audio_streams_tracker.current_stream_count_);
+    EXPECT_EQ(2 * kNumberOfOperations,
+              audio_streams_tracker.max_stream_count());
+  }
+
+  // Reset and check max count.
+  audio_streams_tracker.ResetMaxStreamCount();
+  EXPECT_EQ(0u, audio_streams_tracker.max_stream_count());
+}
+
+}  // namespace media
diff --git a/media/base/audio_renderer_mixer_input_unittest.cc b/media/base/audio_renderer_mixer_input_unittest.cc
index 8cc9e46..c01c9acc 100644
--- a/media/base/audio_renderer_mixer_input_unittest.cc
+++ b/media/base/audio_renderer_mixer_input_unittest.cc
@@ -18,10 +18,9 @@
 static const int kSampleRate = 48000;
 static const int kBufferSize = 8192;
 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
-static const std::string kDefaultDeviceId;
-static const std::string kUnauthorizedDeviceId("unauthorized");
-static const std::string kNonexistentDeviceId("nonexistent");
-static const url::Origin kDefaultSecurityOrigin;
+static const char kDefaultDeviceId[] = "";
+static const char kUnauthorizedDeviceId[] = "unauthorized";
+static const char kNonexistentDeviceId[] = "nonexistent";
 
 class AudioRendererMixerInputTest : public testing::Test {
  public:
@@ -42,7 +41,7 @@
                    base::Unretained(this)),
         base::Bind(&AudioRendererMixerInputTest::RemoveMixer,
                    base::Unretained(this)),
-        device_id, kDefaultSecurityOrigin);
+        device_id, url::Origin());
   }
 
   AudioRendererMixer* GetMixer(const AudioParameters& params,
@@ -170,7 +169,7 @@
   EXPECT_EQ(old_mixer, mixers_[0].get());
   base::RunLoop run_loop;
   mixer_input_->SwitchOutputDevice(
-      kDeviceId, kDefaultSecurityOrigin,
+      kDeviceId, url::Origin(),
       base::Bind(&AudioRendererMixerInputTest::SwitchCallback,
                  base::Unretained(this), &run_loop));
   run_loop.Run();
@@ -187,7 +186,7 @@
   AudioRendererMixer* old_mixer = GetInputMixer();
   base::RunLoop run_loop;
   mixer_input_->SwitchOutputDevice(
-      kDefaultDeviceId, kDefaultSecurityOrigin,
+      kDefaultDeviceId, url::Origin(),
       base::Bind(&AudioRendererMixerInputTest::SwitchCallback,
                  base::Unretained(this), &run_loop));
   run_loop.Run();
@@ -203,7 +202,7 @@
               SwitchCallbackCalled(OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND));
   base::RunLoop run_loop;
   mixer_input_->SwitchOutputDevice(
-      kNonexistentDeviceId, kDefaultSecurityOrigin,
+      kNonexistentDeviceId, url::Origin(),
       base::Bind(&AudioRendererMixerInputTest::SwitchCallback,
                  base::Unretained(this), &run_loop));
   run_loop.Run();
@@ -217,7 +216,7 @@
               SwitchCallbackCalled(OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED));
   base::RunLoop run_loop;
   mixer_input_->SwitchOutputDevice(
-      kUnauthorizedDeviceId, kDefaultSecurityOrigin,
+      kUnauthorizedDeviceId, url::Origin(),
       base::Bind(&AudioRendererMixerInputTest::SwitchCallback,
                  base::Unretained(this), &run_loop));
   run_loop.Run();
@@ -229,7 +228,7 @@
 TEST_F(AudioRendererMixerInputTest, SwitchOutputDeviceBeforeStart) {
   base::RunLoop run_loop;
   mixer_input_->SwitchOutputDevice(
-      kDefaultDeviceId, kDefaultSecurityOrigin,
+      kDefaultDeviceId, url::Origin(),
       base::Bind(&AudioRendererMixerInputTest::SwitchCallback,
                  base::Unretained(this), &run_loop));
   EXPECT_CALL(*this, SwitchCallbackCalled(OUTPUT_DEVICE_STATUS_OK));
@@ -243,7 +242,7 @@
 TEST_F(AudioRendererMixerInputTest, SwitchOutputDeviceWithoutStart) {
   base::RunLoop run_loop;
   mixer_input_->SwitchOutputDevice(
-      kDefaultDeviceId, kDefaultSecurityOrigin,
+      kDefaultDeviceId, url::Origin(),
       base::Bind(&AudioRendererMixerInputTest::SwitchCallback,
                  base::Unretained(this), &run_loop));
   EXPECT_CALL(*this, SwitchCallbackCalled(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL));
@@ -267,7 +266,7 @@
   base::RunLoop run_loop;
   EXPECT_CALL(*this, SwitchCallbackCalled(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL));
   mixer_input_->SwitchOutputDevice(
-      kDefaultDeviceId, kDefaultSecurityOrigin,
+      kDefaultDeviceId, url::Origin(),
       base::Bind(&AudioRendererMixerInputTest::SwitchCallback,
                  base::Unretained(this), &run_loop));
   mixer_input_->Stop();
diff --git a/media/base/audio_renderer_mixer_unittest.cc b/media/base/audio_renderer_mixer_unittest.cc
index 8d2b5d4..bae2ebb1 100644
--- a/media/base/audio_renderer_mixer_unittest.cc
+++ b/media/base/audio_renderer_mixer_unittest.cc
@@ -35,32 +35,25 @@
 // Number of full sine wave cycles for each Render() call.
 const int kSineCycles = 4;
 
-// Default device ID.
-const std::string kDefaultDeviceId;
-const url::Origin kDefaultSecurityOrigin;
-
 // Input sample frequencies for testing.
-std::vector<int> kTestInputLower(1, 44100);
-std::vector<int> kTestInputHigher(1, 48000);
-const int kSampleRates[] = {22050, 44100, 48000};
-std::vector<int> kTestInput3Rates(kSampleRates,
-                                  kSampleRates +
-                                      sizeof(kSampleRates) /
-                                          sizeof(kSampleRates[0]));
+const int kTestInputLower = 44100;
+const int kTestInputHigher = 48000;
+const int kTestInput3Rates[] = {22050, 44100, 48000};
 
-// Tuple of <input sampling rates, output sampling rate, epsilon>.
-typedef std::tr1::tuple<std::vector<int>, int, double>
+// Tuple of <input sampling rates, number of input sample rates,
+// output sampling rate, epsilon>.
+typedef std::tr1::tuple<const int* const, size_t, int, double>
     AudioRendererMixerTestData;
 
 class AudioRendererMixerTest
     : public testing::TestWithParam<AudioRendererMixerTestData> {
  public:
   AudioRendererMixerTest()
-      : epsilon_(std::tr1::get<2>(GetParam())),
-        half_fill_(false) {
+      : epsilon_(std::tr1::get<3>(GetParam())), half_fill_(false) {
     // Create input parameters based on test parameters.
-    const std::vector<int>& sample_rates(std::tr1::get<0>(GetParam()));
-    for (size_t i = 0; i < sample_rates.size(); ++i)
+    const int* const sample_rates = std::tr1::get<0>(GetParam());
+    size_t sample_rates_count = std::tr1::get<1>(GetParam());
+    for (size_t i = 0; i < sample_rates_count; ++i)
       input_parameters_.push_back(AudioParameters(
           AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, sample_rates[i],
           kBitsPerChannel, kHighLatencyBufferSize));
@@ -68,7 +61,7 @@
     // Create output parameters based on test parameters.
     output_parameters_ = AudioParameters(
         AudioParameters::AUDIO_PCM_LOW_LATENCY, kChannelLayout,
-        std::tr1::get<1>(GetParam()), 16, kLowLatencyBufferSize);
+        std::tr1::get<2>(GetParam()), 16, kLowLatencyBufferSize);
 
     sink_ = new MockAudioRendererSink();
     EXPECT_CALL(*sink_.get(), Start());
@@ -119,7 +112,8 @@
                        base::Unretained(this)),
             base::Bind(&AudioRendererMixerTest::RemoveMixer,
                        base::Unretained(this)),
-            kDefaultDeviceId, kDefaultSecurityOrigin));
+            // Default device ID and security origin.
+            std::string(), url::Origin()));
         mixer_inputs_[input]->Initialize(input_parameters_[i],
                                          fake_callbacks_[input]);
         mixer_inputs_[input]->SetVolume(1.0f);
@@ -471,7 +465,8 @@
           base::Bind(&AudioRendererMixerTest::GetMixer, base::Unretained(this)),
           base::Bind(&AudioRendererMixerTest::RemoveMixer,
                      base::Unretained(this)),
-          kDefaultDeviceId, kDefaultSecurityOrigin);
+          // Default device ID and security origin.
+          std::string(), url::Origin());
 }
 
 // Ensure the physical stream is paused after a certain amount of time with no
@@ -519,22 +514,31 @@
     AudioRendererMixerTest,
     testing::Values(
         // No resampling, 1 input sample rate.
-        std::tr1::make_tuple(kTestInputLower, kTestInputLower[0], 0.00000048),
+        std::tr1::make_tuple(&kTestInputLower, 1, kTestInputLower, 0.00000048),
 
         // Upsampling, 1 input sample rate.
-        std::tr1::make_tuple(kTestInputLower, kTestInputHigher[0], 0.01),
+        std::tr1::make_tuple(&kTestInputLower, 1, kTestInputHigher, 0.01),
 
         // Downsampling, 1 input sample rate.
-        std::tr1::make_tuple(kTestInputHigher, kTestInputLower[0], 0.01),
+        std::tr1::make_tuple(&kTestInputHigher, 1, kTestInputLower, 0.01),
 
         // Downsampling, multuple input sample rates.
-        std::tr1::make_tuple(kTestInput3Rates, kTestInput3Rates[0], 0.01),
+        std::tr1::make_tuple(static_cast<const int* const>(kTestInput3Rates),
+                             arraysize(kTestInput3Rates),
+                             kTestInput3Rates[0],
+                             0.01),
 
         // Upsampling, multiple sinput sample rates.
-        std::tr1::make_tuple(kTestInput3Rates, kTestInput3Rates[2], 0.01),
+        std::tr1::make_tuple(static_cast<const int* const>(kTestInput3Rates),
+                             arraysize(kTestInput3Rates),
+                             kTestInput3Rates[2],
+                             0.01),
 
         // Both downsampling and upsampling, multiple input sample rates
-        std::tr1::make_tuple(kTestInput3Rates, kTestInput3Rates[1], 0.01)));
+        std::tr1::make_tuple(static_cast<const int* const>(kTestInput3Rates),
+                             arraysize(kTestInput3Rates),
+                             kTestInput3Rates[1],
+                             0.01)));
 
 // Test cases for behavior which is independent of parameters.  Values() doesn't
 // support single item lists and we don't want these test cases to run for every
@@ -544,7 +548,8 @@
     AudioRendererMixerBehavioralTest,
     testing::ValuesIn(std::vector<AudioRendererMixerTestData>(
         1,
-        std::tr1::make_tuple(kTestInputLower,
-                             kTestInputLower[0],
+        std::tr1::make_tuple(&kTestInputLower,
+                             1,
+                             kTestInputLower,
                              0.00000048))));
 }  // namespace media
diff --git a/media/base/user_input_monitor_win.cc b/media/base/user_input_monitor_win.cc
index 3e172c4..19d27b7 100644
--- a/media/base/user_input_monitor_win.cc
+++ b/media/base/user_input_monitor_win.cc
@@ -180,7 +180,7 @@
   UINT size = 0;
   UINT result = GetRawInputData(
       input_handle, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
-  if (result == -1) {
+  if (result == static_cast<UINT>(-1)) {
     PLOG(ERROR) << "GetRawInputData() failed";
     return 0;
   }
@@ -191,7 +191,7 @@
   RAWINPUT* input = reinterpret_cast<RAWINPUT*>(buffer.get());
   result = GetRawInputData(
       input_handle, RID_INPUT, buffer.get(), &size, sizeof(RAWINPUTHEADER));
-  if (result == -1) {
+  if (result == static_cast<UINT>(-1)) {
     PLOG(ERROR) << "GetRawInputData() failed";
     return 0;
   }
diff --git a/media/base/video_frame_metadata.h b/media/base/video_frame_metadata.h
index 48fe509..5e4c900 100644
--- a/media/base/video_frame_metadata.h
+++ b/media/base/video_frame_metadata.h
@@ -5,6 +5,8 @@
 #ifndef MEDIA_BASE_VIDEO_FRAME_METADATA_H_
 #define MEDIA_BASE_VIDEO_FRAME_METADATA_H_
 
+#include <string>
+
 #include "base/compiler_specific.h"
 #include "base/time/time.h"
 #include "base/values.h"
@@ -50,6 +52,14 @@
     // key.
     FRAME_RATE,
 
+    // This is a boolean that signals that the video capture engine detects
+    // interactive content. One possible optimization that this signal can help
+    // with is remote content: adjusting end-to-end latency down to help the
+    // user better coordinate their actions.
+    //
+    // Use Get/SetBoolean for this key.
+    INTERACTIVE_CONTENT,
+
     // This field represents the local time at which either: 1) the frame was
     // generated, if it was done so locally; or 2) the targeted play-out time
     // of the frame, if it was generated from a remote source. This value is NOT
diff --git a/media/base/video_frame_unittest.cc b/media/base/video_frame_unittest.cc
index ee2a454..157986f 100644
--- a/media/base/video_frame_unittest.cc
+++ b/media/base/video_frame_unittest.cc
@@ -269,7 +269,8 @@
 // Verify the gpu::MailboxHolder::ReleaseCallback is called when VideoFrame is
 // destroyed with the default release sync point.
 TEST(VideoFrame, TextureNoLongerNeededCallbackIsCalled) {
-  gpu::SyncToken called_sync_token(gpu::CommandBufferNamespace::GPU_IO, 1, 1);
+  gpu::SyncToken called_sync_token(gpu::CommandBufferNamespace::GPU_IO, 0, 1,
+                                   1);
 
   {
     scoped_refptr<VideoFrame> frame = VideoFrame::WrapNativeTexture(
@@ -321,10 +322,10 @@
     mailbox[i].name[0] = 50 + 1;
   }
 
-  gpu::SyncToken sync_token(kNamespace, kCommandBufferId, 7);
+  gpu::SyncToken sync_token(kNamespace, 0, kCommandBufferId, 7);
   sync_token.SetVerifyFlush();
   uint32 target = 9;
-  gpu::SyncToken release_sync_token(kNamespace, kCommandBufferId, 111);
+  gpu::SyncToken release_sync_token(kNamespace, 0, kCommandBufferId, 111);
   release_sync_token.SetVerifyFlush();
 
   gpu::SyncToken called_sync_token;
diff --git a/media/blink/websourcebuffer_impl.cc b/media/blink/websourcebuffer_impl.cc
index 7e880dd..ffb62c5 100644
--- a/media/blink/websourcebuffer_impl.cc
+++ b/media/blink/websourcebuffer_impl.cc
@@ -4,6 +4,8 @@
 
 #include "media/blink/websourcebuffer_impl.h"
 
+#include <stdint.h>
+
 #include <cmath>
 #include <limits>
 
@@ -25,7 +27,8 @@
 
   // Don't use base::TimeDelta::Max() here, as we want the largest finite time
   // delta.
-  base::TimeDelta max_time = base::TimeDelta::FromInternalValue(kint64max - 1);
+  base::TimeDelta max_time = base::TimeDelta::FromInternalValue(
+      std::numeric_limits<int64_t>::max() - 1);
   double max_time_in_seconds = max_time.InSecondsF();
 
   if (time >= max_time_in_seconds)
diff --git a/media/blink/websourcebuffer_impl.h b/media/blink/websourcebuffer_impl.h
index b03ea7b5..600ab70 100644
--- a/media/blink/websourcebuffer_impl.h
+++ b/media/blink/websourcebuffer_impl.h
@@ -7,8 +7,8 @@
 
 #include <string>
 
-#include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "base/macros.h"
 #include "base/time/time.h"
 #include "third_party/WebKit/public/platform/WebSourceBuffer.h"
 
diff --git a/media/capture/content/thread_safe_capture_oracle.h b/media/capture/content/thread_safe_capture_oracle.h
index a410000..921c6d1f 100644
--- a/media/capture/content/thread_safe_capture_oracle.h
+++ b/media/capture/content/thread_safe_capture_oracle.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MEDIA_CAPTURE_THREAD_SAFE_CAPTURE_ORACLE_H_
-#define MEDIA_CAPTURE_THREAD_SAFE_CAPTURE_ORACLE_H_
+#ifndef MEDIA_CAPTURE_CONTENT_THREAD_SAFE_CAPTURE_ORACLE_H_
+#define MEDIA_CAPTURE_CONTENT_THREAD_SAFE_CAPTURE_ORACLE_H_
 
 #include <string>
 
@@ -52,6 +52,10 @@
     return oracle_.min_capture_period();
   }
 
+  base::TimeTicks last_time_animation_was_detected() const {
+    return oracle_.last_time_animation_was_detected();
+  }
+
   gfx::Size max_frame_size() const {
     return params_.requested_format.frame_size;
   }
@@ -103,4 +107,4 @@
 
 }  // namespace media
 
-#endif  // MEDIA_CAPTURE_THREAD_SAFE_CAPTURE_ORACLE_H_
+#endif  // MEDIA_CAPTURE_CONTENT_THREAD_SAFE_CAPTURE_ORACLE_H_
diff --git a/media/capture/content/video_capture_oracle.h b/media/capture/content/video_capture_oracle.h
index aff9745..6a23973 100644
--- a/media/capture/content/video_capture_oracle.h
+++ b/media/capture/content/video_capture_oracle.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MEDIA_CAPTURE_VIDEO_CAPTURE_ORACLE_H_
-#define MEDIA_CAPTURE_VIDEO_CAPTURE_ORACLE_H_
+#ifndef MEDIA_CAPTURE_CONTENT_VIDEO_CAPTURE_ORACLE_H_
+#define MEDIA_CAPTURE_CONTENT_VIDEO_CAPTURE_ORACLE_H_
 
 #include "base/callback_forward.h"
 #include "base/memory/scoped_ptr.h"
@@ -98,6 +98,11 @@
   // changes to the capture size, to avoid stressing the end-to-end pipeline.
   gfx::Size capture_size() const { return capture_size_; }
 
+  // Returns the oracle's estimate of the last time animation was detected.
+  base::TimeTicks last_time_animation_was_detected() const {
+    return last_time_animation_was_detected_;
+  }
+
  private:
   // Retrieve/Assign a frame timestamp by capture |frame_number|.  Only valid
   // when IsFrameInRecentHistory(frame_number) returns true.
@@ -199,4 +204,4 @@
 
 }  // namespace media
 
-#endif  // MEDIA_CAPTURE_VIDEO_CAPTURE_ORACLE_H_
+#endif  // MEDIA_CAPTURE_CONTENT_VIDEO_CAPTURE_ORACLE_H_
diff --git a/media/capture/video/win/video_capture_device_factory_win.cc b/media/capture/video/win/video_capture_device_factory_win.cc
index 5a626f8..1ff42d8 100644
--- a/media/capture/video/win/video_capture_device_factory_win.cc
+++ b/media/capture/video/win/video_capture_device_factory_win.cc
@@ -63,9 +63,9 @@
       L"%WINDIR%\\system32\\mfreadwrite.dll",
   };
 
-  for (int i = 0; i < arraysize(kMfDLLs); ++i) {
+  for (const wchar_t* kMfDLL : kMfDLLs) {
     wchar_t path[MAX_PATH] = {0};
-    ExpandEnvironmentStringsW(kMfDLLs[i], path, arraysize(path));
+    ExpandEnvironmentStringsW(kMfDLL, path, arraysize(path));
     if (!LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH))
       return false;
   }
diff --git a/media/capture/video/win/video_capture_device_mf_win.cc b/media/capture/video/win/video_capture_device_mf_win.cc
index 95595bd..77f54f8 100644
--- a/media/capture/video/win/video_capture_device_mf_win.cc
+++ b/media/capture/video/win/video_capture_device_mf_win.cc
@@ -171,9 +171,9 @@
       {MFVideoFormat_YV12, PIXEL_FORMAT_YV12},
   };
 
-  for (int i = 0; i < arraysize(kFormatMap); ++i) {
-    if (kFormatMap[i].guid == guid) {
-      *format = kFormatMap[i].format;
+  for (const auto& kFormat : kFormatMap) {
+    if (kFormat.guid == guid) {
+      *format = kFormat.format;
       return true;
     }
   }
diff --git a/media/cast/cast_config.h b/media/cast/cast_config.h
index 6e6b283..4ebef67 100644
--- a/media/cast/cast_config.h
+++ b/media/cast/cast_config.h
@@ -74,6 +74,9 @@
   base::TimeDelta min_playout_delay;
   base::TimeDelta max_playout_delay;
 
+  // Starting playout delay when streaming animated content.
+  base::TimeDelta animated_playout_delay;
+
   // RTP payload type enum: Specifies the type/encoding of frame data.
   int rtp_payload_type;
 
@@ -109,6 +112,9 @@
   base::TimeDelta min_playout_delay;
   base::TimeDelta max_playout_delay;
 
+  // Starting playout delay when streaming animated content.
+  base::TimeDelta animated_playout_delay;
+
   // RTP payload type enum: Specifies the type/encoding of frame data.
   int rtp_payload_type;
 
diff --git a/media/cast/sender/audio_sender.cc b/media/cast/sender/audio_sender.cc
index 4d57d48..be2fc39e 100644
--- a/media/cast/sender/audio_sender.cc
+++ b/media/cast/sender/audio_sender.cc
@@ -25,6 +25,7 @@
                   0,  // |max_frame_rate_| is set after encoder initialization.
                   audio_config.min_playout_delay,
                   audio_config.max_playout_delay,
+                  audio_config.animated_playout_delay,
                   NewFixedCongestionControl(audio_config.bitrate)),
       samples_in_encoder_(0),
       weak_factory_(this) {
diff --git a/media/cast/sender/frame_sender.cc b/media/cast/sender/frame_sender.cc
index 44f505e8..1101bf1 100644
--- a/media/cast/sender/frame_sender.cc
+++ b/media/cast/sender/frame_sender.cc
@@ -4,6 +4,10 @@
 
 #include "media/cast/sender/frame_sender.h"
 
+#include <algorithm>
+#include <limits>
+#include <vector>
+
 #include "base/trace_event/trace_event.h"
 #include "media/cast/cast_defines.h"
 #include "media/cast/constants.h"
@@ -29,17 +33,22 @@
                          bool is_audio,
                          CastTransportSender* const transport_sender,
                          int rtp_timebase,
-                         uint32 ssrc,
+                         uint32_t ssrc,
                          double max_frame_rate,
                          base::TimeDelta min_playout_delay,
                          base::TimeDelta max_playout_delay,
+                         base::TimeDelta animated_playout_delay,
                          CongestionControl* congestion_control)
     : cast_environment_(cast_environment),
       transport_sender_(transport_sender),
       ssrc_(ssrc),
-      min_playout_delay_(min_playout_delay == base::TimeDelta() ?
-                         max_playout_delay : min_playout_delay),
+      min_playout_delay_(min_playout_delay == base::TimeDelta()
+                             ? max_playout_delay
+                             : min_playout_delay),
       max_playout_delay_(max_playout_delay),
+      animated_playout_delay_(animated_playout_delay == base::TimeDelta()
+                                  ? max_playout_delay
+                                  : animated_playout_delay),
       send_target_playout_delay_(false),
       max_frame_rate_(max_frame_rate),
       num_aggressive_rtcp_reports_sent_(0),
@@ -53,7 +62,13 @@
   DCHECK(transport_sender_);
   DCHECK_GT(rtp_timebase_, 0);
   DCHECK(congestion_control_);
-  SetTargetPlayoutDelay(min_playout_delay_);
+  // We assume animated content to begin with since that is the common use
+  // case today.
+  VLOG(1) << SENDER_SSRC << "min latency "
+          << min_playout_delay_.InMilliseconds() << "max latency "
+          << max_playout_delay.InMilliseconds() << "animated latency "
+          << animated_playout_delay.InMilliseconds();
+  SetTargetPlayoutDelay(animated_playout_delay_);
   send_target_playout_delay_ = false;
   memset(frame_rtp_timestamps_, 0, sizeof(frame_rtp_timestamps_));
 }
@@ -86,10 +101,10 @@
   const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
   const base::TimeDelta time_delta =
       now - GetRecordedReferenceTime(last_sent_frame_id_);
-  const int64 rtp_delta = TimeDeltaToRtpDelta(time_delta, rtp_timebase_);
-  const uint32 now_as_rtp_timestamp =
+  const int64_t rtp_delta = TimeDeltaToRtpDelta(time_delta, rtp_timebase_);
+  const uint32_t now_as_rtp_timestamp =
       GetRecordedRtpTimestamp(last_sent_frame_id_) +
-          static_cast<uint32>(rtp_delta);
+      static_cast<uint32_t>(rtp_delta);
   transport_sender_->SendSenderReport(ssrc_, now, now_as_rtp_timestamp);
 
   if (schedule_future_reports)
@@ -160,7 +175,7 @@
   transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_);
 }
 
-void FrameSender::RecordLatestFrameTimestamps(uint32 frame_id,
+void FrameSender::RecordLatestFrameTimestamps(uint32_t frame_id,
                                               base::TimeTicks reference_time,
                                               RtpTimestamp rtp_timestamp) {
   DCHECK(!reference_time.is_null());
@@ -170,17 +185,17 @@
       rtp_timestamp;
 }
 
-base::TimeTicks FrameSender::GetRecordedReferenceTime(uint32 frame_id) const {
+base::TimeTicks FrameSender::GetRecordedReferenceTime(uint32_t frame_id) const {
   return frame_reference_times_[frame_id % arraysize(frame_reference_times_)];
 }
 
-RtpTimestamp FrameSender::GetRecordedRtpTimestamp(uint32 frame_id) const {
+RtpTimestamp FrameSender::GetRecordedRtpTimestamp(uint32_t frame_id) const {
   return frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)];
 }
 
 int FrameSender::GetUnacknowledgedFrameCount() const {
   const int count =
-      static_cast<int32>(last_sent_frame_id_ - latest_acked_frame_id_);
+      static_cast<int32_t>(last_sent_frame_id_ - latest_acked_frame_id_);
   DCHECK_GE(count, 0);
   return count;
 }
@@ -201,7 +216,7 @@
   VLOG(2) << SENDER_SSRC << "About to send another frame: last_sent="
           << last_sent_frame_id_ << ", latest_acked=" << latest_acked_frame_id_;
 
-  const uint32 frame_id = encoded_frame->frame_id;
+  const uint32_t frame_id = encoded_frame->frame_id;
 
   const bool is_first_frame_to_be_sent = last_send_time_.is_null();
   last_send_time_ = cast_environment_->Clock()->NowTicks();
@@ -335,8 +350,8 @@
   cast_environment_->logger()->DispatchFrameEvent(ack_event.Pass());
 
   const bool is_acked_out_of_order =
-      static_cast<int32>(cast_feedback.ack_frame_id -
-                             latest_acked_frame_id_) < 0;
+      static_cast<int32_t>(cast_feedback.ack_frame_id -
+                           latest_acked_frame_id_) < 0;
   VLOG(2) << SENDER_SSRC
           << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "")
           << " for frame " << cast_feedback.ack_frame_id;
@@ -347,7 +362,7 @@
         "latest_acked_frame_id", latest_acked_frame_id_);
   } else {
     // Cancel resends of acked frames.
-    std::vector<uint32> cancel_sending_frames;
+    std::vector<uint32_t> cancel_sending_frames;
     while (latest_acked_frame_id_ != cast_feedback.ack_frame_id) {
       latest_acked_frame_id_++;
       cancel_sending_frames.push_back(latest_acked_frame_id_);
@@ -390,8 +405,10 @@
       duration_in_flight + frame_duration;
   const base::TimeDelta allowed_in_flight = GetAllowedInFlightMediaDuration();
   if (VLOG_IS_ON(1)) {
-    const int64 percent = allowed_in_flight > base::TimeDelta() ?
-        100 * duration_would_be_in_flight / allowed_in_flight : kint64max;
+    const int64_t percent =
+        allowed_in_flight > base::TimeDelta()
+            ? 100 * duration_would_be_in_flight / allowed_in_flight
+            : std::numeric_limits<int64_t>::max();
     VLOG_IF(1, percent > 50)
         << SENDER_SSRC
         << duration_in_flight.InMicroseconds() << " usec in-flight + "
diff --git a/media/cast/sender/frame_sender.h b/media/cast/sender/frame_sender.h
index d3b925e..6b40dcdc 100644
--- a/media/cast/sender/frame_sender.h
+++ b/media/cast/sender/frame_sender.h
@@ -9,7 +9,9 @@
 #ifndef MEDIA_CAST_SENDER_FRAME_SENDER_H_
 #define MEDIA_CAST_SENDER_FRAME_SENDER_H_
 
-#include "base/basictypes.h"
+#include <stdint.h>
+
+#include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
@@ -28,10 +30,11 @@
               bool is_audio,
               CastTransportSender* const transport_sender,
               int rtp_timebase,
-              uint32 ssrc,
+              uint32_t ssrc,
               double max_frame_rate,
               base::TimeDelta min_playout_delay,
               base::TimeDelta max_playout_delay,
+              base::TimeDelta animated_playout_delay,
               CongestionControl* congestion_control);
   virtual ~FrameSender();
 
@@ -73,7 +76,7 @@
   // network layer.
   CastTransportSender* const transport_sender_;
 
-  const uint32 ssrc_;
+  const uint32_t ssrc_;
 
  protected:
   // Schedule and execute periodic checks for re-sending packets.  If no
@@ -96,24 +99,33 @@
   // Warning: If a frame ID too far in the past is requested, the getters will
   // silently succeed but return incorrect values.  Be sure to respect
   // media::cast::kMaxUnackedFrames.
-  void RecordLatestFrameTimestamps(uint32 frame_id,
+  void RecordLatestFrameTimestamps(uint32_t frame_id,
                                    base::TimeTicks reference_time,
                                    RtpTimestamp rtp_timestamp);
-  base::TimeTicks GetRecordedReferenceTime(uint32 frame_id) const;
-  RtpTimestamp GetRecordedRtpTimestamp(uint32 frame_id) const;
+  base::TimeTicks GetRecordedReferenceTime(uint32_t frame_id) const;
+  RtpTimestamp GetRecordedRtpTimestamp(uint32_t frame_id) const;
 
   // Returns the number of frames that were sent but not yet acknowledged.
   int GetUnacknowledgedFrameCount() const;
 
-  // The total amount of time between a frame's capture/recording on the sender
-  // and its playback on the receiver (i.e., shown to a user).  This is fixed as
-  // a value large enough to give the system sufficient time to encode,
-  // transmit/retransmit, receive, decode, and render; given its run-time
-  // environment (sender/receiver hardware performance, network conditions,
-  // etc.).
+  // Playout delay represents total amount of time between a frame's
+  // capture/recording on the sender and its playback on the receiver
+  // (i.e., shown to a user).  This should be a value large enough to
+  // give the system sufficient time to encode, transmit/retransmit,
+  // receive, decode, and render; given its run-time environment
+  // (sender/receiver hardware performance, network conditions,etc.).
+
+  // The |target_playout delay_| is the current delay that is adaptively
+  // adjusted based on feedback from video capture engine and the congestion
+  // control. In case of interactive content, the target is adjusted to start
+  // at |min_playout_delay_| and in case of animated content, it starts out at
+  // |animated_playout_delay_| and then adaptively adjust based on feedback
+  // from congestion control.
   base::TimeDelta target_playout_delay_;
-  base::TimeDelta min_playout_delay_;
-  base::TimeDelta max_playout_delay_;
+  const base::TimeDelta min_playout_delay_;
+  const base::TimeDelta max_playout_delay_;
+  // Starting playout delay for animated content.
+  const base::TimeDelta animated_playout_delay_;
 
   // If true, we transmit the target playout delay to the receiver.
   bool send_target_playout_delay_;
@@ -133,12 +145,12 @@
   // The ID of the last frame sent.  Logic throughout FrameSender assumes this
   // can safely wrap-around.  This member is invalid until
   // |!last_send_time_.is_null()|.
-  uint32 last_sent_frame_id_;
+  uint32_t last_sent_frame_id_;
 
   // The ID of the latest (not necessarily the last) frame that has been
   // acknowledged.  Logic throughout AudioSender assumes this can safely
   // wrap-around.  This member is invalid until |!last_send_time_.is_null()|.
-  uint32 latest_acked_frame_id_;
+  uint32_t latest_acked_frame_id_;
 
   // Counts the number of duplicate ACK that are being received.  When this
   // number reaches a threshold, the sender will take this as a sign that the
diff --git a/media/cast/sender/video_sender.cc b/media/cast/sender/video_sender.cc
index ff65423d..dc61041e 100644
--- a/media/cast/sender/video_sender.cc
+++ b/media/cast/sender/video_sender.cc
@@ -95,6 +95,7 @@
           video_config.max_frame_rate,
           video_config.min_playout_delay,
           video_config.max_playout_delay,
+          video_config.animated_playout_delay,
           video_config.use_external_encoder
               ? NewFixedCongestionControl(
                     (video_config.min_bitrate + video_config.max_bitrate) / 2)
@@ -105,6 +106,7 @@
       frames_in_encoder_(0),
       last_bitrate_(0),
       playout_delay_change_cb_(playout_delay_change_cb),
+      low_latency_mode_(false),
       last_reported_deadline_utilization_(-1.0),
       last_reported_lossy_utilization_(-1.0),
       weak_factory_(this) {
@@ -161,6 +163,16 @@
       "timestamp", reference_time.ToInternalValue(),
       "rtp_timestamp", rtp_timestamp);
 
+  bool low_latency_mode;
+  if (video_frame->metadata()->GetBoolean(
+          VideoFrameMetadata::INTERACTIVE_CONTENT, &low_latency_mode)) {
+    if (low_latency_mode && !low_latency_mode_) {
+      VLOG(1) << "Interactive mode playout time " << min_playout_delay_;
+      playout_delay_change_cb_.Run(min_playout_delay_);
+    }
+    low_latency_mode_ = low_latency_mode;
+  }
+
   // Drop the frame if either its RTP or reference timestamp is not an increase
   // over the last frame's.  This protects: 1) the duration calculations that
   // assume timestamps are monotonically non-decreasing, and 2) assumptions made
@@ -192,7 +204,18 @@
         current_round_trip_time_ * kRoundTripsNeeded +
         base::TimeDelta::FromMilliseconds(kConstantTimeMs),
         max_playout_delay_);
-    if (new_target_delay > target_playout_delay_) {
+    // In case of low latency mode, we prefer frame drops over increasing
+    // playout time.
+    if (!low_latency_mode_ && new_target_delay > target_playout_delay_) {
+      // In case we detect user is no longer in a low latency mode and there is
+      // a need to drop a frame, we ensure the playout delay is at-least the
+      // the starting value for playing animated content.
+      // This is intended to minimize freeze when moving from an interactive
+      // session to watching animating content while being limited by end-to-end
+      // delay.
+      VLOG(1) << "Ensure playout time is at least " << animated_playout_delay_;
+      if (new_target_delay < animated_playout_delay_)
+        new_target_delay = animated_playout_delay_;
       VLOG(1) << "New target delay: " << new_target_delay.InMilliseconds();
       playout_delay_change_cb_.Run(new_target_delay);
     }
diff --git a/media/cast/sender/video_sender.h b/media/cast/sender/video_sender.h
index ab31e7b..8869454 100644
--- a/media/cast/sender/video_sender.h
+++ b/media/cast/sender/video_sender.h
@@ -98,6 +98,11 @@
 
   PlayoutDelayChangeCB playout_delay_change_cb_;
 
+  // Indicates we are operating in a mode where the target playout latency is
+  // low for best user experience. When operating in low latency mode, we
+  // prefer dropping frames over increasing target playout time.
+  bool low_latency_mode_;
+
   // The video encoder's performance metrics as of the last call to
   // OnEncodedVideoFrame().  See header file comments for SenderEncodedFrame for
   // an explanation of these values.
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index 869edfb..b96b039 100644
--- a/media/filters/chunk_demuxer.cc
+++ b/media/filters/chunk_demuxer.cc
@@ -118,7 +118,7 @@
   // spec's similarly named source buffer attributes that are used in coded
   // frame processing. |init_segment_received_cb| is run for each new fully
   // parsed initialization segment.
-  bool Append(const uint8* data,
+  bool Append(const uint8_t* data,
               size_t length,
               TimeDelta append_window_start,
               TimeDelta append_window_end,
@@ -325,7 +325,7 @@
 }
 
 bool SourceState::Append(
-    const uint8* data,
+    const uint8_t* data,
     size_t length,
     TimeDelta append_window_start,
     TimeDelta append_window_end,
@@ -1453,7 +1453,7 @@
 
 void ChunkDemuxer::AppendData(
     const std::string& id,
-    const uint8* data,
+    const uint8_t* data,
     size_t length,
     TimeDelta append_window_start,
     TimeDelta append_window_end,
@@ -1594,7 +1594,8 @@
   // precision of TimeDelta.
   TimeDelta min_duration = TimeDelta::FromInternalValue(1);
   // Don't use TimeDelta::Max() here, as we want the largest finite time delta.
-  TimeDelta max_duration = TimeDelta::FromInternalValue(kint64max - 1);
+  TimeDelta max_duration =
+      TimeDelta::FromInternalValue(std::numeric_limits<int64_t>::max() - 1);
   double min_duration_in_seconds = min_duration.InSecondsF();
   double max_duration_in_seconds = max_duration.InSecondsF();
 
diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h
index db5a2ef..b5d416b 100644
--- a/media/filters/chunk_demuxer.h
+++ b/media/filters/chunk_demuxer.h
@@ -11,7 +11,7 @@
 #include <utility>
 #include <vector>
 
-#include "base/basictypes.h"
+#include "base/macros.h"
 #include "base/synchronization/lock.h"
 #include "media/base/byte_queue.h"
 #include "media/base/demuxer.h"
@@ -234,7 +234,9 @@
   // processing.
   // |init_segment_received_cb| is run for each newly successfully parsed
   // initialization segment.
-  void AppendData(const std::string& id, const uint8* data, size_t length,
+  void AppendData(const std::string& id,
+                  const uint8_t* data,
+                  size_t length,
                   base::TimeDelta append_window_start,
                   base::TimeDelta append_window_end,
                   base::TimeDelta* timestamp_offset,
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
index f041bb6c..3dccb55 100644
--- a/media/filters/ffmpeg_demuxer.cc
+++ b/media/filters/ffmpeg_demuxer.cc
@@ -174,7 +174,8 @@
 
 scoped_ptr<FFmpegDemuxerStream> FFmpegDemuxerStream::Create(
     FFmpegDemuxer* demuxer,
-    AVStream* stream) {
+    AVStream* stream,
+    const scoped_refptr<MediaLog>& media_log) {
   if (!demuxer || !stream)
     return nullptr;
 
@@ -191,9 +192,14 @@
     // TODO(chcunningham): Change AVStreamToAudioDecoderConfig to check
     // IsValidConfig internally and return a null scoped_ptr if not valid.
     if (!AVStreamToAudioDecoderConfig(stream, audio_config.get()) ||
-        !audio_config->IsValidConfig())
+        !audio_config->IsValidConfig()) {
+      MEDIA_LOG(ERROR, media_log)
+          << "FFmpegDemuxer: failed creating audio stream";
       return nullptr;
+    }
 
+    MEDIA_LOG(INFO, media_log) << "FFmpegDemuxer: created audio stream, config "
+                               << audio_config->AsHumanReadableString();
   } else if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
     video_config.reset(new VideoDecoderConfig());
 
@@ -203,8 +209,14 @@
     // TODO(chcunningham): Change AVStreamToVideoDecoderConfig to check
     // IsValidConfig internally and return a null scoped_ptr if not valid.
     if (!AVStreamToVideoDecoderConfig(stream, video_config.get()) ||
-        !video_config->IsValidConfig())
+        !video_config->IsValidConfig()) {
+      MEDIA_LOG(ERROR, media_log)
+          << "FFmpegDemuxer: failed creating video stream";
       return nullptr;
+    }
+
+    MEDIA_LOG(INFO, media_log) << "FFmpegDemuxer: created video stream, config "
+                               << video_config->AsHumanReadableString();
   }
 
   return make_scoped_ptr(new FFmpegDemuxerStream(
@@ -1108,7 +1120,7 @@
     // return nullptr if the AVStream is invalid. Validity checks will verify
     // things like: codec, channel layout, sample/pixel format, etc...
     scoped_ptr<FFmpegDemuxerStream> demuxer_stream =
-        FFmpegDemuxerStream::Create(this, stream);
+        FFmpegDemuxerStream::Create(this, stream, media_log_);
     if (demuxer_stream.get()) {
       streams_[i] = demuxer_stream.release();
     } else {
diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h
index c527b74..009f21b 100644
--- a/media/filters/ffmpeg_demuxer.h
+++ b/media/filters/ffmpeg_demuxer.h
@@ -61,8 +61,10 @@
   //
   // FFmpegDemuxerStream keeps a copy of |demuxer| and initializes itself using
   // information inside |stream|. Both parameters must outlive |this|.
-  static scoped_ptr<FFmpegDemuxerStream> Create(FFmpegDemuxer* demuxer,
-                                                AVStream* stream);
+  static scoped_ptr<FFmpegDemuxerStream> Create(
+      FFmpegDemuxer* demuxer,
+      AVStream* stream,
+      const scoped_refptr<MediaLog>& media_log);
 
   ~FFmpegDemuxerStream() override;
 
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc
index 78b7dcd..af64343 100644
--- a/media/formats/mp4/mp4_stream_parser.cc
+++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -4,6 +4,7 @@
 
 #include "media/formats/mp4/mp4_stream_parser.h"
 
+#include <limits>
 #include <vector>
 
 #include "base/callback_helpers.h"
@@ -83,7 +84,7 @@
   ChangeState(kParsingBoxes);
 }
 
-bool MP4StreamParser::Parse(const uint8* buf, int size) {
+bool MP4StreamParser::Parse(const uint8_t* buf, int size) {
   DCHECK_NE(state_, kWaitingForInit);
 
   if (state_ == kError)
@@ -117,7 +118,7 @@
       case kEmittingSamples:
         result = EnqueueSample(&audio_buffers, &video_buffers, &err);
         if (result) {
-          int64 max_clear = runs_->GetMaxClearOffset() + moof_head_;
+          int64_t max_clear = runs_->GetMaxClearOffset() + moof_head_;
           err = !ReadAndDiscardMDATsUntil(max_clear);
         }
         break;
@@ -139,7 +140,7 @@
 }
 
 bool MP4StreamParser::ParseBox(bool* err) {
-  const uint8* buf;
+  const uint8_t* buf;
   int size;
   queue_.Peek(&buf, &size);
   if (!size) return false;
@@ -225,7 +226,7 @@
         return false;
       }
 
-      uint8 audio_type = entry.esds.object_type;
+      uint8_t audio_type = entry.esds.object_type;
       DVLOG(1) << "audio_type " << std::hex << static_cast<int>(audio_type);
       if (audio_object_types_.find(audio_type) == audio_object_types_.end()) {
         MEDIA_LOG(ERROR, media_log_)
@@ -238,7 +239,7 @@
       AudioCodec codec = kUnknownAudioCodec;
       ChannelLayout channel_layout = CHANNEL_LAYOUT_NONE;
       int sample_per_second = 0;
-      std::vector<uint8> extra_data;
+      std::vector<uint8_t> extra_data;
       // Check if it is MPEG4 AAC defined in ISO 14496 Part 3 or
       // supported MPEG2 AAC varients.
       if (ESDescriptor::IsAAC(audio_type)) {
@@ -325,7 +326,7 @@
         moov_->extends.header.fragment_duration, moov_->header.timescale);
     params.liveness = DemuxerStream::LIVENESS_RECORDED;
   } else if (moov_->header.duration > 0 &&
-             moov_->header.duration != kuint64max) {
+             moov_->header.duration != std::numeric_limits<uint64_t>::max()) {
     params.duration =
         TimeDeltaFromRational(moov_->header.duration, moov_->header.timescale);
     params.liveness = DemuxerStream::LIVENESS_RECORDED;
@@ -376,7 +377,7 @@
   for (size_t i = 0; i < headers.size(); i++)
     total_size += headers[i].raw_box.size();
 
-  std::vector<uint8> init_data(total_size);
+  std::vector<uint8_t> init_data(total_size);
   size_t pos = 0;
   for (size_t i = 0; i < headers.size(); i++) {
     memcpy(&init_data[pos], &headers[i].raw_box[0],
@@ -387,7 +388,8 @@
 }
 
 bool MP4StreamParser::PrepareAACBuffer(
-    const AAC& aac_config, std::vector<uint8>* frame_buf,
+    const AAC& aac_config,
+    std::vector<uint8_t>* frame_buf,
     std::vector<SubsampleEntry>* subsamples) const {
   // Append an ADTS header to every audio sample.
   RCHECK(aac_config.ConvertEsdsToADTS(frame_buf));
@@ -432,7 +434,7 @@
 
   DCHECK(!(*err));
 
-  const uint8* buf;
+  const uint8_t* buf;
   int buf_size;
   queue_.Peek(&buf, &buf_size);
   if (!buf_size) return false;
@@ -474,7 +476,7 @@
     subsamples = decrypt_config->subsamples();
   }
 
-  std::vector<uint8> frame_buf(buf, buf + runs_->sample_size());
+  std::vector<uint8_t> frame_buf(buf, buf + runs_->sample_size());
   if (video) {
     DCHECK(runs_->video_description().frame_bitstream_converter);
     if (!runs_->video_description().frame_bitstream_converter->ConvertFrame(
@@ -562,11 +564,11 @@
   return success;
 }
 
-bool MP4StreamParser::ReadAndDiscardMDATsUntil(int64 max_clear_offset) {
+bool MP4StreamParser::ReadAndDiscardMDATsUntil(int64_t max_clear_offset) {
   bool err = false;
-  int64 upper_bound = std::min(max_clear_offset, queue_.tail());
+  int64_t upper_bound = std::min(max_clear_offset, queue_.tail());
   while (mdat_tail_ < upper_bound) {
-    const uint8* buf = NULL;
+    const uint8_t* buf = NULL;
     int size = 0;
     queue_.PeekAt(mdat_tail_, &buf, &size);
 
@@ -610,12 +612,12 @@
   RCHECK(runs.Init(moof));
 
   while (runs.IsRunValid()) {
-    int64 aux_info_end_offset = runs.aux_info_offset() + runs.aux_info_size();
+    int64_t aux_info_end_offset = runs.aux_info_offset() + runs.aux_info_size();
     if (aux_info_end_offset > highest_end_offset_)
       highest_end_offset_ = aux_info_end_offset;
 
     while (runs.IsSampleValid()) {
-      int64 sample_end_offset = runs.sample_offset() + runs.sample_size();
+      int64_t sample_end_offset = runs.sample_offset() + runs.sample_size();
       if (sample_end_offset > highest_end_offset_)
         highest_end_offset_ = sample_end_offset;
 
diff --git a/media/formats/mp4/mp4_stream_parser.h b/media/formats/mp4/mp4_stream_parser.h
index 2ffe640..169d3331 100644
--- a/media/formats/mp4/mp4_stream_parser.h
+++ b/media/formats/mp4/mp4_stream_parser.h
@@ -5,12 +5,14 @@
 #ifndef MEDIA_FORMATS_MP4_MP4_STREAM_PARSER_H_
 #define MEDIA_FORMATS_MP4_MP4_STREAM_PARSER_H_
 
+#include <stdint.h>
+
 #include <set>
 #include <vector>
 
-#include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/compiler_specific.h"
+#include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "media/base/media_export.h"
 #include "media/base/stream_parser.h"
@@ -37,7 +39,7 @@
             const base::Closure& end_of_segment_cb,
             const scoped_refptr<MediaLog>& media_log) override;
   void Flush() override;
-  bool Parse(const uint8* buf, int size) override;
+  bool Parse(const uint8_t* buf, int size) override;
 
  private:
   enum State {
@@ -63,13 +65,13 @@
   // is the upper bound on what can be removed from |queue_|. Anything below
   // this offset is no longer needed by the parser.
   // Returns 'true' on success, 'false' if there was an error.
-  bool ReadAndDiscardMDATsUntil(int64 max_clear_offset);
+  bool ReadAndDiscardMDATsUntil(int64_t max_clear_offset);
 
   void ChangeState(State new_state);
 
   bool EmitConfigs();
   bool PrepareAACBuffer(const AAC& aac_config,
-                        std::vector<uint8>* frame_buf,
+                        std::vector<uint8_t>* frame_buf,
                         std::vector<SubsampleEntry>* subsamples) const;
   bool EnqueueSample(BufferQueue* audio_buffers,
                      BufferQueue* video_buffers,
@@ -104,23 +106,23 @@
   // |moof_head_| is the offset of the start of the most recently parsed moof
   // block. All byte offsets in sample information are relative to this offset,
   // as mandated by the Media Source spec.
-  int64 moof_head_;
+  int64_t moof_head_;
   // |mdat_tail_| is the stream offset of the end of the current 'mdat' box.
   // Valid iff it is greater than the head of the queue.
-  int64 mdat_tail_;
+  int64_t mdat_tail_;
 
   // The highest end offset in the current moof. This offset is
   // relative to |moof_head_|. This value is used to make sure we have collected
   // enough bytes to parse all samples and aux_info in the current moof.
-  int64 highest_end_offset_;
+  int64_t highest_end_offset_;
 
   scoped_ptr<mp4::Movie> moov_;
   scoped_ptr<mp4::TrackRunIterator> runs_;
 
   bool has_audio_;
   bool has_video_;
-  uint32 audio_track_id_;
-  uint32 video_track_id_;
+  uint32_t audio_track_id_;
+  uint32_t video_track_id_;
   // The object types allowed for audio tracks.
   std::set<int> audio_object_types_;
   bool has_sbr_;
diff --git a/media/formats/webm/webm_parser.cc b/media/formats/webm/webm_parser.cc
index fda287c..6929a83c 100644
--- a/media/formats/webm/webm_parser.cc
+++ b/media/formats/webm/webm_parser.cc
@@ -12,6 +12,7 @@
 // http://wiki.webmproject.org/encryption/webm-encryption-rfc
 
 #include <iomanip>
+#include <limits>
 
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
@@ -423,9 +424,11 @@
 //                     element size fields and is false for ID field values.
 //
 // Returns: The number of bytes parsed on success. -1 on error.
-static int ParseWebMElementHeaderField(const uint8* buf, int size,
-                                       int max_bytes, bool mask_first_byte,
-                                       int64* num) {
+static int ParseWebMElementHeaderField(const uint8_t* buf,
+                                       int size,
+                                       int max_bytes,
+                                       bool mask_first_byte,
+                                       int64_t* num) {
   DCHECK(buf);
   DCHECK(num);
 
@@ -436,7 +439,7 @@
     return 0;
 
   int mask = 0x80;
-  uint8 ch = buf[0];
+  uint8_t ch = buf[0];
   int extra_bytes = -1;
   bool all_ones = false;
   for (int i = 0; i < max_bytes; ++i) {
@@ -466,13 +469,15 @@
   }
 
   if (all_ones)
-    *num = kint64max;
+    *num = std::numeric_limits<int64_t>::max();
 
   return bytes_used;
 }
 
-int WebMParseElementHeader(const uint8* buf, int size,
-                           int* id, int64* element_size) {
+int WebMParseElementHeader(const uint8_t* buf,
+                           int size,
+                           int* id,
+                           int64_t* element_size) {
   DCHECK(buf);
   DCHECK_GE(size, 0);
   DCHECK(id);
@@ -481,13 +486,13 @@
   if (size == 0)
     return 0;
 
-  int64 tmp = 0;
+  int64_t tmp = 0;
   int num_id_bytes = ParseWebMElementHeaderField(buf, size, 4, false, &tmp);
 
   if (num_id_bytes <= 0)
     return num_id_bytes;
 
-  if (tmp == kint64max)
+  if (tmp == std::numeric_limits<int64_t>::max())
     tmp = kWebMReservedId;
 
   *id = static_cast<int>(tmp);
@@ -499,7 +504,7 @@
   if (num_size_bytes <= 0)
     return num_size_bytes;
 
-  if (tmp == kint64max)
+  if (tmp == std::numeric_limits<int64_t>::max())
     tmp = kWebMUnknownSize;
 
   *element_size = tmp;
@@ -543,19 +548,22 @@
   return -1;
 }
 
-static int ParseUInt(const uint8* buf, int size, int id,
+static int ParseUInt(const uint8_t* buf,
+                     int size,
+                     int id,
                      WebMParserClient* client) {
   if ((size <= 0) || (size > 8))
     return -1;
 
   // Read in the big-endian integer.
-  uint64 value = 0;
+  uint64_t value = 0;
   for (int i = 0; i < size; ++i)
     value = (value << 8) | buf[i];
 
-  // We use int64 in place of uint64 everywhere for convenience.  See this bug
+  // We use int64_t in place of uint64_t everywhere for convenience.  See this
+  // bug
   // for more details: http://crbug.com/366750#c3
-  if (!base::IsValueInRangeForNumericType<int64>(value))
+  if (!base::IsValueInRangeForNumericType<int64_t>(value))
     return -1;
 
   if (!client->OnUInt(id, value))
@@ -564,16 +572,17 @@
   return size;
 }
 
-static int ParseFloat(const uint8* buf, int size, int id,
+static int ParseFloat(const uint8_t* buf,
+                      int size,
+                      int id,
                       WebMParserClient* client) {
-
   if ((size != 4) && (size != 8))
     return -1;
 
   double value = -1;
 
   // Read the bytes from big-endian form into a native endian integer.
-  int64 tmp = 0;
+  int64_t tmp = 0;
   for (int i = 0; i < size; ++i)
     tmp = (tmp << 8) | buf[i];
 
@@ -581,14 +590,14 @@
   // number.
   if (size == 4) {
     union {
-      int32 src;
+      int32_t src;
       float dst;
     } tmp2;
-    tmp2.src = static_cast<int32>(tmp);
+    tmp2.src = static_cast<int32_t>(tmp);
     value = tmp2.dst;
   } else if (size == 8) {
     union {
-      int64 src;
+      int64_t src;
       double dst;
     } tmp2;
     tmp2.src = tmp;
@@ -603,21 +612,28 @@
   return size;
 }
 
-static int ParseBinary(const uint8* buf, int size, int id,
+static int ParseBinary(const uint8_t* buf,
+                       int size,
+                       int id,
                        WebMParserClient* client) {
   return client->OnBinary(id, buf, size) ? size : -1;
 }
 
-static int ParseString(const uint8* buf, int size, int id,
+static int ParseString(const uint8_t* buf,
+                       int size,
+                       int id,
                        WebMParserClient* client) {
-  const uint8* end = static_cast<const uint8*>(memchr(buf, '\0', size));
+  const uint8_t* end = static_cast<const uint8_t*>(memchr(buf, '\0', size));
   int length = (end != NULL) ? static_cast<int>(end - buf) : size;
   std::string str(reinterpret_cast<const char*>(buf), length);
   return client->OnString(id, str) ? size : -1;
 }
 
-static int ParseNonListElement(ElementType type, int id, int64 element_size,
-                               const uint8* buf, int size,
+static int ParseNonListElement(ElementType type,
+                               int id,
+                               int64_t element_size,
+                               const uint8_t* buf,
+                               int size,
                                WebMParserClient* client) {
   DCHECK_GE(size, element_size);
 
@@ -664,7 +680,7 @@
   return false;
 }
 
-bool WebMParserClient::OnUInt(int id, int64 val) {
+bool WebMParserClient::OnUInt(int id, int64_t val) {
   DVLOG(1) << "Unexpected unsigned integer element with ID " << std::hex << id;
   return false;
 }
@@ -674,7 +690,7 @@
   return false;
 }
 
-bool WebMParserClient::OnBinary(int id, const uint8* data, int size) {
+bool WebMParserClient::OnBinary(int id, const uint8_t* data, int size) {
   DVLOG(1) << "Unexpected binary element with ID " << std::hex << id;
   return false;
 }
@@ -700,7 +716,7 @@
   list_state_stack_.clear();
 }
 
-int WebMListParser::Parse(const uint8* buf, int size) {
+int WebMListParser::Parse(const uint8_t* buf, int size) {
   DCHECK(buf);
 
   if (size < 0 || state_ == PARSE_ERROR || state_ == DONE_PARSING_LIST)
@@ -709,13 +725,13 @@
   if (size == 0)
     return 0;
 
-  const uint8* cur = buf;
+  const uint8_t* cur = buf;
   int cur_size = size;
   int bytes_parsed = 0;
 
   while (cur_size > 0 && state_ != PARSE_ERROR && state_ != DONE_PARSING_LIST) {
     int element_id = 0;
-    int64 element_size = 0;
+    int64_t element_size = 0;
     int result = WebMParseElementHeader(cur, cur_size, &element_id,
                                         &element_size);
 
@@ -749,7 +765,7 @@
 
       case INSIDE_LIST: {
         int header_size = result;
-        const uint8* element_data = cur + header_size;
+        const uint8_t* element_data = cur + header_size;
         int element_data_size = cur_size - header_size;
 
         if (element_size < element_data_size)
@@ -793,8 +809,10 @@
 }
 
 int WebMListParser::ParseListElement(int header_size,
-                                     int id, int64 element_size,
-                                     const uint8* data, int size) {
+                                     int id,
+                                     int64_t element_size,
+                                     const uint8_t* data,
+                                     int size) {
   DCHECK_GT(list_state_stack_.size(), 0u);
 
   ListState& list_state = list_state_stack_.back();
@@ -827,7 +845,7 @@
   }
 
   // Make sure the whole element can fit inside the current list.
-  int64 total_element_size = header_size + element_size;
+  int64_t total_element_size = header_size + element_size;
   if (list_state.size_ != kWebMUnknownSize &&
       list_state.size_ < list_state.bytes_parsed_ + total_element_size) {
     return -1;
@@ -869,7 +887,7 @@
   return result;
 }
 
-bool WebMListParser::OnListStart(int id, int64 size) {
+bool WebMListParser::OnListStart(int id, int64_t size) {
   const ListElementInfo* element_info = FindListInfo(id);
   if (!element_info)
     return false;
@@ -907,7 +925,7 @@
   int lists_ended = 0;
   for (; !list_state_stack_.empty(); ++lists_ended) {
     const ListState& list_state = list_state_stack_.back();
-    int64 bytes_parsed = list_state.bytes_parsed_;
+    int64_t bytes_parsed = list_state.bytes_parsed_;
     int id = list_state.id_;
 
     if (bytes_parsed != list_state.size_)
diff --git a/media/formats/webm/webm_parser.h b/media/formats/webm/webm_parser.h
index 854db68..3af81ea1 100644
--- a/media/formats/webm/webm_parser.h
+++ b/media/formats/webm/webm_parser.h
@@ -5,10 +5,12 @@
 #ifndef MEDIA_FORMATS_WEBM_WEBM_PARSER_H_
 #define MEDIA_FORMATS_WEBM_WEBM_PARSER_H_
 
+#include <stdint.h>
+
 #include <string>
 #include <vector>
 
-#include "base/basictypes.h"
+#include "base/macros.h"
 #include "media/base/media_export.h"
 
 namespace media {
@@ -31,9 +33,9 @@
 
   virtual WebMParserClient* OnListStart(int id);
   virtual bool OnListEnd(int id);
-  virtual bool OnUInt(int id, int64 val);
+  virtual bool OnUInt(int id, int64_t val);
   virtual bool OnFloat(int id, double val);
-  virtual bool OnBinary(int id, const uint8* data, int size);
+  virtual bool OnBinary(int id, const uint8_t* data, int size);
   virtual bool OnString(int id, const std::string& str);
 
  protected:
@@ -64,7 +66,7 @@
   // Returns < 0 if the parse fails.
   // Returns 0 if more data is needed.
   // Returning > 0 indicates success & the number of bytes parsed.
-  int Parse(const uint8* buf, int size);
+  int Parse(const uint8_t* buf, int size);
 
   // Returns true if the entire list has been parsed.
   bool IsParsingComplete() const;
@@ -79,8 +81,8 @@
 
   struct ListState {
     int id_;
-    int64 size_;
-    int64 bytes_parsed_;
+    int64_t size_;
+    int64_t bytes_parsed_;
     const ListElementInfo* element_info_;
     WebMParserClient* client_;
   };
@@ -100,8 +102,10 @@
   // Returns 0 if more data is needed.
   // Returning > 0 indicates success & the number of bytes parsed.
   int ParseListElement(int header_size,
-                       int id, int64 element_size,
-                       const uint8* data, int size);
+                       int id,
+                       int64_t element_size,
+                       const uint8_t* data,
+                       int size);
 
   // Called when starting to parse a new list.
   //
@@ -111,7 +115,7 @@
   //
   // Returns true if this list can be started in the current context. False
   // if starting this list causes some sort of parse error.
-  bool OnListStart(int id, int64 size);
+  bool OnListStart(int id, int64_t size);
 
   // Called when the end of the current list has been reached. This may also
   // signal the end of the current list's ancestors if the current list happens
@@ -150,8 +154,10 @@
 // |*id| contains the element ID on success and is undefined otherwise.
 // |*element_size| contains the element size on success and is undefined
 //                 otherwise.
-int MEDIA_EXPORT WebMParseElementHeader(const uint8* buf, int size,
-                                        int* id, int64* element_size);
+int MEDIA_EXPORT WebMParseElementHeader(const uint8_t* buf,
+                                        int size,
+                                        int* id,
+                                        int64_t* element_size);
 
 }  // namespace media
 
diff --git a/media/formats/webm/webm_parser_unittest.cc b/media/formats/webm/webm_parser_unittest.cc
index a1249e89..26f5f4b 100644
--- a/media/formats/webm/webm_parser_unittest.cc
+++ b/media/formats/webm/webm_parser_unittest.cc
@@ -25,9 +25,9 @@
   // WebMParserClient methods.
   MOCK_METHOD1(OnListStart, WebMParserClient*(int));
   MOCK_METHOD1(OnListEnd, bool(int));
-  MOCK_METHOD2(OnUInt, bool(int, int64));
+  MOCK_METHOD2(OnUInt, bool(int, int64_t));
   MOCK_METHOD2(OnFloat, bool(int, double));
-  MOCK_METHOD3(OnBinary, bool(int, const uint8*, int));
+  MOCK_METHOD3(OnBinary, bool(int, const uint8_t*, int));
   MOCK_METHOD2(OnString, bool(int, const std::string&));
 };
 
@@ -41,7 +41,7 @@
   cb.SetClusterTimecode(0);
 
   for (int i = 0; i < block_count; i++) {
-    uint8 data[] = { 0x00 };
+    uint8_t data[] = {0x00};
     cb.AddSimpleBlock(0, i, 0, data, sizeof(data));
   }
 
@@ -67,8 +67,8 @@
 }
 
 TEST_F(WebMParserTest, EmptyCluster) {
-  const uint8 kEmptyCluster[] = {
-    0x1F, 0x43, 0xB6, 0x75, 0x80  // CLUSTER (size = 0)
+  const uint8_t kEmptyCluster[] = {
+      0x1F, 0x43, 0xB6, 0x75, 0x80  // CLUSTER (size = 0)
   };
   int size = sizeof(kEmptyCluster);
 
@@ -82,9 +82,9 @@
 }
 
 TEST_F(WebMParserTest, EmptyClusterInSegment) {
-  const uint8 kBuffer[] = {
-    0x18, 0x53, 0x80, 0x67, 0x85,  // SEGMENT (size = 5)
-    0x1F, 0x43, 0xB6, 0x75, 0x80,  // CLUSTER (size = 0)
+  const uint8_t kBuffer[] = {
+      0x18, 0x53, 0x80, 0x67, 0x85,  // SEGMENT (size = 5)
+      0x1F, 0x43, 0xB6, 0x75, 0x80,  // CLUSTER (size = 0)
   };
   int size = sizeof(kBuffer);
 
@@ -102,9 +102,9 @@
 // Test the case where a non-list child element has a size
 // that is beyond the end of the parent.
 TEST_F(WebMParserTest, ChildNonListLargerThanParent) {
-  const uint8 kBuffer[] = {
-    0x1F, 0x43, 0xB6, 0x75, 0x81,  // CLUSTER (size = 1)
-    0xE7, 0x81, 0x01,  // Timecode (size=1, value=1)
+  const uint8_t kBuffer[] = {
+      0x1F, 0x43, 0xB6, 0x75, 0x81,  // CLUSTER (size = 1)
+      0xE7, 0x81, 0x01,              // Timecode (size=1, value=1)
   };
 
   InSequence s;
@@ -118,9 +118,10 @@
 // Test the case where a list child element has a size
 // that is beyond the end of the parent.
 TEST_F(WebMParserTest, ChildListLargerThanParent) {
-  const uint8 kBuffer[] = {
-    0x18, 0x53, 0x80, 0x67, 0x85,  // SEGMENT (size = 5)
-    0x1F, 0x43, 0xB6, 0x75, 0x81, 0x11  // CLUSTER (size = 1)
+  const uint8_t kBuffer[] = {
+      0x18, 0x53, 0x80, 0x67, 0x85,  // SEGMENT (size = 5)
+      0x1F, 0x43, 0xB6, 0x75, 0x81,
+      0x11  // CLUSTER (size = 1)
   };
 
   InSequence s;
@@ -133,8 +134,8 @@
 
 // Expecting to parse a Cluster, but get a Segment.
 TEST_F(WebMParserTest, ListIdDoesNotMatch) {
-  const uint8 kBuffer[] = {
-    0x18, 0x53, 0x80, 0x67, 0x80,  // SEGMENT (size = 0)
+  const uint8_t kBuffer[] = {
+      0x18, 0x53, 0x80, 0x67, 0x80,  // SEGMENT (size = 0)
   };
 
   WebMListParser parser(kWebMIdCluster, &client_);
@@ -143,9 +144,9 @@
 }
 
 TEST_F(WebMParserTest, InvalidElementInList) {
-  const uint8 kBuffer[] = {
-    0x18, 0x53, 0x80, 0x67, 0x82,  // SEGMENT (size = 2)
-    0xAE, 0x80,  // TrackEntry (size = 0)
+  const uint8_t kBuffer[] = {
+      0x18, 0x53, 0x80, 0x67, 0x82,  // SEGMENT (size = 2)
+      0xAE, 0x80,                    // TrackEntry (size = 0)
   };
 
   InSequence s;
@@ -159,9 +160,9 @@
 // Test specific case of InvalidElementInList to verify EBMLHEADER within
 // known-sized cluster causes parse error.
 TEST_F(WebMParserTest, InvalidEBMLHeaderInCluster) {
-  const uint8 kBuffer[] = {
-    0x1F, 0x43, 0xB6, 0x75, 0x85,  // CLUSTER (size = 5)
-    0x1A, 0x45, 0xDF, 0xA3, 0x80,    // EBMLHEADER (size = 0)
+  const uint8_t kBuffer[] = {
+      0x1F, 0x43, 0xB6, 0x75, 0x85,  // CLUSTER (size = 5)
+      0x1A, 0x45, 0xDF, 0xA3, 0x80,  // EBMLHEADER (size = 0)
   };
 
   InSequence s;
@@ -174,9 +175,11 @@
 
 // Verify that EBMLHEADER ends a preceding "unknown"-sized CLUSTER.
 TEST_F(WebMParserTest, UnknownSizeClusterFollowedByEBMLHeader) {
-  const uint8 kBuffer[] = {
-    0x1F, 0x43, 0xB6, 0x75, 0xFF,  // CLUSTER (size = unknown; really 0 due to:)
-    0x1A, 0x45, 0xDF, 0xA3, 0x80,  // EBMLHEADER (size = 0)
+  const uint8_t kBuffer[] = {
+      0x1F, 0x43, 0xB6,
+      0x75, 0xFF,  // CLUSTER (size = unknown; really 0 due to:)
+      0x1A, 0x45, 0xDF,
+      0xA3, 0x80,  // EBMLHEADER (size = 0)
   };
 
   InSequence s;
@@ -191,13 +194,13 @@
 }
 
 TEST_F(WebMParserTest, VoidAndCRC32InList) {
-  const uint8 kBuffer[] = {
-    0x18, 0x53, 0x80, 0x67, 0x99,  // SEGMENT (size = 25)
-    0xEC, 0x83, 0x00, 0x00, 0x00,  // Void (size = 3)
-    0xBF, 0x83, 0x00, 0x00, 0x00,  // CRC32 (size = 3)
-    0x1F, 0x43, 0xB6, 0x75, 0x8A,  // CLUSTER (size = 10)
-    0xEC, 0x83, 0x00, 0x00, 0x00,  // Void (size = 3)
-    0xBF, 0x83, 0x00, 0x00, 0x00,  // CRC32 (size = 3)
+  const uint8_t kBuffer[] = {
+      0x18, 0x53, 0x80, 0x67, 0x99,  // SEGMENT (size = 25)
+      0xEC, 0x83, 0x00, 0x00, 0x00,  // Void (size = 3)
+      0xBF, 0x83, 0x00, 0x00, 0x00,  // CRC32 (size = 3)
+      0x1F, 0x43, 0xB6, 0x75, 0x8A,  // CLUSTER (size = 10)
+      0xEC, 0x83, 0x00, 0x00, 0x00,  // Void (size = 3)
+      0xBF, 0x83, 0x00, 0x00, 0x00,  // CRC32 (size = 3)
   };
   int size = sizeof(kBuffer);
 
@@ -226,7 +229,7 @@
   scoped_ptr<Cluster> cluster(CreateCluster(kBlockCount));
   CreateClusterExpectations(kBlockCount, true, &client_);
 
-  const uint8* data = cluster->data();
+  const uint8_t* data = cluster->data();
   int size = cluster->size();
   int default_parse_size = 3;
   WebMListParser parser(kWebMIdCluster, &client_);
@@ -283,13 +286,13 @@
 
 // Test the case where multiple clients are used for different lists.
 TEST_F(WebMParserTest, MultipleClients) {
-  const uint8 kBuffer[] = {
-    0x18, 0x53, 0x80, 0x67, 0x94,  // SEGMENT (size = 20)
-    0x16, 0x54, 0xAE, 0x6B, 0x85,  //   TRACKS (size = 5)
-    0xAE, 0x83,                    //     TRACKENTRY (size = 3)
-    0xD7, 0x81, 0x01,              //       TRACKNUMBER (size = 1)
-    0x1F, 0x43, 0xB6, 0x75, 0x85,  //   CLUSTER (size = 5)
-    0xEC, 0x83, 0x00, 0x00, 0x00,  //     Void (size = 3)
+  const uint8_t kBuffer[] = {
+      0x18, 0x53, 0x80, 0x67, 0x94,  // SEGMENT (size = 20)
+      0x16, 0x54, 0xAE, 0x6B, 0x85,  //   TRACKS (size = 5)
+      0xAE, 0x83,                    //     TRACKENTRY (size = 3)
+      0xD7, 0x81, 0x01,              //       TRACKNUMBER (size = 1)
+      0x1F, 0x43, 0xB6, 0x75, 0x85,  //   CLUSTER (size = 5)
+      0xEC, 0x83, 0x00, 0x00, 0x00,  //     Void (size = 3)
   };
   int size = sizeof(kBuffer);
 
@@ -315,9 +318,9 @@
 
 // Test the case where multiple clients are used for different lists.
 TEST_F(WebMParserTest, InvalidClient) {
-  const uint8 kBuffer[] = {
-    0x18, 0x53, 0x80, 0x67, 0x85,  // SEGMENT (size = 20)
-    0x16, 0x54, 0xAE, 0x6B, 0x80,  //   TRACKS (size = 5)
+  const uint8_t kBuffer[] = {
+      0x18, 0x53, 0x80, 0x67, 0x85,  // SEGMENT (size = 20)
+      0x16, 0x54, 0xAE, 0x6B, 0x80,  //   TRACKS (size = 5)
   };
 
   InSequence s;
@@ -329,20 +332,16 @@
 }
 
 TEST_F(WebMParserTest, ReservedIds) {
-  const uint8 k1ByteReservedId[] = { 0xFF, 0x81 };
-  const uint8 k2ByteReservedId[] = { 0x7F, 0xFF, 0x81 };
-  const uint8 k3ByteReservedId[] = { 0x3F, 0xFF, 0xFF, 0x81 };
-  const uint8 k4ByteReservedId[] = { 0x1F, 0xFF, 0xFF, 0xFF, 0x81 };
-  const uint8* kBuffers[] = {
-    k1ByteReservedId,
-    k2ByteReservedId,
-    k3ByteReservedId,
-    k4ByteReservedId
-  };
+  const uint8_t k1ByteReservedId[] = {0xFF, 0x81};
+  const uint8_t k2ByteReservedId[] = {0x7F, 0xFF, 0x81};
+  const uint8_t k3ByteReservedId[] = {0x3F, 0xFF, 0xFF, 0x81};
+  const uint8_t k4ByteReservedId[] = {0x1F, 0xFF, 0xFF, 0xFF, 0x81};
+  const uint8_t* kBuffers[] = {k1ByteReservedId, k2ByteReservedId,
+                               k3ByteReservedId, k4ByteReservedId};
 
   for (size_t i = 0; i < arraysize(kBuffers); i++) {
     int id;
-    int64 element_size;
+    int64_t element_size;
     int buffer_size = 2 + i;
     EXPECT_EQ(buffer_size, WebMParseElementHeader(kBuffers[i], buffer_size,
                                                   &id, &element_size));
@@ -352,31 +351,25 @@
 }
 
 TEST_F(WebMParserTest, ReservedSizes) {
-  const uint8 k1ByteReservedSize[] = { 0xA3, 0xFF };
-  const uint8 k2ByteReservedSize[] = { 0xA3, 0x7F, 0xFF };
-  const uint8 k3ByteReservedSize[] = { 0xA3, 0x3F, 0xFF, 0xFF };
-  const uint8 k4ByteReservedSize[] = { 0xA3, 0x1F, 0xFF, 0xFF, 0xFF };
-  const uint8 k5ByteReservedSize[] = { 0xA3, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF };
-  const uint8 k6ByteReservedSize[] = { 0xA3, 0x07, 0xFF, 0xFF, 0xFF, 0xFF,
-                                       0xFF };
-  const uint8 k7ByteReservedSize[] = { 0xA3, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-                                       0xFF };
-  const uint8 k8ByteReservedSize[] = { 0xA3, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-                                       0xFF, 0xFF };
-  const uint8* kBuffers[] = {
-    k1ByteReservedSize,
-    k2ByteReservedSize,
-    k3ByteReservedSize,
-    k4ByteReservedSize,
-    k5ByteReservedSize,
-    k6ByteReservedSize,
-    k7ByteReservedSize,
-    k8ByteReservedSize
-  };
+  const uint8_t k1ByteReservedSize[] = {0xA3, 0xFF};
+  const uint8_t k2ByteReservedSize[] = {0xA3, 0x7F, 0xFF};
+  const uint8_t k3ByteReservedSize[] = {0xA3, 0x3F, 0xFF, 0xFF};
+  const uint8_t k4ByteReservedSize[] = {0xA3, 0x1F, 0xFF, 0xFF, 0xFF};
+  const uint8_t k5ByteReservedSize[] = {0xA3, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF};
+  const uint8_t k6ByteReservedSize[] = {0xA3, 0x07, 0xFF, 0xFF,
+                                        0xFF, 0xFF, 0xFF};
+  const uint8_t k7ByteReservedSize[] = {0xA3, 0x03, 0xFF, 0xFF,
+                                        0xFF, 0xFF, 0xFF, 0xFF};
+  const uint8_t k8ByteReservedSize[] = {0xA3, 0x01, 0xFF, 0xFF, 0xFF,
+                                        0xFF, 0xFF, 0xFF, 0xFF};
+  const uint8_t* kBuffers[] = {k1ByteReservedSize, k2ByteReservedSize,
+                               k3ByteReservedSize, k4ByteReservedSize,
+                               k5ByteReservedSize, k6ByteReservedSize,
+                               k7ByteReservedSize, k8ByteReservedSize};
 
   for (size_t i = 0; i < arraysize(kBuffers); i++) {
     int id;
-    int64 element_size;
+    int64_t element_size;
     int buffer_size = 2 + i;
     EXPECT_EQ(buffer_size, WebMParseElementHeader(kBuffers[i], buffer_size,
                                                   &id, &element_size));
@@ -386,12 +379,13 @@
 }
 
 TEST_F(WebMParserTest, ZeroPaddedStrings) {
-  const uint8 kBuffer[] = {
-    0x1A, 0x45, 0xDF, 0xA3, 0x91,  // EBMLHEADER (size = 17)
-    0x42, 0x82, 0x80,  // DocType (size = 0)
-    0x42, 0x82, 0x81, 0x00,  // DocType (size = 1) ""
-    0x42, 0x82, 0x81, 'a',  // DocType (size = 1) "a"
-    0x42, 0x82, 0x83, 'a', 0x00, 0x00  // DocType (size = 3) "a"
+  const uint8_t kBuffer[] = {
+      0x1A, 0x45, 0xDF, 0xA3, 0x91,  // EBMLHEADER (size = 17)
+      0x42, 0x82, 0x80,              // DocType (size = 0)
+      0x42, 0x82, 0x81, 0x00,        // DocType (size = 1) ""
+      0x42, 0x82, 0x81, 'a',         // DocType (size = 1) "a"
+      0x42, 0x82, 0x83, 'a',  0x00,
+      0x00  // DocType (size = 3) "a"
   };
   int size = sizeof(kBuffer);
 
diff --git a/media/media.gyp b/media/media.gyp
index 67cbe5d..18297a4 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -131,6 +131,8 @@
         'audio/audio_power_monitor.cc',
         'audio/audio_power_monitor.h',
         'audio/audio_source_diverter.h',
+        'audio/audio_streams_tracker.cc',
+        'audio/audio_streams_tracker.h',
         'audio/clockless_audio_sink.cc',
         'audio/clockless_audio_sink.h',
         'audio/cras/audio_manager_cras.cc',
@@ -1507,6 +1509,7 @@
           'audio/audio_output_proxy_unittest.cc',
           'audio/audio_parameters_unittest.cc',
           'audio/audio_power_monitor_unittest.cc',
+          'audio/audio_streams_tracker_unittest.cc',
           'audio/fake_audio_worker_unittest.cc',
           'audio/point_unittest.cc',
           'audio/simple_sources_unittest.cc',
diff --git a/media/mojo/interfaces/decryptor.mojom b/media/mojo/interfaces/decryptor.mojom
index e25df3e..dad3d68 100644
--- a/media/mojo/interfaces/decryptor.mojom
+++ b/media/mojo/interfaces/decryptor.mojom
@@ -61,9 +61,3 @@
   // The decoder can be reinitialized after it is deinitialized.
   DeinitializeDecoder(DemuxerStream.Type stream_type);
 };
-
-interface DecryptorClient {
-  // Indicates that a new usable key is available in the CDM associated with the
-  // Decryptor.
-  OnNewUsableKey();
-};
diff --git a/media/mojo/services/BUILD.gn b/media/mojo/services/BUILD.gn
index 8275e256..0be1d70 100644
--- a/media/mojo/services/BUILD.gn
+++ b/media/mojo/services/BUILD.gn
@@ -55,6 +55,8 @@
     "mojo_cdm.h",
     "mojo_cdm_factory.cc",
     "mojo_cdm_factory.h",
+    "mojo_decryptor.cc",
+    "mojo_decryptor.h",
     "mojo_demuxer_stream_impl.cc",
     "mojo_demuxer_stream_impl.h",
     "mojo_renderer_factory.cc",
diff --git a/media/mojo/services/media_type_converters.cc b/media/mojo/services/media_type_converters.cc
index a4a9ead..1f2f0d68 100644
--- a/media/mojo/services/media_type_converters.cc
+++ b/media/mojo/services/media_type_converters.cc
@@ -11,6 +11,7 @@
 #include "media/base/cdm_key_information.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/decrypt_config.h"
+#include "media/base/decryptor.h"
 #include "media/base/demuxer_stream.h"
 #include "media/base/media_keys.h"
 #include "media/base/video_decoder_config.h"
@@ -226,6 +227,20 @@
                VIDEO_CODEC_PROFILE_,
                VIDEO_CODEC_PROFILE_MAX);
 
+// Decryptor Status
+ASSERT_ENUM_EQ_RAW(Decryptor::Status,
+                   Decryptor::kSuccess,
+                   Decryptor::STATUS_SUCCESS);
+ASSERT_ENUM_EQ_RAW(Decryptor::Status,
+                   Decryptor::kNoKey,
+                   Decryptor::STATUS_NO_KEY);
+ASSERT_ENUM_EQ_RAW(Decryptor::Status,
+                   Decryptor::kNeedMoreData,
+                   Decryptor::STATUS_NEED_MORE_DATA);
+ASSERT_ENUM_EQ_RAW(Decryptor::Status,
+                   Decryptor::kError,
+                   Decryptor::STATUS_ERROR);
+
 // CdmException
 #define ASSERT_CDM_EXCEPTION(value)                                \
   static_assert(media::MediaKeys::value ==                         \
diff --git a/media/mojo/services/mojo_cdm.cc b/media/mojo/services/mojo_cdm.cc
index e302887a..be5a9ce 100644
--- a/media/mojo/services/mojo_cdm.cc
+++ b/media/mojo/services/mojo_cdm.cc
@@ -13,6 +13,7 @@
 #include "media/base/cdm_promise.h"
 #include "media/mojo/interfaces/decryptor.mojom.h"
 #include "media/mojo/services/media_type_converters.h"
+#include "media/mojo/services/mojo_decryptor.h"
 #include "mojo/application/public/cpp/connect.h"
 #include "mojo/application/public/interfaces/service_provider.mojom.h"
 #include "url/gurl.h"
@@ -163,8 +164,12 @@
 }
 
 media::Decryptor* MojoCdm::GetDecryptor() {
-  // TODO(jrummell): Return a decryptor using |decryptor_ptr_|.
-  return nullptr;
+  if (decryptor_ptr_) {
+    DCHECK(!decryptor_);
+    decryptor_.reset(new MojoDecryptor(std::move(decryptor_ptr_)));
+  }
+
+  return decryptor_.get();
 }
 
 int MojoCdm::GetCdmId() const {
@@ -209,6 +214,12 @@
     bool has_additional_usable_key,
     mojo::Array<interfaces::CdmKeyInformationPtr> keys_info) {
   DVLOG(2) << __FUNCTION__;
+
+  // TODO(jrummell): Handling resume playback should be done in the media
+  // player, not in the Decryptors. http://crbug.com/413413.
+  if (has_additional_usable_key && decryptor_)
+    decryptor_->OnKeyAdded();
+
   media::CdmKeysInfo key_data;
   key_data.reserve(keys_info.size());
   for (size_t i = 0; i < keys_info.size(); ++i) {
diff --git a/media/mojo/services/mojo_cdm.h b/media/mojo/services/mojo_cdm.h
index dc82ed2..2774e56 100644
--- a/media/mojo/services/mojo_cdm.h
+++ b/media/mojo/services/mojo_cdm.h
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "media/base/cdm_context.h"
 #include "media/base/cdm_initialized_promise.h"
@@ -22,6 +23,8 @@
 
 namespace media {
 
+class MojoDecryptor;
+
 // A MediaKeys that proxies to a interfaces::ContentDecryptionModule. That
 // interfaces::ContentDecryptionModule proxies back to the MojoCdm via the
 // interfaces::ContentDecryptionModuleClient interface.
@@ -123,7 +126,10 @@
   mojo::Binding<ContentDecryptionModuleClient> binding_;
   int cdm_id_;
 
+  // Keep track of the DecryptorPtr in order to do lazy initialization of
+  // MojoDecryptor.
   interfaces::DecryptorPtr decryptor_ptr_;
+  scoped_ptr<MojoDecryptor> decryptor_;
 
   // Callbacks for firing session events.
   SessionMessageCB session_message_cb_;
diff --git a/media/mojo/services/mojo_cdm_service.cc b/media/mojo/services/mojo_cdm_service.cc
index f41708f..a7d5fc5 100644
--- a/media/mojo/services/mojo_cdm_service.cc
+++ b/media/mojo/services/mojo_cdm_service.cc
@@ -241,6 +241,7 @@
                                          bool has_additional_usable_key,
                                          CdmKeysInfo keys_info) {
   DVLOG(2) << __FUNCTION__;
+
   mojo::Array<interfaces::CdmKeyInformationPtr> keys_data;
   for (const auto& key : keys_info)
     keys_data.push_back(interfaces::CdmKeyInformation::From(*key));
diff --git a/media/mojo/services/mojo_decryptor.cc b/media/mojo/services/mojo_decryptor.cc
new file mode 100644
index 0000000..74af5cf
--- /dev/null
+++ b/media/mojo/services/mojo_decryptor.cc
@@ -0,0 +1,126 @@
+// 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/mojo/services/mojo_decryptor.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "media/base/audio_buffer.h"
+#include "media/base/decoder_buffer.h"
+#include "media/base/video_frame.h"
+#include "media/mojo/interfaces/decryptor.mojom.h"
+#include "media/mojo/services/media_type_converters.h"
+#include "mojo/application/public/cpp/connect.h"
+
+namespace media {
+
+MojoDecryptor::MojoDecryptor(interfaces::DecryptorPtr remote_decryptor)
+    : remote_decryptor_(std::move(remote_decryptor)), weak_factory_(this) {}
+
+MojoDecryptor::~MojoDecryptor() {}
+
+void MojoDecryptor::RegisterNewKeyCB(StreamType stream_type,
+                                     const NewKeyCB& key_added_cb) {
+  switch (stream_type) {
+    case kAudio:
+      new_audio_key_cb_ = key_added_cb;
+      break;
+    case kVideo:
+      new_video_key_cb_ = key_added_cb;
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+void MojoDecryptor::Decrypt(StreamType stream_type,
+                            const scoped_refptr<DecoderBuffer>& encrypted,
+                            const DecryptCB& decrypt_cb) {
+  remote_decryptor_->Decrypt(
+      static_cast<interfaces::DemuxerStream::Type>(stream_type),
+      interfaces::DecoderBuffer::From(encrypted),
+      base::Bind(&MojoDecryptor::OnBufferDecrypted, weak_factory_.GetWeakPtr(),
+                 decrypt_cb));
+}
+
+void MojoDecryptor::CancelDecrypt(StreamType stream_type) {
+  remote_decryptor_->CancelDecrypt(
+      static_cast<interfaces::DemuxerStream::Type>(stream_type));
+}
+
+void MojoDecryptor::InitializeAudioDecoder(const AudioDecoderConfig& config,
+                                           const DecoderInitCB& init_cb) {
+  remote_decryptor_->InitializeAudioDecoder(
+      interfaces::AudioDecoderConfig::From(config), init_cb);
+}
+
+void MojoDecryptor::InitializeVideoDecoder(const VideoDecoderConfig& config,
+                                           const DecoderInitCB& init_cb) {
+  remote_decryptor_->InitializeVideoDecoder(
+      interfaces::VideoDecoderConfig::From(config), init_cb);
+}
+
+void MojoDecryptor::DecryptAndDecodeAudio(
+    const scoped_refptr<DecoderBuffer>& encrypted,
+    const AudioDecodeCB& audio_decode_cb) {
+  remote_decryptor_->DecryptAndDecodeAudio(
+      interfaces::DecoderBuffer::From(encrypted),
+      base::Bind(&MojoDecryptor::OnAudioDecoded, weak_factory_.GetWeakPtr(),
+                 audio_decode_cb));
+}
+
+void MojoDecryptor::DecryptAndDecodeVideo(
+    const scoped_refptr<DecoderBuffer>& encrypted,
+    const VideoDecodeCB& video_decode_cb) {
+  remote_decryptor_->DecryptAndDecodeVideo(
+      interfaces::DecoderBuffer::From(encrypted),
+      base::Bind(&MojoDecryptor::OnVideoDecoded, weak_factory_.GetWeakPtr(),
+                 video_decode_cb));
+}
+
+void MojoDecryptor::ResetDecoder(StreamType stream_type) {
+  remote_decryptor_->ResetDecoder(
+      static_cast<interfaces::DemuxerStream::Type>(stream_type));
+}
+
+void MojoDecryptor::DeinitializeDecoder(StreamType stream_type) {
+  remote_decryptor_->DeinitializeDecoder(
+      static_cast<interfaces::DemuxerStream::Type>(stream_type));
+}
+
+void MojoDecryptor::OnKeyAdded() {
+  if (!new_audio_key_cb_.is_null())
+    new_audio_key_cb_.Run();
+
+  if (!new_video_key_cb_.is_null())
+    new_video_key_cb_.Run();
+}
+
+void MojoDecryptor::OnBufferDecrypted(const DecryptCB& decrypt_cb,
+                                      interfaces::Decryptor::Status status,
+                                      interfaces::DecoderBufferPtr buffer) {
+  decrypt_cb.Run(static_cast<Decryptor::Status>(status),
+                 std::move(buffer.To<scoped_refptr<DecoderBuffer>>()));
+}
+
+void MojoDecryptor::OnAudioDecoded(
+    const AudioDecodeCB& audio_decode_cb,
+    interfaces::Decryptor::Status status,
+    mojo::Array<interfaces::AudioBufferPtr> audio_buffers) {
+  Decryptor::AudioFrames audio_frames;
+  for (size_t i = 0; i < audio_buffers.size(); ++i)
+    audio_frames.push_back(audio_buffers[i].To<scoped_refptr<AudioBuffer>>());
+
+  audio_decode_cb.Run(static_cast<Decryptor::Status>(status), audio_frames);
+}
+
+void MojoDecryptor::OnVideoDecoded(const VideoDecodeCB& video_decode_cb,
+                                   interfaces::Decryptor::Status status,
+                                   interfaces::VideoFramePtr video_frame) {
+  video_decode_cb.Run(static_cast<Decryptor::Status>(status),
+                      std::move(video_frame.To<scoped_refptr<VideoFrame>>()));
+}
+
+}  // namespace media
diff --git a/media/mojo/services/mojo_decryptor.h b/media/mojo/services/mojo_decryptor.h
new file mode 100644
index 0000000..9933658
--- /dev/null
+++ b/media/mojo/services/mojo_decryptor.h
@@ -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.
+
+#ifndef MEDIA_MOJO_SERVICES_MOJO_DECRYPTOR_H_
+#define MEDIA_MOJO_SERVICES_MOJO_DECRYPTOR_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "media/base/decryptor.h"
+#include "media/mojo/interfaces/decryptor.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace media {
+
+class MojoDecryptor : public Decryptor {
+ public:
+  explicit MojoDecryptor(interfaces::DecryptorPtr remote_decryptor);
+  ~MojoDecryptor() final;
+
+  // Decryptor implementation.
+  void RegisterNewKeyCB(StreamType stream_type,
+                        const NewKeyCB& key_added_cb) final;
+  void Decrypt(StreamType stream_type,
+               const scoped_refptr<DecoderBuffer>& encrypted,
+               const DecryptCB& decrypt_cb) final;
+  void CancelDecrypt(StreamType stream_type) final;
+  void InitializeAudioDecoder(const AudioDecoderConfig& config,
+                              const DecoderInitCB& init_cb) final;
+  void InitializeVideoDecoder(const VideoDecoderConfig& config,
+                              const DecoderInitCB& init_cb) final;
+  void DecryptAndDecodeAudio(const scoped_refptr<DecoderBuffer>& encrypted,
+                             const AudioDecodeCB& audio_decode_cb) final;
+  void DecryptAndDecodeVideo(const scoped_refptr<DecoderBuffer>& encrypted,
+                             const VideoDecodeCB& video_decode_cb) final;
+  void ResetDecoder(StreamType stream_type) final;
+  void DeinitializeDecoder(StreamType stream_type) final;
+
+  // Called when keys have changed and an additional key is available.
+  void OnKeyAdded();
+
+ private:
+  // Called when a buffer is decrypted.
+  void OnBufferDecrypted(const DecryptCB& decrypt_cb,
+                         interfaces::Decryptor::Status status,
+                         interfaces::DecoderBufferPtr buffer);
+  void OnAudioDecoded(const AudioDecodeCB& audio_decode_cb,
+                      interfaces::Decryptor::Status status,
+                      mojo::Array<interfaces::AudioBufferPtr> audio_buffers);
+  void OnVideoDecoded(const VideoDecodeCB& video_decode_cb,
+                      interfaces::Decryptor::Status status,
+                      interfaces::VideoFramePtr video_frame);
+
+  interfaces::DecryptorPtr remote_decryptor_;
+
+  NewKeyCB new_audio_key_cb_;
+  NewKeyCB new_video_key_cb_;
+
+  base::WeakPtrFactory<MojoDecryptor> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(MojoDecryptor);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_MOJO_SERVICES_MOJO_DECRYPTOR_H_
diff --git a/media/renderers/skcanvas_video_renderer.cc b/media/renderers/skcanvas_video_renderer.cc
index aa9321a..ec093da 100644
--- a/media/renderers/skcanvas_video_renderer.cc
+++ b/media/renderers/skcanvas_video_renderer.cc
@@ -4,6 +4,8 @@
 
 #include "media/renderers/skcanvas_video_renderer.h"
 
+#include <limits>
+
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "gpu/command_buffer/common/mailbox_holder.h"
@@ -119,8 +121,15 @@
       source_textures[i] = texture_copy;
     }
   }
-  GrBackendObject handles[3] = {source_textures[0], source_textures[1],
-                                source_textures[2]};
+  DCHECK_LE(source_textures[0],
+            static_cast<unsigned>(std::numeric_limits<int>::max()));
+  DCHECK_LE(source_textures[1],
+            static_cast<unsigned>(std::numeric_limits<int>::max()));
+  DCHECK_LE(source_textures[2],
+            static_cast<unsigned>(std::numeric_limits<int>::max()));
+  GrBackendObject handles[3] = {static_cast<int>(source_textures[0]),
+                                static_cast<int>(source_textures[1]),
+                                static_cast<int>(source_textures[2])};
 
   SkISize yuvSizes[] = {
       {ya_tex_size.width(), ya_tex_size.height()},
@@ -180,7 +189,9 @@
   desc.fWidth = video_frame->coded_size().width();
   desc.fHeight = video_frame->coded_size().height();
   desc.fConfig = kRGBA_8888_GrPixelConfig;
-  desc.fTextureHandle = source_texture;
+  DCHECK_LE(source_texture,
+            static_cast<unsigned>(std::numeric_limits<int>::max()));
+  desc.fTextureHandle = static_cast<int>(source_texture);
   return skia::AdoptRef(
       SkImage::NewFromAdoptedTexture(context_3d.gr_context, desc));
 }
diff --git a/mojo/BUILD.gn b/mojo/BUILD.gn
index 72f8e8f..34e9bf2 100644
--- a/mojo/BUILD.gn
+++ b/mojo/BUILD.gn
@@ -74,9 +74,10 @@
     "//mojo/application/public/cpp/tests:mojo_public_application_unittests",
     "//mojo/common:mojo_common_unittests",
     "//mojo/converters/surfaces/tests:mojo_surfaces_lib_unittests",
+    "//mojo/edk/js/test:js_unittests",
 
     # TODO(use_chrome_edk):
-    #"//mojo/edk/js/test:js_unittests",
+    #"//mojo/edk/js/test:js_integration_tests2",
     #"//mojo/edk/system:mojo_message_pipe_perftests",
     #"//mojo/edk/system:mojo_system_unittests",
     #"//mojo/edk/test:mojo_public_bindings_unittests",
@@ -84,7 +85,6 @@
     #"//mojo/edk/test:mojo_public_system_perftests",
     #"//mojo/edk/test:mojo_public_system_unittests",
     #"//mojo/edk/test:mojo_public_utility_unittests",
-    "//third_party/mojo/src/mojo/edk/js/test:js_unittests",
     "//third_party/mojo/src/mojo/edk/system:mojo_message_pipe_perftests",
     "//third_party/mojo/src/mojo/edk/system:mojo_system_unittests",
     "//third_party/mojo/src/mojo/edk/test:mojo_public_bindings_unittests",
diff --git a/mojo/application/public/interfaces/application_manager.mojom b/mojo/application/public/interfaces/application_manager.mojom
index 43edc81..7069d2e 100644
--- a/mojo/application/public/interfaces/application_manager.mojom
+++ b/mojo/application/public/interfaces/application_manager.mojom
@@ -15,4 +15,10 @@
   CreateInstanceForHandle(handle channel,
                           string url,
                           mojo.CapabilityFilter filter);
+
+  // Called by a child process every time it launches a process. This is needed
+  // so that the ChildBroker class in the grandchild process can talk to the one
+  // global BrokerState in the parent mojo_runner process.
+  RegisterProcessWithBroker(uint32 pid,
+                            handle pipe);
 };
diff --git a/mojo/converters/surfaces/surfaces_type_converters.cc b/mojo/converters/surfaces/surfaces_type_converters.cc
index f0a32bd..f0944548 100644
--- a/mojo/converters/surfaces/surfaces_type_converters.cc
+++ b/mojo/converters/surfaces/surfaces_type_converters.cc
@@ -547,8 +547,8 @@
     const SyncTokenPtr& input) {
   const gpu::CommandBufferNamespace namespace_id =
       static_cast<gpu::CommandBufferNamespace>(input->namespace_id);
-  gpu::SyncToken sync_token(namespace_id, input->command_buffer_id,
-                            input->release_count);
+  gpu::SyncToken sync_token(namespace_id, 0,
+                            input->command_buffer_id, input->release_count);
   if (input->verified_flush)
     sync_token.SetVerifyFlush();
 
diff --git a/mojo/edk/embedder/embedder_internal.h b/mojo/edk/embedder/embedder_internal.h
index a6fb2b1..7a0b395 100644
--- a/mojo/edk/embedder/embedder_internal.h
+++ b/mojo/edk/embedder/embedder_internal.h
@@ -38,7 +38,7 @@
 extern Core* g_core;
 extern base::TaskRunner* g_delegate_thread_task_runner;
 extern ProcessDelegate* g_process_delegate;
-extern base::TaskRunner* g_io_thread_task_runner;
+MOJO_SYSTEM_IMPL_EXPORT extern base::TaskRunner* g_io_thread_task_runner;
 
 // TODO(use_chrome_edk): temporary until we have only one SDK.
 MOJO_SYSTEM_IMPL_EXPORT Core* GetCore();
diff --git a/mojo/edk/js/BUILD.gn b/mojo/edk/js/BUILD.gn
index 50f62d9..b0c4c07 100644
--- a/mojo/edk/js/BUILD.gn
+++ b/mojo/edk/js/BUILD.gn
@@ -13,7 +13,7 @@
   deps = [
     # TODO(use_chrome_edk): remove "2"
     "test:js_integration_tests2",
-    "test:js_unittests2",
+    "test:js_unittests",
   ]
 }
 
@@ -47,17 +47,3 @@
     "//mojo/public/cpp/system",
   ]
 }
-
-source_set("js_unittests") {
-  testonly = true
-  sources = [
-    "handle_unittest.cc",
-  ]
-
-  deps = [
-    "//mojo/edk/js",
-    "//mojo/edk/test:test_support",
-    "//mojo/public/cpp/system",
-    "//testing/gtest",
-  ]
-}
diff --git a/mojo/edk/js/test/BUILD.gn b/mojo/edk/js/test/BUILD.gn
index e41e889a..c95260b 100644
--- a/mojo/edk/js/test/BUILD.gn
+++ b/mojo/edk/js/test/BUILD.gn
@@ -4,15 +4,15 @@
 
 import("//testing/test.gni")
 
-# TODO(use_chrome_edk): remove "2"
-test("js_unittests2") {
+test("js_unittests") {
+  output_name = "mojo_js_unittests"
+
   deps = [
-    "../../js",
-    "../../js:js_unittests",
-    "../../test:run_all_unittests",
-    "../../test:test_support",
     "//base",
     "//gin:gin_test",
+    "//mojo/edk/js",
+    "//mojo/edk/test:run_all_unittests",
+    "//mojo/edk/test:test_support",
     "//mojo/environment:chromium",
     "//mojo/public/cpp/environment",
     "//mojo/public/cpp/system",
diff --git a/mojo/edk/system/BUILD.gn b/mojo/edk/system/BUILD.gn
index 54e3e3e..072fc4f9 100644
--- a/mojo/edk/system/BUILD.gn
+++ b/mojo/edk/system/BUILD.gn
@@ -159,7 +159,6 @@
     "options_validation_unittest.cc",
     "platform_handle_dispatcher_unittest.cc",
     "raw_channel_unittest.cc",
-    "run_all_unittests.cc",
     "shared_buffer_dispatcher_unittest.cc",
     "simple_dispatcher_unittest.cc",
     "waiter_test_utils.cc",
@@ -168,6 +167,7 @@
   ]
 
   deps = [
+    ":system",
     ":test_utils",
 
     # TODO(use_chrome_edk): remove "2"
@@ -176,6 +176,7 @@
     "../test:test_support",
     "//base",
     "//base/test:test_support",
+    "//mojo/edk/test:run_all_unittests",
     "//testing/gtest",
 
     # TODO(use_chrome_edk): temporary since the Mojo wrapper primitives are
diff --git a/mojo/edk/system/child_broker.cc b/mojo/edk/system/child_broker.cc
index fbfeb3d..31bae43a 100644
--- a/mojo/edk/system/child_broker.cc
+++ b/mojo/edk/system/child_broker.cc
@@ -38,24 +38,21 @@
                      sizeof(parent_handle), &bytes_read, NULL);
   CHECK(rv);
   parent_async_channel_handle.reset(PlatformHandle(parent_handle));
+  sync_channel_lock_.Unlock();
 #endif
 
-  parent_async_channel_ =
-      RawChannel::Create(parent_async_channel_handle.Pass());
   internal::g_io_thread_task_runner->PostTask(
       FROM_HERE,
-      base::Bind(&RawChannel::Init, base::Unretained(parent_async_channel_),
-                 this));
-
-  lock_.Unlock();
+      base::Bind(&ChildBroker::InitAsyncChannel, base::Unretained(this),
+                 base::Passed(&parent_async_channel_handle)));
 }
 
 #if defined(OS_WIN)
 void ChildBroker::CreatePlatformChannelPair(
     ScopedPlatformHandle* server, ScopedPlatformHandle* client) {
-  lock_.Lock();
+  sync_channel_lock_.Lock();
   CreatePlatformChannelPairNoLock(server, client);
-  lock_.Unlock();
+  sync_channel_lock_.Unlock();
 }
 
 void ChildBroker::HandleToToken(const PlatformHandle* platform_handles,
@@ -71,9 +68,9 @@
     message->handles[i] = platform_handles[i].handle;
 
   uint32_t response_size = static_cast<int>(count) * sizeof(uint64_t);
-  lock_.Lock();
+  sync_channel_lock_.Lock();
   WriteAndReadResponse(message, tokens, response_size);
-  lock_.Unlock();
+  sync_channel_lock_.Unlock();
 }
 
 void ChildBroker::TokenToHandle(const uint64_t* tokens,
@@ -91,11 +88,11 @@
   std::vector<HANDLE> handles_temp(count);
   uint32_t response_size =
       static_cast<uint32_t>(handles_temp.size()) * sizeof(HANDLE);
-  lock_.Lock();
+  sync_channel_lock_.Lock();
   if (WriteAndReadResponse(message, &handles_temp[0], response_size)) {
     for (uint32_t i = 0; i < count; ++i)
       handles[i].handle = handles_temp[i];
-  lock_.Unlock();
+    sync_channel_lock_.Unlock();
   }
 }
 #endif
@@ -103,11 +100,19 @@
 void ChildBroker::ConnectMessagePipe(uint64_t pipe_id,
                                      MessagePipeDispatcher* message_pipe) {
   DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
-  lock_.Lock();
 
   ConnectMessagePipeMessage data;
   data.pipe_id = pipe_id;
   if (pending_connects_.find(pipe_id) != pending_connects_.end()) {
+    if (!parent_async_channel_) {
+      // On Windows, we can't create the local RoutedRawChannel yet because we
+      // don't have parent_sync_channel_. Treat all platforms the same and just
+      // queue this.
+      CHECK(pending_inprocess_connects_.find(pipe_id) ==
+            pending_inprocess_connects_.end());
+      pending_inprocess_connects_[pipe_id] = message_pipe;
+      return;
+    }
     // Both ends of the message pipe are in the same process.
     // First, tell the browser side that to remove its bookkeeping for a pending
     // connect, since it'll never get the other side.
@@ -115,7 +120,7 @@
     data.type = CANCEL_CONNECT_MESSAGE_PIPE;
     scoped_ptr<MessageInTransit> message(new MessageInTransit(
         MessageInTransit::Type::MESSAGE, sizeof(data), &data));
-    parent_async_channel_->WriteMessage(message.Pass());
+    WriteAsyncMessage(message.Pass());
 
     if (!in_process_pipes_channel1_) {
       ScopedPlatformHandle server_handle, client_handle;
@@ -144,7 +149,6 @@
         in_process_pipes_channel2_->channel());
 
     pending_connects_.erase(pipe_id);
-    lock_.Unlock();
     return;
   }
 
@@ -152,28 +156,27 @@
   scoped_ptr<MessageInTransit> message(new MessageInTransit(
       MessageInTransit::Type::MESSAGE, sizeof(data), &data));
   pending_connects_[pipe_id] = message_pipe;
-  parent_async_channel_->WriteMessage(message.Pass());
-
-  lock_.Unlock();
+  WriteAsyncMessage(message.Pass());
 }
 
 void ChildBroker::CloseMessagePipe(
     uint64_t pipe_id, MessagePipeDispatcher* message_pipe) {
   DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
-  lock_.Lock();
   CHECK(connected_pipes_.find(message_pipe) != connected_pipes_.end());
   connected_pipes_[message_pipe]->RemoveRoute(pipe_id, message_pipe);
   connected_pipes_.erase(message_pipe);
-  lock_.Unlock();
 }
 
 ChildBroker::ChildBroker()
-    : in_process_pipes_channel1_(nullptr),
+    : parent_async_channel_(nullptr),
+      in_process_pipes_channel1_(nullptr),
       in_process_pipes_channel2_(nullptr) {
   DCHECK(!internal::g_broker);
   internal::g_broker = this;
+#if defined(OS_WIN)
   // Block any threads from calling this until we have a pipe to the parent.
-  lock_.Lock();
+  sync_channel_lock_.Lock();
+#endif
 }
 
 ChildBroker::~ChildBroker() {
@@ -183,7 +186,6 @@
     const MessageInTransit::View& message_view,
     ScopedPlatformHandleVectorPtr platform_handles) {
   DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
-  lock_.Lock();
   MultiplexMessages type =
       *static_cast<const MultiplexMessages*>(message_view.bytes());
   if (type == CONNECT_TO_PROCESS) {
@@ -221,8 +223,6 @@
   } else {
     NOTREACHED();
   }
-
-  lock_.Unlock();
 }
 
 void ChildBroker::OnError(Error error) {
@@ -231,14 +231,38 @@
 
 void ChildBroker::ChannelDestructed(RoutedRawChannel* channel) {
   DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
-  lock_.Lock();
   for (auto it : channels_) {
     if (it.second == channel) {
       channels_.erase(it.first);
       break;
     }
   }
-  lock_.Unlock();
+}
+
+void ChildBroker::WriteAsyncMessage(scoped_ptr<MessageInTransit> message) {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+  if (parent_async_channel_) {
+    parent_async_channel_->WriteMessage(message.Pass());
+  } else {
+    async_channel_queue_.AddMessage(message.Pass());
+  }
+}
+
+void ChildBroker::InitAsyncChannel(
+    ScopedPlatformHandle parent_async_channel_handle) {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+
+  parent_async_channel_ =
+      RawChannel::Create(parent_async_channel_handle.Pass());
+  parent_async_channel_->Init(this);
+  while (!async_channel_queue_.IsEmpty())
+    parent_async_channel_->WriteMessage(async_channel_queue_.GetMessage());
+
+  while (!pending_inprocess_connects_.empty()) {
+    ConnectMessagePipe(pending_inprocess_connects_.begin()->first,
+                       pending_inprocess_connects_.begin()->second);
+    pending_inprocess_connects_.erase(pending_inprocess_connects_.begin());
+  }
 }
 
 #if defined(OS_WIN)
diff --git a/mojo/edk/system/child_broker.h b/mojo/edk/system/child_broker.h
index 366daa74..c782616 100644
--- a/mojo/edk/system/child_broker.h
+++ b/mojo/edk/system/child_broker.h
@@ -13,6 +13,7 @@
 #include "base/synchronization/lock_impl.h"
 #include "mojo/edk/embedder/scoped_platform_handle.h"
 #include "mojo/edk/system/broker.h"
+#include "mojo/edk/system/message_in_transit_queue.h"
 #include "mojo/edk/system/raw_channel.h"
 #include "mojo/edk/system/system_impl_export.h"
 
@@ -64,6 +65,12 @@
   // Callback for when a RoutedRawChannel is destroyed for cleanup.
   void ChannelDestructed(RoutedRawChannel* channel);
 
+  // Sends a message over |parent_async_channel_|, queueing it if necessary.
+  void WriteAsyncMessage(scoped_ptr<MessageInTransit> message);
+
+  // Initializes |parent_async_channel_|.
+  void InitAsyncChannel(ScopedPlatformHandle parent_async_channel_handle);
+
 #if defined(OS_WIN)
   // Helper method to write the given message and read back the result.
   bool WriteAndReadResponse(BrokerMessage* message,
@@ -73,18 +80,18 @@
   void CreatePlatformChannelPairNoLock(ScopedPlatformHandle* server,
                                        ScopedPlatformHandle* client);
 
+  // Guards access to |parent_sync_channel_|.
+  // We use LockImpl instead of Lock because the latter adds thread checking
+  // that we don't want (since we lock in the constructor and unlock on another
+  // thread.
+  base::internal::LockImpl sync_channel_lock_;
+
   // Pipe used for communication to the parent process. We use a pipe directly
   // instead of bindings or RawChannel because we need to send synchronous
   // messages with replies from any thread.
   ScopedPlatformHandle parent_sync_channel_;
 #endif
 
-  // Guards access to below.
-  // We use LockImpl instead of Lock because the latter adds thread checking
-  // that we don't want (since we lock in the constructor and unlock on another
-  // thread.
-  base::internal::LockImpl lock_;
-
   // RawChannel used for asynchronous communication to and from the parent
   // process. Since these messages are bidirectional, we can't use
   // |parent_sync_channel_| which is only used for sync messages to the parent.
@@ -95,11 +102,23 @@
   // bindings.
   RawChannel* parent_async_channel_;
 
+  // Queue of messages to |parent_async_channel_| that are sent before it is
+  // created.
+  MessageInTransitQueue async_channel_queue_;
+
+  // The following members are only used on the IO thread, so they don't need to
+  // be used under a lock.
+
   // Maps from routing ids to the MessagePipeDispatcher that have requested to
   // connect to them. When the parent replies with which process they should be
   // connected to, they will migrate to |connected_pipes_|.
   base::hash_map<uint64_t, MessagePipeDispatcher*> pending_connects_;
 
+  // These are MessagePipeDispatchers that are connected to other MPDs in this
+  // process, but they both connected before we had parent_sync_channel_ so we
+  // delayed connecting them.
+  base::hash_map<uint64_t, MessagePipeDispatcher*> pending_inprocess_connects_;
+
   // Map from MessagePipeDispatcher to its RoutedRawChannel. This is needed so
   // that when a MessagePipeDispatcher is closed we can remove the route for the
   // corresponding RoutedRawChannel.
diff --git a/mojo/edk/system/child_broker_host.cc b/mojo/edk/system/child_broker_host.cc
index ae7236f..a10c778 100644
--- a/mojo/edk/system/child_broker_host.cc
+++ b/mojo/edk/system/child_broker_host.cc
@@ -30,7 +30,10 @@
 #if defined(OS_POSIX)
   parent_async_channel_handle = pipe.Pass();
 #else
-  child_process_ = child_process;
+  DuplicateHandle(GetCurrentProcess(), child_process,
+                  GetCurrentProcess(), &child_process,
+                  0, FALSE, DUPLICATE_SAME_ACCESS);
+  child_process_ = base::Process(child_process);
   sync_channel_ = pipe.Pass();
   memset(&read_context_.overlapped, 0, sizeof(read_context_.overlapped));
   read_context_.handler = this;
@@ -279,7 +282,7 @@
 HANDLE ChildBrokerHost::DuplicateToChild(HANDLE handle) {
   HANDLE rv = INVALID_HANDLE_VALUE;
   BOOL result = DuplicateHandle(base::GetCurrentProcessHandle(), handle,
-                                child_process_, &rv, 0, FALSE,
+                                child_process_.Handle(), &rv, 0, FALSE,
                                 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
   DCHECK(result);
   return rv;
@@ -287,7 +290,7 @@
 
 HANDLE ChildBrokerHost::DuplicateFromChild(HANDLE handle) {
   HANDLE rv = INVALID_HANDLE_VALUE;
-  BOOL result = DuplicateHandle(child_process_, handle,
+  BOOL result = DuplicateHandle(child_process_.Handle(), handle,
                                 base::GetCurrentProcessHandle(), &rv, 0, FALSE,
                                 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
   DCHECK(result);
diff --git a/mojo/edk/system/child_broker_host.h b/mojo/edk/system/child_broker_host.h
index a91218a..35153d4 100644
--- a/mojo/edk/system/child_broker_host.h
+++ b/mojo/edk/system/child_broker_host.h
@@ -10,7 +10,7 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
-#include "base/process/process_handle.h"
+#include "base/process/process.h"
 #include "mojo/edk/embedder/scoped_platform_handle.h"
 #include "mojo/edk/system/raw_channel.h"
 #include "mojo/edk/system/system_impl_export.h"
@@ -30,11 +30,10 @@
     {
 #endif
  public:
-  // |child_process| is a handle to the child process. It's not owned by this
-  // class but is guaranteed to be alive as long as the child process is
-  // running. |pipe| is a handle to the communication pipe to the child process,
-  // which is generated inside mojo::edk::ChildProcessLaunched. It is owned by
-  // this class.
+  // |child_process| is a handle to the child process. It will be duplicated by
+  // this object. |pipe| is a handle to the communication pipe to the child
+  // process, which is generated inside mojo::edk::ChildProcessLaunched. It is
+  // owned by this class.
   ChildBrokerHost(base::ProcessHandle child_process, ScopedPlatformHandle pipe);
 
   base::ProcessId GetProcessId();
@@ -76,7 +75,7 @@
 
 #if defined(OS_WIN)
   // Handle to the child process, used for duplication of handles.
-  base::ProcessHandle child_process_;
+  base::Process child_process_;
 
   // Pipe used for synchronous messages from the child. Responses are written to
   // it as well.
diff --git a/mojo/edk/system/message_pipe_dispatcher.cc b/mojo/edk/system/message_pipe_dispatcher.cc
index 55e03fa..2a53d642 100644
--- a/mojo/edk/system/message_pipe_dispatcher.cc
+++ b/mojo/edk/system/message_pipe_dispatcher.cc
@@ -5,6 +5,7 @@
 #include "mojo/edk/system/message_pipe_dispatcher.h"
 
 #include "base/bind.h"
+#include "base/debug/stack_trace.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
 #include "mojo/edk/embedder/embedder_internal.h"
@@ -441,9 +442,12 @@
   serialized_ = true;
   if (!transferable_) {
     CHECK(non_transferable_state_ == WAITING_FOR_READ_OR_WRITE)
-        << "Non transferable message pipe being sent after read/write. "
+        << "Non transferable message pipe being sent after read/write/waited. "
         << "MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE must be used if "
-        << "the pipe can be sent after it's read or written.";
+        << "the pipe can be sent after it's read or written. This message pipe "
+        << "was previously bound at:\n"
+        << non_transferable_bound_stack_->ToString();
+
     non_transferable_state_ = SERIALISED;
     return;
   }
@@ -611,12 +615,12 @@
   if (channel_) {
     channel_->EnsureLazyInitialized();
   } else if (!transferable_) {
-      if (non_transferable_state_ == WAITING_FOR_READ_OR_WRITE) {
-        RequestNontransferableChannel();
-        return MOJO_RESULT_SHOULD_WAIT;
-      } else if (non_transferable_state_ == CONNECT_CALLED) {
-        return MOJO_RESULT_SHOULD_WAIT;
-      }
+    if (non_transferable_state_ == WAITING_FOR_READ_OR_WRITE) {
+      RequestNontransferableChannel();
+      return MOJO_RESULT_SHOULD_WAIT;
+    } else if (non_transferable_state_ == CONNECT_CALLED) {
+      return MOJO_RESULT_SHOULD_WAIT;
+    }
   }
 
   DCHECK(!dispatchers || dispatchers->empty());
@@ -983,6 +987,9 @@
   CHECK(!transferable_);
   CHECK_EQ(non_transferable_state_, WAITING_FOR_READ_OR_WRITE);
   non_transferable_state_ = CONNECT_CALLED;
+#if !defined(OFFICIAL_BUILD)
+  non_transferable_bound_stack_.reset(new base::debug::StackTrace);
+#endif
 
   // PostTask since the broker can call us back synchronously.
   internal::g_io_thread_task_runner->PostTask(
diff --git a/mojo/edk/system/message_pipe_dispatcher.h b/mojo/edk/system/message_pipe_dispatcher.h
index d70d3bc..976064d 100644
--- a/mojo/edk/system/message_pipe_dispatcher.h
+++ b/mojo/edk/system/message_pipe_dispatcher.h
@@ -14,6 +14,12 @@
 #include "mojo/edk/system/system_impl_export.h"
 #include "mojo/public/cpp/system/macros.h"
 
+namespace base {
+namespace debug {
+class StackTrace;
+}
+}
+
 namespace mojo {
 namespace edk {
 
@@ -141,7 +147,7 @@
   // consumed through MojoReadMessage yet.
   MessageInTransitQueue message_queue_;
 
-  // The following members are only used when transferable_ is false;
+  // The following members are only used when transferable_ is true;
 
   // When sending MP, contains serialized message_queue_.
   std::vector<char> serialized_message_queue_;
@@ -155,7 +161,7 @@
   size_t serialized_message_fds_length_;
   ScopedPlatformHandle serialized_platform_handle_;
 
-  // The following members are only used when transferable_ is true;
+  // The following members are only used when transferable_ is false;
 
   // The unique id shared by both ends of a non-transferable message pipe. This
   // is held on until a read or write are done, and at that point it's used to
@@ -173,6 +179,7 @@
   NonTransferableState non_transferable_state_;
   // Messages that were written while we were waiting to get a RawChannel.
   MessageInTransitQueue non_transferable_outgoing_message_queue_;
+  scoped_ptr<base::debug::StackTrace> non_transferable_bound_stack_;
 
 
   // The following members are used for both modes of transferable_.
diff --git a/mojo/edk/system/run_all_unittests.cc b/mojo/edk/system/run_all_unittests.cc
deleted file mode 100644
index 4421aa6..0000000
--- a/mojo/edk/system/run_all_unittests.cc
+++ /dev/null
@@ -1,45 +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 "base/bind.h"
-#include "base/command_line.h"
-#include "base/test/launcher/unit_test_launcher.h"
-#include "base/test/test_io_thread.h"
-#include "base/test/test_suite.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/test/multiprocess_test_helper.h"
-#include "mojo/edk/test/scoped_ipc_support.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-int main(int argc, char** argv) {
-// Silence death test thread warnings on Linux. We can afford to run our death
-// tests a little more slowly (< 10 ms per death test on a Z620).
-// On android, we need to run in the default mode, as the threadsafe mode
-// relies on execve which is not available.
-#if !defined(OS_ANDROID)
-  testing::GTEST_FLAG(death_test_style) = "threadsafe";
-#endif
-  base::TestSuite test_suite(argc, argv);
-
-  // Must be run before mojo::edk::Init.
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          mojo::edk::test::kBrokerHandleSwitch)) {
-    mojo::edk::PreInitializeChildProcess();
-  }
-
-  // TODO(use_chrome_edk): temporary to force new EDK.
-  base::CommandLine::ForCurrentProcess()->AppendSwitch("--use-new-edk");
-
-  mojo::edk::Init();
-
-  base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
-  // Leak this because its destructor calls mojo::edk::ShutdownIPCSupport which
-  // really does nothing in the new EDK but does depend on the current message
-  // loop, which is destructed inside base::LaunchUnitTests.
-  new mojo::edk::test::ScopedIPCSupport(test_io_thread.task_runner());
-
-  return base::LaunchUnitTests(
-      argc, argv,
-      base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
-}
diff --git a/mojo/edk/test/run_all_unittests.cc b/mojo/edk/test/run_all_unittests.cc
index 23266444..e99040f7 100644
--- a/mojo/edk/test/run_all_unittests.cc
+++ b/mojo/edk/test/run_all_unittests.cc
@@ -5,10 +5,12 @@
 #include <signal.h>
 
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/test/launcher/unit_test_launcher.h"
 #include "base/test/test_io_thread.h"
 #include "base/test/test_suite.h"
 #include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/test/multiprocess_test_helper.h"
 #include "mojo/edk/test/scoped_ipc_support.h"
 #include "mojo/edk/test/test_support_impl.h"
 #include "mojo/public/tests/test_support_private.h"
@@ -32,10 +34,23 @@
 
   base::TestSuite test_suite(argc, argv);
 
+  // Must be run before mojo::edk::Init.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          mojo::edk::test::kBrokerHandleSwitch)) {
+    mojo::edk::PreInitializeChildProcess();
+  }
+
+  // TODO(use_chrome_edk): temporary to force new EDK.
+  base::CommandLine::ForCurrentProcess()->AppendSwitch("--use-new-edk");
+
   mojo::edk::Init();
+
   mojo::test::TestSupport::Init(new mojo::edk::test::TestSupportImpl());
   base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
-  mojo::edk::test::ScopedIPCSupport ipc_support(test_io_thread.task_runner());
+  // Leak this because its destructor calls mojo::edk::ShutdownIPCSupport which
+  // really does nothing in the new EDK but does depend on the current message
+  // loop, which is destructed inside base::LaunchUnitTests.
+  new mojo::edk::test::ScopedIPCSupport(test_io_thread.task_runner());
 
   return base::LaunchUnitTests(
       argc, argv,
diff --git a/mojo/gles2/command_buffer_client_impl.cc b/mojo/gles2/command_buffer_client_impl.cc
index fc9e5f0..142bfc9 100644
--- a/mojo/gles2/command_buffer_client_impl.cc
+++ b/mojo/gles2/command_buffer_client_impl.cc
@@ -99,6 +99,7 @@
       observer_ptr.Pass(), duped.Pass(), mojo::Array<int32_t>::From(attribs_),
       base::Bind(&Copy<mus::mojom::CommandBufferInfoPtr>, &info));
 
+  base::ThreadRestrictions::ScopedAllowWait wait;
   if (!command_buffer_.WaitForIncomingResponse()) {
     VLOG(1) << "Channel encountered error while creating command buffer.";
     return false;
@@ -270,6 +271,8 @@
   uint32_t sync_point = 0;
   command_buffer_->InsertSyncPoint(true,
                                    base::Bind(&Copy<uint32_t>, &sync_point));
+
+  base::ThreadRestrictions::ScopedAllowWait wait;
   if (!command_buffer_.WaitForIncomingResponse()) {
     VLOG(1) << "Channel encountered error while creating command buffer.";
   }
@@ -280,6 +283,8 @@
   uint32_t sync_point = 0;
   command_buffer_->InsertSyncPoint(false,
                                    base::Bind(&Copy<uint32_t>, &sync_point));
+
+  base::ThreadRestrictions::ScopedAllowWait wait;
   if (!command_buffer_.WaitForIncomingResponse()) {
     VLOG(1) << "Channel encountered error while creating command buffer.";
   }
@@ -318,6 +323,8 @@
   command_buffer_->MakeProgress(
       last_state_.get_offset,
       base::Bind(&Copy<mus::mojom::CommandBufferStatePtr>, &state));
+
+  base::ThreadRestrictions::ScopedAllowWait wait;
   if (!command_buffer_.WaitForIncomingResponse()) {
     VLOG(1) << "Channel encountered error while waiting for command buffer.";
     // TODO(piman): is it ok for this to re-enter?
@@ -345,6 +352,10 @@
   return command_buffer_id_;
 }
 
+int32_t CommandBufferClientImpl::GetExtraCommandBufferData() const {
+  return 0;
+}
+
 uint64_t CommandBufferClientImpl::GenerateFenceSyncRelease() {
   return next_fence_sync_release_++;
 }
diff --git a/mojo/gles2/command_buffer_client_impl.h b/mojo/gles2/command_buffer_client_impl.h
index 7d7d38f5..0261b79 100644
--- a/mojo/gles2/command_buffer_client_impl.h
+++ b/mojo/gles2/command_buffer_client_impl.h
@@ -75,6 +75,7 @@
   bool IsGpuChannelLost() override;
   gpu::CommandBufferNamespace GetNamespaceID() const override;
   uint64_t GetCommandBufferID() const override;
+  int32_t GetExtraCommandBufferData() const override;
   uint64_t GenerateFenceSyncRelease() override;
   bool IsFenceSyncRelease(uint64_t release) override;
   bool IsFenceSyncFlushed(uint64_t release) override;
diff --git a/mojo/gpu/mojo_gles2_impl_autogen.cc b/mojo/gpu/mojo_gles2_impl_autogen.cc
index 2b2538a..6380a30 100644
--- a/mojo/gpu/mojo_gles2_impl_autogen.cc
+++ b/mojo/gpu/mojo_gles2_impl_autogen.cc
@@ -1668,6 +1668,11 @@
   MojoGLES2MakeCurrent(context_);
   glGenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token);
 }
+void MojoGLES2Impl::VerifySyncTokensCHROMIUM(GLbyte** sync_tokens,
+                                             GLsizei count) {
+  MojoGLES2MakeCurrent(context_);
+  glVerifySyncTokensCHROMIUM(sync_tokens, count);
+}
 void MojoGLES2Impl::WaitSyncTokenCHROMIUM(const GLbyte* sync_token) {
   MojoGLES2MakeCurrent(context_);
   glWaitSyncTokenCHROMIUM(sync_token);
diff --git a/mojo/gpu/mojo_gles2_impl_autogen.h b/mojo/gpu/mojo_gles2_impl_autogen.h
index c00372dd..ca855bc 100644
--- a/mojo/gpu/mojo_gles2_impl_autogen.h
+++ b/mojo/gpu/mojo_gles2_impl_autogen.h
@@ -769,6 +769,7 @@
   void GenSyncTokenCHROMIUM(GLuint64 fence_sync, GLbyte* sync_token) override;
   void GenUnverifiedSyncTokenCHROMIUM(GLuint64 fence_sync,
                                       GLbyte* sync_token) override;
+  void VerifySyncTokensCHROMIUM(GLbyte** sync_tokens, GLsizei count) override;
   void WaitSyncTokenCHROMIUM(const GLbyte* sync_token) override;
   void DrawBuffersEXT(GLsizei count, const GLenum* bufs) override;
   void DiscardBackbufferCHROMIUM() override;
diff --git a/mojo/message_pump/handle_watcher.cc b/mojo/message_pump/handle_watcher.cc
index 0071058f..dc3b9b9 100644
--- a/mojo/message_pump/handle_watcher.cc
+++ b/mojo/message_pump/handle_watcher.cc
@@ -23,6 +23,7 @@
 #include "mojo/message_pump/message_pump_mojo.h"
 #include "mojo/message_pump/message_pump_mojo_handler.h"
 #include "mojo/message_pump/time_helper.h"
+#include "mojo/public/c/system/message_pipe.h"
 
 namespace mojo {
 namespace common {
@@ -457,6 +458,17 @@
     state_.reset(new SameThreadWatchingState(
         this, handle, handle_signals, deadline, callback));
   } else {
+#if !defined(OFFICIAL_BUILD)
+    // Just for making debugging non-transferable message pipes easier. Since
+    // they can't be sent after they're read/written/listened to,
+    // MessagePipeDispatcher saves the callstack of when it's "bound" to a
+    // pipe id. Triggering a read here, instead of later in the PostTask, means
+    // we have a callstack that is useful to check if the pipe is erronously
+    // attempted to be sent.
+    uint32_t temp = 0;
+    MojoReadMessage(handle.value(), nullptr, &temp, nullptr, nullptr,
+                    MOJO_READ_MESSAGE_FLAG_NONE);
+#endif
     state_.reset(new SecondaryThreadWatchingState(
         this, handle, handle_signals, deadline, callback));
   }
diff --git a/mojo/mojo_edk_tests.gyp b/mojo/mojo_edk_tests.gyp
index 2b11d07..7dd521b 100644
--- a/mojo/mojo_edk_tests.gyp
+++ b/mojo/mojo_edk_tests.gyp
@@ -18,7 +18,7 @@
         # to be built.
         'mojo_message_pipe_perftests2',
         'mojo_system_unittests2',
-        'mojo_js_unittests2',
+        'mojo_js_unittests',
         'mojo_js_integration_tests2',
       ],
     },
@@ -94,7 +94,7 @@
     },
     {
       # GN version: //mojo/edk/js/test:js_unittests
-      'target_name': 'mojo_js_unittests2',
+      'target_name': 'mojo_js_unittests',
       'type': 'executable',
       'dependencies': [
         '../gin/gin.gyp:gin_test',
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 c0668d3c..ba6a5e9 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
@@ -336,6 +336,10 @@
               void,
               (GLuint64 fence_sync, GLbyte* sync_token),
               (fence_sync, sync_token))
+VISIT_GL_CALL(VerifySyncTokensCHROMIUM,
+              void,
+              (GLbyte * *sync_tokens, GLsizei count),
+              (sync_tokens, count))
 VISIT_GL_CALL(WaitSyncTokenCHROMIUM,
               void,
               (const GLbyte* sync_token),
diff --git a/mojo/public/c/system/BUILD.gn b/mojo/public/c/system/BUILD.gn
index f31964a9..78e7ab6 100644
--- a/mojo/public/c/system/BUILD.gn
+++ b/mojo/public/c/system/BUILD.gn
@@ -16,6 +16,7 @@
     "message_pipe.h",
     "system_export.h",
     "types.h",
+    "wait_set.h",
   ]
 }
 
diff --git a/mojo/public/c/system/core.h b/mojo/public/c/system/core.h
index 0e78786..857abeb 100644
--- a/mojo/public/c/system/core.h
+++ b/mojo/public/c/system/core.h
@@ -17,5 +17,6 @@
 #include "mojo/public/c/system/message_pipe.h"
 #include "mojo/public/c/system/system_export.h"
 #include "mojo/public/c/system/types.h"
+#include "mojo/public/c/system/wait_set.h"
 
 #endif  // MOJO_PUBLIC_C_SYSTEM_CORE_H_
diff --git a/mojo/public/c/system/wait_set.h b/mojo/public/c/system/wait_set.h
new file mode 100644
index 0000000..c237403
--- /dev/null
+++ b/mojo/public/c/system/wait_set.h
@@ -0,0 +1,130 @@
+// 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.
+
+// This file contains types/constants and functions specific to wait sets.
+//
+// Note: This header should be compilable as C.
+
+#ifndef MOJO_PUBLIC_C_SYSTEM_WAIT_SET_H_
+#define MOJO_PUBLIC_C_SYSTEM_WAIT_SET_H_
+
+#include "mojo/public/c/system/system_export.h"
+#include "mojo/public/c/system/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Note: See the comment in functions.h about the meaning of the "optional"
+// label for pointer parameters.
+
+// Creates a wait set. A wait set is a way to efficiently wait on multiple
+// handles.
+//
+// On success, |*wait_set_handle| will contain a handle to a wait set.
+//
+// Returns:
+//   |MOJO_RESULT_OK| on success.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if |wait_set_handle| is null.
+//   |MOJO_RESULT_RESOURCE_EXHAUSTED| if a process/system/quota/etc. limit has
+//       been reached.
+MOJO_SYSTEM_EXPORT MojoResult MojoCreateWaitSet(
+    MojoHandle* wait_set_handle);  // Out.
+
+// Adds a wait on |handle| to |wait_set_handle|.
+//
+// A handle can only be added to any given wait set once, but may be added to
+// any number of different wait sets. To modify the signals being waited for,
+// the handle must first be removed, and then added with the new signals.
+//
+// It is safe to add a handle to a wait set while performing a wait on another
+// thread. If the added handle already has its signals satisfied, the waiting
+// thread will be woken.
+//
+// Returns:
+//   |MOJO_RESULT_OK| if |handle| was successfully added to |wait_set_handle|.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if |handle| is not a valid handle, or
+//       |wait_set_handle| is not a valid wait set.
+//   |MOJO_RESULT_ALREADY_EXISTS| if |handle| already exists in
+//       |wait_set_handle|.
+MOJO_SYSTEM_EXPORT MojoResult MojoAddHandle(
+    MojoHandle wait_set_handle,
+    MojoHandle handle,
+    MojoHandleSignals signals);
+
+// Removes |handle| from |wait_set_handle|.
+//
+// It is safe to remove a handle from a wait set while performing a wait on
+// another thread. If handle has its signals satisfied while it is being
+// removed, the waiting thread may be woken up, but no handle may be available
+// when |MojoGetReadyHandles()| is called.
+//
+// Returns:
+//   |MOJO_RESULT_OK| if |handle| was successfully removed from
+//       |wait_set_handle|.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if |handle| is not a valid handle, or
+//       |wait_set_handle| is not a valid wait set.
+//   |MOJO_RESULT_NOT_FOUND| if |handle| does not exist in |wait_set_handle|.
+MOJO_SYSTEM_EXPORT MojoResult MojoRemoveHandle(
+    MojoHandle wait_set_handle,
+    MojoHandle handle);
+
+// Retrieves a set of ready handles from |wait_set_handle|. A handle is ready if
+// at least of of the following is true:
+//   - The handle's signals are satisfied.
+//   - It becomes known that no signal for the handle will ever be satisfied.
+//   - The handle is closed.
+//
+// A wait set may have ready handles when it satisfies the
+// |MOJO_HANDLE_SIGNAL_READABLE| signal. Since handles may be added and removed
+// from a wait set concurrently, it is possible for a wait set to satisfy
+// |MOJO_HANDLE_SIGNAL_READABLE|, but not have any ready handles when
+// |MojoGetReadyHandle()| is called. These spurious wake-ups must be gracefully
+// handled.
+//
+// |*count| on input, must contain the maximum number of ready handles to be
+// returned. On output, it will contain the number of ready handles returned.
+//
+// |handles| must point to an array of size |*count| of |MojoHandle|. It will be
+// populated with handles that are considered ready. The number of handles
+// returned will be in |*count|.
+//
+// |results| must point to an array of size |*count| of |MojoResult|. It will be
+// populated with the wait result of the corresponding handle in |*handles|.
+// Care should be taken that if a handle is closed on another thread, the handle
+// would be invalid, but the result may not be |MOJO_RESULT_CANCELLED|. See
+// documentation for |MojoWait()| for possible results.
+//
+// |signals_state| (optional) if non-null, must point to an array of size
+// |*count| of |MojoHandleSignalsState|. It will be populated with the signals
+// state of the corresponding handle in |*handles|. See documentation for
+// |MojoHandleSignalsState|.
+//
+// Mojo signals and satisfiability are logically 'level-triggered'. Therefore,
+// if a signal continues to be satisfied and is not removed from the wait set,
+// subsequent calls to |MojoGetReadyHandle()| will return the same handle.
+//
+// If multiple handles have their signals satisfied, the order in which handles
+// are returned is undefined. The same handle, if not removed, may be returned
+// in consecutive calls. Callers must not rely on any fairness and handles
+// could be starved if not acted on.
+//
+// Returns:
+//   |MOJO_RESULT_OK| if ready handles are available.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if |wait_set_handle| is not a valid wait
+//       set, if |*count| is 0, or if either |count|, |handles|, or |results| is
+//       null.
+//   |MOJO_RESULT_SHOULD_WAIT| if there are no ready handles.
+MOJO_SYSTEM_EXPORT MojoResult MojoGetReadyHandles(
+    MojoHandle wait_set_handle,
+    uint32_t* count,                                 // In/out.
+    MojoHandle* handles,                             // Out.
+    MojoResult* results,                             // Out.
+    struct MojoHandleSignalsState *signals_states);  // Optional out.
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // MOJO_PUBLIC_C_SYSTEM_WAIT_SET_H_
diff --git a/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc b/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc
index ecd678ef..0e34fd5 100644
--- a/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc
@@ -308,15 +308,37 @@
   base::Closure notify_finish_;
 };
 
-#if defined(OS_ANDROID)
-// TODO(yzshen): This test is occasionally failing on Android GN builds.
-// http://crbug.com/567395.
-#define MAYBE_MultiThreadAccess DISABLED_MultiThreadAccess
-#else
-#define MAYBE_MultiThreadAccess MultiThreadAccess
-#endif  // defined(OS_ANDROID)
+class NotificationCounter {
+ public:
+  NotificationCounter(size_t total_count, const base::Closure& notify_finish)
+      : total_count_(total_count),
+        current_count_(0),
+        notify_finish_(notify_finish) {}
 
-TEST_F(AssociatedInterfaceTest, MAYBE_MultiThreadAccess) {
+  ~NotificationCounter() {}
+
+  // Okay to call from any thread.
+  void OnGotNotification() {
+    bool finshed = false;
+    {
+      base::AutoLock locker(lock_);
+      CHECK_LT(current_count_, total_count_);
+      current_count_++;
+      finshed = current_count_ == total_count_;
+    }
+
+    if (finshed)
+      notify_finish_.Run();
+  }
+
+ private:
+  base::Lock lock_;
+  const size_t total_count_;
+  size_t current_count_;
+  base::Closure notify_finish_;
+};
+
+TEST_F(AssociatedInterfaceTest, MultiThreadAccess) {
   // Set up four associated interfaces on a message pipe. Use the inteface
   // pointers on four threads in parallel; run the interface implementations on
   // two threads. Test that multi-threaded access works.
@@ -348,15 +370,18 @@
 
   base::RunLoop run_loop;
   TestReceiver receivers[2];
+  NotificationCounter counter(
+      2, base::Bind(&AssociatedInterfaceTest::QuitRunLoop,
+                    base::Unretained(this), base::Unretained(&run_loop)));
   for (size_t i = 0; i < 2; ++i) {
     receivers[i].receiver_thread()->task_runner()->PostTask(
         FROM_HERE,
-        base::Bind(
-            &TestReceiver::SetUp, base::Unretained(&receivers[i]),
-            base::Passed(&requests[2 * i]), base::Passed(&requests[2 * i + 1]),
-            kMaxValue,
-            base::Bind(&AssociatedInterfaceTest::QuitRunLoop,
-                       base::Unretained(this), base::Unretained(&run_loop))));
+        base::Bind(&TestReceiver::SetUp, base::Unretained(&receivers[i]),
+                   base::Passed(&requests[2 * i]),
+                   base::Passed(&requests[2 * i + 1]),
+                   static_cast<int32_t>((i + 1) * kMaxValue / 2),
+                   base::Bind(&NotificationCounter::OnGotNotification,
+                              base::Unretained(&counter))));
   }
 
   for (size_t i = 0; i < 4; ++i) {
diff --git a/mojo/public/js/connector.js b/mojo/public/js/connector.js
index 78ed963..e672b54e 100644
--- a/mojo/public/js/connector.js
+++ b/mojo/public/js/connector.js
@@ -110,8 +110,8 @@
   };
 
   // The TestConnector subclass is only intended to be used in unit tests. It
-  // enables delivering a message to the pipe's handle without an async wait.
-
+  // doesn't automatically listen for input messages. Instead, you need to
+  // call waitForNextMessage to block and wait for the next incoming message.
   function TestConnector(handle) {
     Connector.call(this, handle);
   }
@@ -119,10 +119,12 @@
   TestConnector.prototype = Object.create(Connector.prototype);
 
   TestConnector.prototype.waitToReadMore_ = function() {
-  };
+  }
 
-  TestConnector.prototype.deliverMessage = function() {
-    this.readMore_(core.RESULT_OK);
+  TestConnector.prototype.waitForNextMessage = function() {
+    var wait = core.wait(this.handle_, core.HANDLE_SIGNAL_READABLE,
+                         core.DEADLINE_INDEFINITE);
+    this.readMore_(wait.result);
   }
 
   var exports = {};
diff --git a/mojo/public/js/core_unittests.js b/mojo/public/js/core_unittests.js
index 0f7b3ff..61770f29 100644
--- a/mojo/public/js/core_unittests.js
+++ b/mojo/public/js/core_unittests.js
@@ -156,6 +156,9 @@
     expect(write.result).toBe(core.RESULT_OK);
     expect(write.numBytes).toBe(42);
 
+    var wait = core.wait(pipe.consumerHandle, core.HANDLE_SIGNAL_READABLE,
+                         core.DEADLINE_INDEFINITE);
+    expect(wait.result).toBe(core.RESULT_OK);
     var peeked = core.readData(
          pipe.consumerHandle,
          core.READ_DATA_FLAG_PEEK | core.READ_DATA_FLAG_ALL_OR_NONE);
diff --git a/mojo/public/js/validation_unittests.js b/mojo/public/js/validation_unittests.js
index 4fdb5d4..ca43a65 100644
--- a/mojo/public/js/validation_unittests.js
+++ b/mojo/public/js/validation_unittests.js
@@ -180,7 +180,7 @@
     return null;
   }
 
-  function getMessageTestFiles(key) {
+  function getMessageTestFiles(prefix) {
     var sourceRoot = file.getSourceRootDirectory();
     expect(sourceRoot).not.toBeNull();
 
@@ -192,11 +192,9 @@
 
     // The matching ".data" pathnames with the extension removed.
     return testFiles.filter(function(s) {
-      return s.substr(-5) == ".data";
+      return s.substr(-5) == ".data" && s.indexOf(prefix) == 0;
     }).map(function(s) {
       return testDir + s.slice(0, -5);
-    }).filter(function(s) {
-      return s.indexOf(key) != -1;
     });
   }
 
@@ -220,8 +218,8 @@
     expect(actualResult).toEqual(expectedResult);
   }
 
-  function testMessageValidation(key, filters) {
-    var testFiles = getMessageTestFiles(key);
+  function testMessageValidation(prefix, filters) {
+    var testFiles = getMessageTestFiles(prefix);
     expect(testFiles.length).toBeGreaterThan(0);
 
     for (var i = 0; i < testFiles.length; i++) {
@@ -260,15 +258,35 @@
         testInterface.ConformanceTestInterface.validateRequest]);
   }
 
-  function testIntegratedMessageValidation(testFilesPattern) {
+  function testBoundsCheckMessageValidation() {
+    testMessageValidation("boundscheck_", [
+        testInterface.BoundsCheckTestInterface.validateRequest]);
+  }
+
+  function testResponseConformanceMessageValidation() {
+    testMessageValidation("resp_conformance_", [
+        testInterface.ConformanceTestInterface.validateResponse]);
+  }
+
+  function testResponseBoundsCheckMessageValidation() {
+    testMessageValidation("resp_boundscheck_", [
+        testInterface.BoundsCheckTestInterface.validateResponse]);
+  }
+
+  function testIntegratedMessageValidation(testFilesPattern,
+                                           localFactory,
+                                           remoteFactory) {
     var testFiles = getMessageTestFiles(testFilesPattern);
     expect(testFiles.length).toBeGreaterThan(0);
 
+    var testMessagePipe = new core.createMessagePipe();
+    expect(testMessagePipe.result).toBe(core.RESULT_OK);
+    var testConnection = new connection.TestConnection(
+        testMessagePipe.handle1, localFactory, remoteFactory);
+
     for (var i = 0; i < testFiles.length; i++) {
       var testMessage = readTestMessage(testFiles[i]);
       var handles = new Array(testMessage.handleCount);
-      var testMessagePipe = new core.createMessagePipe();
-      expect(testMessagePipe.result).toBe(core.RESULT_OK);
 
       var writeMessageValue = core.writeMessage(
           testMessagePipe.handle0,
@@ -277,40 +295,52 @@
           core.WRITE_MESSAGE_FLAG_NONE);
       expect(writeMessageValue).toBe(core.RESULT_OK);
 
-      var testConnection = new connection.TestConnection(
-          testMessagePipe.handle1,
-          testInterface.IntegrationTestInterface.stubClass,
-          testInterface.IntegrationTestInterface.proxyClass);
-
       var validationError = noError;
       testConnection.router_.validationErrorHandler = function(err) {
         validationError = err;
       }
 
-      testConnection.router_.connector_.deliverMessage();
+      testConnection.router_.connector_.waitForNextMessage();
       checkValidationResult(testFiles[i], validationError);
-
-      testConnection.close();
-      expect(core.close(testMessagePipe.handle0)).toBe(core.RESULT_OK);
     }
+
+    testConnection.close();
+    expect(core.close(testMessagePipe.handle0)).toBe(core.RESULT_OK);
   }
 
   function testIntegratedMessageHeaderValidation() {
-    testIntegratedMessageValidation("integration_msghdr");
+    testIntegratedMessageValidation(
+        "integration_msghdr",
+        testInterface.IntegrationTestInterface.stubClass,
+        undefined);
+    testIntegratedMessageValidation(
+        "integration_msghdr",
+        undefined,
+        testInterface.IntegrationTestInterface.proxyClass);
   }
 
   function testIntegratedRequestMessageValidation() {
-    testIntegratedMessageValidation("integration_intf_rqst");
+    testIntegratedMessageValidation(
+        "integration_intf_rqst",
+        testInterface.IntegrationTestInterface.stubClass,
+        undefined);
   }
 
   function testIntegratedResponseMessageValidation() {
-    testIntegratedMessageValidation("integration_intf_resp");
+    testIntegratedMessageValidation(
+        "integration_intf_resp",
+        undefined,
+        testInterface.IntegrationTestInterface.proxyClass);
   }
 
   expect(checkTestMessageParser()).toBeNull();
   testConformanceMessageValidation();
+  testBoundsCheckMessageValidation();
+  testResponseConformanceMessageValidation();
+  testResponseBoundsCheckMessageValidation();
   testIntegratedMessageHeaderValidation();
   testIntegratedResponseMessageValidation();
   testIntegratedRequestMessageValidation();
+
   this.result = "PASS";
 });
diff --git a/mojo/runner/android/main.cc b/mojo/runner/android/main.cc
index 5e4710f..8fbda23 100644
--- a/mojo/runner/android/main.cc
+++ b/mojo/runner/android/main.cc
@@ -183,10 +183,6 @@
   base::AtExitManager at_exit;
   base::CommandLine::Init(argc, argv);
 
-#if !defined(OFFICIAL_BUILD)
-  base::debug::EnableInProcessStackDumping();
-#endif
-
   mojo::runner::InitializeLogging();
   return mojo::runner::ChildProcessMain();
 }
diff --git a/mojo/runner/child/runner_connection.cc b/mojo/runner/child/runner_connection.cc
index ca0c7fc8..b75a5031 100644
--- a/mojo/runner/child/runner_connection.cc
+++ b/mojo/runner/child/runner_connection.cc
@@ -12,6 +12,8 @@
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_checker.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/platform_channel_pair.h"
 #include "mojo/message_pump/message_pump_mojo.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/runner/child/child_controller.mojom.h"
@@ -215,9 +217,46 @@
             *base::CommandLine::ForCurrentProcess());
     if (!platform_channel.is_valid())
       return false;
+    scoped_refptr<base::TaskRunner> task_runner;
+    if (!base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk"))
+      task_runner = base::ThreadTaskRunnerHandle::Get();
     handle = embedder::CreateChannel(platform_channel.Pass(),
                                      base::Bind(&DidCreateChannel),
-                                     base::ThreadTaskRunnerHandle::Get());
+                                     task_runner);
+    // Copy of code in child_process.cc
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) {
+      // When using the new Mojo EDK, each message pipe is backed by a platform
+      // handle. The one platform handle that comes on the command line is used
+      // to bind to the ChildController interface. However we also want a
+      // platform handle to setup the communication channel by which we exchange
+      // handles to/from tokens, which is needed for sandboxed Windows
+      // processes.
+      char broker_handle[10];
+      MojoHandleSignalsState state;
+      MojoResult rv =
+          MojoWait(handle.get().value(), MOJO_HANDLE_SIGNAL_READABLE,
+                   MOJO_DEADLINE_INDEFINITE, &state);
+      CHECK_EQ(MOJO_RESULT_OK, rv);
+      uint32_t num_bytes = arraysize(broker_handle);
+      rv = MojoReadMessage(handle.get().value(),
+                           broker_handle, &num_bytes, nullptr, 0,
+                           MOJO_READ_MESSAGE_FLAG_NONE);
+      CHECK_EQ(MOJO_RESULT_OK, rv);
+
+      edk::ScopedPlatformHandle broker_channel =
+          edk::PlatformChannelPair::PassClientHandleFromParentProcessFromString(
+              std::string(broker_handle, num_bytes));
+      CHECK(broker_channel.is_valid());
+      embedder::SetParentPipeHandle(
+          mojo::embedder::ScopedPlatformHandle(mojo::embedder::PlatformHandle(
+              broker_channel.release().
+#if defined(OS_WIN)
+                                      handle
+#else
+                                      fd
+#endif
+              )));
+    }
   }
 
   Blocker blocker;
diff --git a/mojo/runner/child/test_native_main.cc b/mojo/runner/child/test_native_main.cc
index a7e57b4b..326233e 100644
--- a/mojo/runner/child/test_native_main.cc
+++ b/mojo/runner/child/test_native_main.cc
@@ -45,6 +45,7 @@
 #endif
 
   {
+    mojo::embedder::PreInitializeChildProcess();
     mojo::embedder::Init();
 
     ProcessDelegate process_delegate;
@@ -56,16 +57,14 @@
         mojo::embedder::ProcessType::NONE, &process_delegate,
         io_thread.task_runner().get(), mojo::embedder::ScopedPlatformHandle());
 
-    base::MessageLoop loop(mojo::common::MessagePumpMojo::Create());
     mojo::InterfaceRequest<mojo::Application> application_request;
     scoped_ptr<mojo::runner::RunnerConnection> connection(
         mojo::runner::RunnerConnection::ConnectToRunner(
             &application_request, ScopedMessagePipeHandle()));
-    {
-      mojo::ApplicationImpl impl(application_delegate,
-                                 application_request.Pass());
-      loop.Run();
-    }
+    base::MessageLoop loop(mojo::common::MessagePumpMojo::Create());
+    mojo::ApplicationImpl impl(application_delegate,
+                                application_request.Pass());
+    loop.Run();
 
     mojo::embedder::ShutdownIPCSupport();
   }
diff --git a/mojo/runner/desktop/launcher_process.cc b/mojo/runner/desktop/launcher_process.cc
index b55953c..7354661 100644
--- a/mojo/runner/desktop/launcher_process.cc
+++ b/mojo/runner/desktop/launcher_process.cc
@@ -11,6 +11,7 @@
 #include "base/base_switches.h"
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/debug/stack_trace.h"
 #include "base/files/file_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
@@ -24,6 +25,9 @@
 namespace runner {
 
 int LauncherProcessMain(const GURL& mojo_url, const base::Closure& callback) {
+#if !defined(OFFICIAL_BUILD)
+  base::debug::EnableInProcessStackDumping();
+#endif
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   if (!command_line->HasSwitch(switches::kMojoSingleProcess) &&
       !command_line->HasSwitch("gtest_list_tests"))
diff --git a/mojo/runner/desktop/main_helper.cc b/mojo/runner/desktop/main_helper.cc
index c36266631..a186619 100644
--- a/mojo/runner/desktop/main_helper.cc
+++ b/mojo/runner/desktop/main_helper.cc
@@ -39,11 +39,9 @@
   InitializeLogging();
   WaitForDebuggerIfNecessary();
 
-#if !defined(OFFICIAL_BUILD)
-#if defined(OS_WIN)
+#if !defined(OFFICIAL_BUILD) && defined(OS_WIN)
   base::RouteStdioToConsole(false);
 #endif
-#endif
 
   if (command_line.HasSwitch(switches::kChildProcess))
     return ChildProcessMain();
diff --git a/mojo/runner/host/child_process.cc b/mojo/runner/host/child_process.cc
index a9f07bb..07c574a 100644
--- a/mojo/runner/host/child_process.cc
+++ b/mojo/runner/host/child_process.cc
@@ -361,15 +361,14 @@
   base::i18n::InitializeICU();
   if (app_library)
     CallLibraryEarlyInitialization(app_library);
-#if defined(OS_LINUX) && !defined(OS_ANDROID)
-  if (command_line.HasSwitch(switches::kEnableSandbox)) {
 #if !defined(OFFICIAL_BUILD)
-    // Initialize stack dumping just before initializing sandbox to make
-    // sure symbol names in all loaded libraries will be cached.
-    base::debug::EnableInProcessStackDumping();
+  // Initialize stack dumping just before initializing sandbox to make
+  // sure symbol names in all loaded libraries will be cached.
+  base::debug::EnableInProcessStackDumping();
 #endif
+#if defined(OS_LINUX) && !defined(OS_ANDROID)
+  if (command_line.HasSwitch(switches::kEnableSandbox))
     sandbox = InitializeSandbox();
-  }
 #endif
 
   embedder::ScopedPlatformHandle platform_channel =
diff --git a/mojo/shell/application_manager_apptest_driver.cc b/mojo/shell/application_manager_apptest_driver.cc
index b0aa8fab..1bbc794d 100644
--- a/mojo/shell/application_manager_apptest_driver.cc
+++ b/mojo/shell/application_manager_apptest_driver.cc
@@ -20,6 +20,8 @@
 #include "mojo/application/public/interfaces/application_manager.mojom.h"
 #include "mojo/common/weak_binding_set.h"
 #include "mojo/converters/network/network_type_converters.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/platform_channel_pair.h"
 #include "mojo/runner/child/test_native_main.h"
 #include "mojo/runner/init.h"
 #include "mojo/shell/application_manager_apptests.mojom.h"
@@ -79,6 +81,19 @@
                    weak_factory_.GetWeakPtr()),
         base::ThreadTaskRunnerHandle::Get()));
 
+    // The platform handle used for the new EDK's broker.
+    mojo::edk::PlatformChannelPair broker_channel_pair;
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) {
+      std::string client_handle_as_string =
+          broker_channel_pair.PrepareToPassClientHandleToChildProcessAsString(
+              &handle_passing_info);
+      MojoResult rv = MojoWriteMessage(
+          handle.get().value(), client_handle_as_string.c_str(),
+          static_cast<uint32_t>(client_handle_as_string.size()), nullptr, 0,
+          MOJO_WRITE_MESSAGE_FLAG_NONE);
+      DCHECK_EQ(rv, MOJO_RESULT_OK);
+    }
+
     mojo::CapabilityFilterPtr filter(mojo::CapabilityFilter::New());
     mojo::Array<mojo::String> test_interfaces;
     test_interfaces.push_back(
@@ -99,6 +114,16 @@
     options.fds_to_remap = &handle_passing_info;
   #endif
     target_ = base::LaunchProcess(child_command_line, options);
+
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) {
+      MojoHandle platform_handle_wrapper;
+      MojoResult rv = mojo::edk::CreatePlatformHandleWrapper(
+          broker_channel_pair.PassServerHandle(), &platform_handle_wrapper);
+      DCHECK_EQ(rv, MOJO_RESULT_OK);
+      application_manager->RegisterProcessWithBroker(
+          target_.Pid(),
+          mojo::ScopedHandle(mojo::Handle(platform_handle_wrapper)));
+    }
   }
   bool ConfigureIncomingConnection(
       mojo::ApplicationConnection* connection) override {
diff --git a/mojo/shell/shell_application_delegate.cc b/mojo/shell/shell_application_delegate.cc
index 445bc37..66267c0 100644
--- a/mojo/shell/shell_application_delegate.cc
+++ b/mojo/shell/shell_application_delegate.cc
@@ -4,8 +4,10 @@
 
 #include "mojo/shell/shell_application_delegate.h"
 
+#include "base/process/process.h"
 #include "mojo/application/public/cpp/application_connection.h"
 #include "mojo/shell/application_manager.h"
+#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
 
 namespace mojo {
 namespace shell {
@@ -35,5 +37,43 @@
   manager_->CreateInstanceForHandle(channel.Pass(), GURL(url), filter.Pass());
 }
 
+void ShellApplicationDelegate::RegisterProcessWithBroker(
+    uint32_t pid, ScopedHandle pipe) {
+  // First, for security we want to verify that the given pid's grand parent
+  // process is us.
+  base::Process process = base::Process::OpenWithExtraPrivileges(
+      static_cast<base::ProcessId>(pid));
+  if (!process.IsValid()) {
+    NOTREACHED();
+    return;
+  }
+  base::ProcessId parent_pid = base::GetParentProcessId(process.Handle());
+  base::Process parent_process = base::Process::Open(parent_pid);
+  if (!parent_process.IsValid()) {
+    NOTREACHED();
+    return;
+  }
+  base::ProcessId grandparent_pid = base::GetParentProcessId(
+      parent_process.Handle());
+  if (grandparent_pid != base::GetCurrentProcId()) {
+#if defined(OS_POSIX)
+    // Zygote can also be in between.
+    base::ProcessId great_grandparent =
+        base::GetParentProcessId(base::Process(grandparent_pid).Handle());
+    if (great_grandparent != base::GetCurrentProcId())
+#endif
+    {
+      NOTREACHED();
+      return;
+    }
+  }
+
+  embedder::ScopedPlatformHandle platform_pipe;
+  MojoResult rv = embedder::PassWrappedPlatformHandle(
+      pipe.release().value(), &platform_pipe);
+  CHECK_EQ(rv, MOJO_RESULT_OK);
+  embedder::ChildProcessLaunched(process.Handle(), platform_pipe.Pass());
+}
+
 }  // namespace shell
 }  // namespace mojo
diff --git a/mojo/shell/shell_application_delegate.h b/mojo/shell/shell_application_delegate.h
index fcf1e29..979bdf4 100644
--- a/mojo/shell/shell_application_delegate.h
+++ b/mojo/shell/shell_application_delegate.h
@@ -38,6 +38,7 @@
   void CreateInstanceForHandle(ScopedHandle channel,
                                const String& url,
                                CapabilityFilterPtr filter) override;
+  void RegisterProcessWithBroker(uint32_t pid, ScopedHandle pipe) override;
 
   mojo::shell::ApplicationManager* manager_;
 
diff --git a/mojo/tools/data/apptests b/mojo/tools/data/apptests
index 27b077a..8c7c37f4 100644
--- a/mojo/tools/data/apptests
+++ b/mojo/tools/data/apptests
@@ -76,13 +76,12 @@
       'test': 'mojo:mandoline_browser_apptests',
       'type': 'gtest_isolated',
     },
-    # 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']
-    # },
+    {
+      '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
     {
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 8623889..7403fe2a 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1438,14 +1438,9 @@
   }
 
   if (use_openssl) {
-    # When building for OpenSSL, we need to exclude NSS specific tests
-    # or functionality not supported by OpenSSL yet.
-    # TODO(bulach): Add equivalent tests when the underlying
-    #               functionality is ported to OpenSSL.
     sources -= [ "quic/test_tools/crypto_test_utils_nss.cc" ]
   } else {
     sources -= [
-      "cert/x509_util_openssl_unittest.cc",
       "quic/test_tools/crypto_test_utils_openssl.cc",
       "socket/ssl_client_socket_openssl_unittest.cc",
       "ssl/ssl_client_session_cache_openssl_unittest.cc",
@@ -1469,7 +1464,7 @@
     sources -= [ "http/http_auth_handler_negotiate_unittest.cc" ]
   }
 
-  if (use_openssl || (!is_desktop_linux && !is_chromeos && !is_ios)) {
+  if (!use_nss_certs && !is_ios) {
     # Only include this test when on Posix and using NSS for
     # cert verification or on iOS (which also uses NSS for certs).
     sources -= [ "cert_net/nss_ocsp_unittest.cc" ]
diff --git a/net/base/backoff_entry.cc b/net/base/backoff_entry.cc
index ac4882c..64125721 100644
--- a/net/base/backoff_entry.cc
+++ b/net/base/backoff_entry.cc
@@ -8,7 +8,6 @@
 #include <cmath>
 #include <limits>
 
-#include "base/basictypes.h"
 #include "base/logging.h"
 #include "base/numerics/safe_math.h"
 #include "base/rand_util.h"
@@ -145,7 +144,7 @@
   base::internal::CheckedNumeric<int64_t> backoff_duration_us = delay_ms + 0.5;
   backoff_duration_us *= base::Time::kMicrosecondsPerMillisecond;
   base::TimeDelta backoff_duration = base::TimeDelta::FromMicroseconds(
-      backoff_duration_us.ValueOrDefault(kint64max));
+      backoff_duration_us.ValueOrDefault(std::numeric_limits<int64_t>::max()));
   base::TimeTicks release_time = BackoffDurationToReleaseTime(backoff_duration);
 
   // Never reduce previously set release horizon, e.g. due to Retry-After
@@ -162,7 +161,8 @@
       backoff_duration.InMicroseconds();
   calculated_release_time_us += kTimeTicksNowUs;
 
-  base::internal::CheckedNumeric<int64_t> maximum_release_time_us = kint64max;
+  base::internal::CheckedNumeric<int64_t> maximum_release_time_us =
+      std::numeric_limits<int64_t>::max();
   if (policy_->maximum_backoff_ms >= 0) {
     maximum_release_time_us = policy_->maximum_backoff_ms;
     maximum_release_time_us *= base::Time::kMicrosecondsPerMillisecond;
@@ -171,9 +171,10 @@
 
   // Decide between maximum release time and calculated release time, accounting
   // for overflow with both.
-  int64_t release_time_us =
-      std::min(calculated_release_time_us.ValueOrDefault(kint64max),
-               maximum_release_time_us.ValueOrDefault(kint64max));
+  int64_t release_time_us = std::min(calculated_release_time_us.ValueOrDefault(
+                                         std::numeric_limits<int64_t>::max()),
+                                     maximum_release_time_us.ValueOrDefault(
+                                         std::numeric_limits<int64_t>::max()));
 
   return base::TimeTicks() + base::TimeDelta::FromMicroseconds(release_time_us);
 }
diff --git a/net/base/backoff_entry.h b/net/base/backoff_entry.h
index 2aa3a96..3efd32c 100644
--- a/net/base/backoff_entry.h
+++ b/net/base/backoff_entry.h
@@ -5,6 +5,8 @@
 #ifndef NET_BASE_BACKOFF_ENTRY_H_
 #define NET_BASE_BACKOFF_ENTRY_H_
 
+#include <stdint.h>
+
 #include "base/macros.h"
 #include "base/threading/non_thread_safe.h"
 #include "base/time/time.h"
diff --git a/net/base/elements_upload_data_stream_unittest.cc b/net/base/elements_upload_data_stream_unittest.cc
index a395c83..07e3dd7 100644
--- a/net/base/elements_upload_data_stream_unittest.cc
+++ b/net/base/elements_upload_data_stream_unittest.cc
@@ -4,7 +4,10 @@
 
 #include "net/base/elements_upload_data_stream.h"
 
+#include <stdint.h>
+
 #include <algorithm>
+#include <limits>
 #include <vector>
 
 #include "base/basictypes.h"
@@ -183,8 +186,8 @@
             base::WriteFile(temp_file_path, kTestData, kTestDataSize));
 
   element_readers_.push_back(make_scoped_ptr(new UploadFileElementReader(
-      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0, kuint64max,
-      base::Time())));
+      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0,
+      std::numeric_limits<uint64_t>::max(), base::Time())));
 
   TestCompletionCallback init_callback;
   scoped_ptr<UploadDataStream> stream(
@@ -219,8 +222,8 @@
       overriding_content_length(kFakeSize);
 
   element_readers_.push_back(make_scoped_ptr(new UploadFileElementReader(
-      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0, kuint64max,
-      base::Time())));
+      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0,
+      std::numeric_limits<uint64_t>::max(), base::Time())));
 
   TestCompletionCallback init_callback;
   scoped_ptr<UploadDataStream> stream(
@@ -569,8 +572,8 @@
   element_readers_.push_back(
       make_scoped_ptr(new UploadBytesElementReader(kTestData, kTestDataSize)));
   element_readers_.push_back(make_scoped_ptr(new UploadFileElementReader(
-      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0, kuint64max,
-      base::Time())));
+      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0,
+      std::numeric_limits<uint64_t>::max(), base::Time())));
   scoped_ptr<UploadDataStream> stream(
       new ElementsUploadDataStream(std::move(element_readers_), 0));
 
@@ -612,8 +615,8 @@
   element_readers_.push_back(
       make_scoped_ptr(new UploadBytesElementReader(kTestData, kTestDataSize)));
   element_readers_.push_back(make_scoped_ptr(new UploadFileElementReader(
-      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0, kuint64max,
-      base::Time())));
+      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0,
+      std::numeric_limits<uint64_t>::max(), base::Time())));
   scoped_ptr<UploadDataStream> stream(
       new ElementsUploadDataStream(std::move(element_readers_), 0));
 
@@ -652,8 +655,8 @@
   element_readers_.push_back(
       make_scoped_ptr(new UploadBytesElementReader(kTestData, kTestDataSize)));
   element_readers_.push_back(make_scoped_ptr(new UploadFileElementReader(
-      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0, kuint64max,
-      base::Time())));
+      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0,
+      std::numeric_limits<uint64_t>::max(), base::Time())));
   scoped_ptr<UploadDataStream> stream(
       new ElementsUploadDataStream(std::move(element_readers_), 0));
 
@@ -708,8 +711,8 @@
   element_readers_.push_back(
       make_scoped_ptr(new UploadBytesElementReader(kTestData, kTestDataSize)));
   element_readers_.push_back(make_scoped_ptr(new UploadFileElementReader(
-      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0, kuint64max,
-      base::Time())));
+      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0,
+      std::numeric_limits<uint64_t>::max(), base::Time())));
   scoped_ptr<UploadDataStream> stream(
       new ElementsUploadDataStream(std::move(element_readers_), 0));
 
@@ -754,8 +757,8 @@
   element_readers_.push_back(
       make_scoped_ptr(new UploadBytesElementReader(kTestData, kTestDataSize)));
   element_readers_.push_back(make_scoped_ptr(new UploadFileElementReader(
-      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0, kuint64max,
-      base::Time())));
+      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0,
+      std::numeric_limits<uint64_t>::max(), base::Time())));
   scoped_ptr<UploadDataStream> stream(
       new ElementsUploadDataStream(std::move(element_readers_), 0));
 
diff --git a/net/base/int128.cc b/net/base/int128.cc
index 94275eb6..64f6421 100644
--- a/net/base/int128.cc
+++ b/net/base/int128.cc
@@ -2,14 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <iostream>
-#include "base/basictypes.h"
 #include "net/base/int128.h"
 
-const uint128_pod kuint128max = {
-    static_cast<uint64>(0xFFFFFFFFFFFFFFFFULL),
-    static_cast<uint64>(0xFFFFFFFFFFFFFFFFULL)
-};
+#include <iostream>
+
+const uint128_pod kuint128max = {static_cast<uint64_t>(0xFFFFFFFFFFFFFFFFULL),
+                                 static_cast<uint64_t>(0xFFFFFFFFFFFFFFFFULL)};
 
 std::ostream& operator<<(std::ostream& o, const uint128& b) {
   return (o << b.hi_ << "::" << b.lo_);
diff --git a/net/base/int128.h b/net/base/int128.h
index b17801be..57501fb 100644
--- a/net/base/int128.h
+++ b/net/base/int128.h
@@ -5,24 +5,26 @@
 #ifndef NET_BASE_INT128_H_
 #define NET_BASE_INT128_H_
 
+#include <stdint.h>
+
 #include <iosfwd>
-#include "base/basictypes.h"
+
 #include "net/base/net_export.h"
 
 struct uint128_pod;
 
 // An unsigned 128-bit integer type. Thread-compatible.
 class uint128 {
-public:
+ public:
   uint128();  // Sets to 0, but don't trust on this behavior.
-  uint128(uint64 top, uint64 bottom);
+  uint128(uint64_t top, uint64_t bottom);
   uint128(int bottom);
-  uint128(uint32 bottom);   // Top 96 bits = 0
-  uint128(uint64 bottom);   // hi_ = 0
+  uint128(uint32_t bottom);  // Top 96 bits = 0
+  uint128(uint64_t bottom);  // hi_ = 0
   uint128(const uint128 &val);
   uint128(const uint128_pod &val);
 
-  void Initialize(uint64 top, uint64 bottom);
+  void Initialize(uint64_t top, uint64_t bottom);
 
   uint128& operator=(const uint128& b);
 
@@ -41,23 +43,23 @@
   uint128& operator++();
   uint128& operator--();
 
-  friend uint64 Uint128Low64(const uint128& v);
-  friend uint64 Uint128High64(const uint128& v);
+  friend uint64_t Uint128Low64(const uint128& v);
+  friend uint64_t Uint128High64(const uint128& v);
 
   // We add "std::" to avoid including all of port.h.
   friend NET_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& o,
                                                      const uint128& b);
 
-private:
+ private:
   // Little-endian memory order optimizations can benefit from
   // having lo_ first, hi_ last.
   // See util/endian/endian.h and Load128/Store128 for storing a uint128.
-  uint64        lo_;
-  uint64        hi_;
+  uint64_t lo_;
+  uint64_t hi_;
 
   // Not implemented, just declared for catching automatic type conversions.
-  uint128(uint8);
-  uint128(uint16);
+  uint128(uint8_t);
+  uint128(uint16_t);
   uint128(float v);
   uint128(double v);
 };
@@ -70,8 +72,8 @@
   // of static instances, which is the primary reason for this struct in the
   // first place.  This does not seem to defeat any optimizations wrt
   // operations involving this struct.
-  uint64 hi;
-  uint64 lo;
+  uint64_t hi;
+  uint64_t lo;
 };
 
 NET_EXPORT_PRIVATE extern const uint128_pod kuint128max;
@@ -83,8 +85,12 @@
 // Methods to access low and high pieces of 128-bit value.
 // Defined externally from uint128 to facilitate conversion
 // to native 128-bit types when compilers support them.
-inline uint64 Uint128Low64(const uint128& v) { return v.lo_; }
-inline uint64 Uint128High64(const uint128& v) { return v.hi_; }
+inline uint64_t Uint128Low64(const uint128& v) {
+  return v.lo_;
+}
+inline uint64_t Uint128High64(const uint128& v) {
+  return v.hi_;
+}
 
 // TODO: perhaps it would be nice to have int128, a signed 128-bit type?
 
@@ -105,17 +111,18 @@
 }
 
 inline uint128::uint128(): lo_(0), hi_(0) { }
-inline uint128::uint128(uint64 top, uint64 bottom) : lo_(bottom), hi_(top) { }
+inline uint128::uint128(uint64_t top, uint64_t bottom)
+    : lo_(bottom), hi_(top) {}
 inline uint128::uint128(const uint128 &v) : lo_(v.lo_), hi_(v.hi_) { }
 inline uint128::uint128(const uint128_pod &v) : lo_(v.lo), hi_(v.hi) { }
-inline uint128::uint128(uint64 bottom) : lo_(bottom), hi_(0) { }
-inline uint128::uint128(uint32 bottom) : lo_(bottom), hi_(0) { }
+inline uint128::uint128(uint64_t bottom) : lo_(bottom), hi_(0) {}
+inline uint128::uint128(uint32_t bottom) : lo_(bottom), hi_(0) {}
 inline uint128::uint128(int bottom) : lo_(bottom), hi_(0) {
   if (bottom < 0) {
     --hi_;
   }
 }
-inline void uint128::Initialize(uint64 top, uint64 bottom) {
+inline void uint128::Initialize(uint64_t top, uint64_t bottom) {
   hi_ = top;
   lo_ = bottom;
 }
@@ -139,9 +146,9 @@
 // Unary operators
 
 inline uint128 operator-(const uint128& val) {
-  const uint64 hi_flip = ~Uint128High64(val);
-  const uint64 lo_flip = ~Uint128Low64(val);
-  const uint64 lo_add = lo_flip + 1;
+  const uint64_t hi_flip = ~Uint128High64(val);
+  const uint64_t lo_flip = ~Uint128Low64(val);
+  const uint64_t lo_add = lo_flip + 1;
   if (lo_add < lo_flip) {
     return uint128(hi_flip + 1, lo_add);
   }
@@ -186,14 +193,15 @@
 // Shift operators.
 
 inline uint128 operator<<(const uint128& val, int amount) {
-  // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
+  // uint64_t shifts of >= 64 are undefined, so we will need some
+  // special-casing.
   if (amount < 64) {
     if (amount == 0) {
       return val;
     }
-    uint64 new_hi = (Uint128High64(val) << amount) |
-                    (Uint128Low64(val) >> (64 - amount));
-    uint64 new_lo = Uint128Low64(val) << amount;
+    uint64_t new_hi =
+        (Uint128High64(val) << amount) | (Uint128Low64(val) >> (64 - amount));
+    uint64_t new_lo = Uint128Low64(val) << amount;
     return uint128(new_hi, new_lo);
   } else if (amount < 128) {
     return uint128(Uint128Low64(val) << (amount - 64), 0);
@@ -203,14 +211,15 @@
 }
 
 inline uint128 operator>>(const uint128& val, int amount) {
-  // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
+  // uint64_t shifts of >= 64 are undefined, so we will need some
+  // special-casing.
   if (amount < 64) {
     if (amount == 0) {
       return val;
     }
-    uint64 new_hi = Uint128High64(val) >> amount;
-    uint64 new_lo = (Uint128Low64(val) >> amount) |
-                    (Uint128High64(val) << (64 - amount));
+    uint64_t new_hi = Uint128High64(val) >> amount;
+    uint64_t new_lo =
+        (Uint128Low64(val) >> amount) | (Uint128High64(val) << (64 - amount));
     return uint128(new_hi, new_lo);
   } else if (amount < 128) {
     return uint128(0, Uint128High64(val) >> (amount - 64));
@@ -220,7 +229,8 @@
 }
 
 inline uint128& uint128::operator<<=(int amount) {
-  // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
+  // uint64_t shifts of >= 64 are undefined, so we will need some
+  // special-casing.
   if (amount < 64) {
     if (amount != 0) {
       hi_ = (hi_ << amount) | (lo_ >> (64 - amount));
@@ -237,7 +247,8 @@
 }
 
 inline uint128& uint128::operator>>=(int amount) {
-  // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
+  // uint64_t shifts of >= 64 are undefined, so we will need some
+  // special-casing.
   if (amount < 64) {
     if (amount != 0) {
       lo_ = (lo_ >> amount) | (hi_ << (64 - amount));
@@ -267,7 +278,7 @@
 
 inline uint128& uint128::operator+=(const uint128& b) {
   hi_ += b.hi_;
-  uint64 lolo = lo_ + b.lo_;
+  uint64_t lolo = lo_ + b.lo_;
   if (lolo < lo_)
     ++hi_;
   lo_ = lolo;
@@ -283,19 +294,19 @@
 }
 
 inline uint128& uint128::operator*=(const uint128& b) {
-  uint64 a96 = hi_ >> 32;
-  uint64 a64 = hi_ & 0xffffffffu;
-  uint64 a32 = lo_ >> 32;
-  uint64 a00 = lo_ & 0xffffffffu;
-  uint64 b96 = b.hi_ >> 32;
-  uint64 b64 = b.hi_ & 0xffffffffu;
-  uint64 b32 = b.lo_ >> 32;
-  uint64 b00 = b.lo_ & 0xffffffffu;
+  uint64_t a96 = hi_ >> 32;
+  uint64_t a64 = hi_ & 0xffffffffu;
+  uint64_t a32 = lo_ >> 32;
+  uint64_t a00 = lo_ & 0xffffffffu;
+  uint64_t b96 = b.hi_ >> 32;
+  uint64_t b64 = b.hi_ & 0xffffffffu;
+  uint64_t b32 = b.lo_ >> 32;
+  uint64_t b00 = b.lo_ & 0xffffffffu;
   // multiply [a96 .. a00] x [b96 .. b00]
   // terms higher than c96 disappear off the high side
   // terms c96 and c64 are safe to ignore carry bit
-  uint64 c96 = a96 * b00 + a64 * b32 + a32 * b64 + a00 * b96;
-  uint64 c64 = a64 * b00 + a32 * b32 + a00 * b64;
+  uint64_t c96 = a96 * b00 + a64 * b32 + a32 * b64 + a00 * b96;
+  uint64_t c64 = a64 * b00 + a32 * b32 + a00 * b64;
   this->hi_ = (c96 << 32) + c64;
   this->lo_ = 0;
   // add terms after this one at a time to capture carry
diff --git a/net/base/int128_unittest.cc b/net/base/int128_unittest.cc
index 957038bf..40e01c9 100644
--- a/net/base/int128_unittest.cc
+++ b/net/base/int128_unittest.cc
@@ -2,12 +2,14 @@
 // 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 <limits>
+
 #include "base/logging.h"
 #include "net/base/int128.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-
 TEST(Int128, AllTests) {
   uint128 zero(0);
   uint128 one(1);
@@ -19,7 +21,7 @@
   uint128 bigger(2001, 1);
   uint128 biggest(kuint128max);
   uint128 high_low(1, 0);
-  uint128 low_high(0, kuint64max);
+  uint128 low_high(0, std::numeric_limits<uint64_t>::max());
   EXPECT_LT(one, two);
   EXPECT_GT(two, one);
   EXPECT_LT(one, big);
@@ -58,8 +60,8 @@
   EXPECT_EQ(zero, (one >> 80) << 80);
   EXPECT_EQ(zero, big >> 128);
   EXPECT_EQ(zero, big << 128);
-  EXPECT_EQ(Uint128High64(biggest), kuint64max);
-  EXPECT_EQ(Uint128Low64(biggest), kuint64max);
+  EXPECT_EQ(Uint128High64(biggest), std::numeric_limits<uint64_t>::max());
+  EXPECT_EQ(Uint128Low64(biggest), std::numeric_limits<uint64_t>::max());
   EXPECT_EQ(zero + one, one);
   EXPECT_EQ(one + one, two);
   EXPECT_EQ(big_minus_one + one, big);
@@ -68,13 +70,14 @@
   EXPECT_EQ(zero - one, biggest);
   EXPECT_EQ(big - big, zero);
   EXPECT_EQ(big - one, big_minus_one);
-  EXPECT_EQ(big + kuint64max, bigger);
+  EXPECT_EQ(big + std::numeric_limits<uint64_t>::max(), bigger);
   EXPECT_EQ(biggest + 1, zero);
   EXPECT_EQ(zero - 1, biggest);
   EXPECT_EQ(high_low - one, low_high);
   EXPECT_EQ(low_high + one, high_low);
   EXPECT_EQ(Uint128High64((uint128(1) << 64) - 1), 0u);
-  EXPECT_EQ(Uint128Low64((uint128(1) << 64) - 1), kuint64max);
+  EXPECT_EQ(Uint128Low64((uint128(1) << 64) - 1),
+            std::numeric_limits<uint64_t>::max());
   EXPECT_TRUE(!!one);
   EXPECT_TRUE(!!high_low);
   EXPECT_FALSE(!!zero);
diff --git a/net/base/keygen_handler_win.cc b/net/base/keygen_handler_win.cc
index 44365fa..e7f10d6 100644
--- a/net/base/keygen_handler_win.cc
+++ b/net/base/keygen_handler_win.cc
@@ -183,7 +183,7 @@
             CRYPT_SILENT | CRYPT_NEWKEYSET))
       break;
 
-    if (GetLastError() != NTE_BAD_KEYSET) {
+    if (GetLastError() != static_cast<DWORD>(NTE_BAD_KEYSET)) {
       LOG(ERROR) << "Keygen failed: Couldn't acquire a CryptoAPI provider "
                     "context: " << GetLastError();
       return std::string();
diff --git a/net/base/upload_file_element_reader_unittest.cc b/net/base/upload_file_element_reader_unittest.cc
index 2a61dc622..abffc2a 100644
--- a/net/base/upload_file_element_reader_unittest.cc
+++ b/net/base/upload_file_element_reader_unittest.cc
@@ -4,6 +4,10 @@
 
 #include "net/base/upload_file_element_reader.h"
 
+#include <stdint.h>
+
+#include <limits>
+
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/run_loop.h"
@@ -34,7 +38,7 @@
 
     reader_.reset(new UploadFileElementReader(
         base::ThreadTaskRunnerHandle::Get().get(), temp_file_path_, 0,
-        kuint64max, base::Time()));
+        std::numeric_limits<uint64_t>::max(), base::Time()));
     TestCompletionCallback callback;
     ASSERT_EQ(ERR_IO_PENDING, reader_->Init(callback.callback()));
     EXPECT_EQ(OK, callback.WaitForResult());
@@ -205,8 +209,8 @@
   const base::Time expected_modification_time =
       info.last_modified - base::TimeDelta::FromSeconds(1);
   reader_.reset(new UploadFileElementReader(
-      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path_, 0, kuint64max,
-      expected_modification_time));
+      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path_, 0,
+      std::numeric_limits<uint64_t>::max(), expected_modification_time));
   TestCompletionCallback init_callback;
   ASSERT_EQ(ERR_IO_PENDING, reader_->Init(init_callback.callback()));
   EXPECT_EQ(ERR_UPLOAD_FILE_CHANGED, init_callback.WaitForResult());
@@ -219,8 +223,8 @@
   const base::Time expected_modification_time =
       info.last_modified - base::TimeDelta::FromMilliseconds(900);
   reader_.reset(new UploadFileElementReader(
-      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path_, 0, kuint64max,
-      expected_modification_time));
+      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path_, 0,
+      std::numeric_limits<uint64_t>::max(), expected_modification_time));
   TestCompletionCallback init_callback;
   ASSERT_EQ(ERR_IO_PENDING, reader_->Init(init_callback.callback()));
   EXPECT_EQ(OK, init_callback.WaitForResult());
@@ -228,9 +232,9 @@
 
 TEST_F(UploadFileElementReaderTest, WrongPath) {
   const base::FilePath wrong_path(FILE_PATH_LITERAL("wrong_path"));
-  reader_.reset(
-      new UploadFileElementReader(base::ThreadTaskRunnerHandle::Get().get(),
-                                  wrong_path, 0, kuint64max, base::Time()));
+  reader_.reset(new UploadFileElementReader(
+      base::ThreadTaskRunnerHandle::Get().get(), wrong_path, 0,
+      std::numeric_limits<uint64_t>::max(), base::Time()));
   TestCompletionCallback init_callback;
   ASSERT_EQ(ERR_IO_PENDING, reader_->Init(init_callback.callback()));
   EXPECT_EQ(ERR_FILE_NOT_FOUND, init_callback.WaitForResult());
diff --git a/net/cert/ct_serialization.cc b/net/cert/ct_serialization.cc
index 6ea3cedc..235d37e6 100644
--- a/net/cert/ct_serialization.cc
+++ b/net/cert/ct_serialization.cc
@@ -6,6 +6,8 @@
 
 #include <stdint.h>
 
+#include <limits>
+
 #include "base/logging.h"
 
 namespace net {
@@ -360,7 +362,7 @@
     return false;
   }
 
-  if (timestamp > static_cast<uint64_t>(kint64max)) {
+  if (timestamp > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
     DVLOG(1) << "Timestamp value too big to cast to int64_t: " << timestamp;
     return false;
   }
diff --git a/net/cert/multi_log_ct_verifier_unittest.cc b/net/cert/multi_log_ct_verifier_unittest.cc
index e9505d7..d5d609a 100644
--- a/net/cert/multi_log_ct_verifier_unittest.cc
+++ b/net/cert/multi_log_ct_verifier_unittest.cc
@@ -70,6 +70,20 @@
     ASSERT_TRUE(embedded_sct_chain_.get());
   }
 
+  bool CheckForSingleVerifiedSCTInResult(const ct::CTVerifyResult& result) {
+    return (result.verified_scts.size() == 1U) &&
+        result.invalid_scts.empty() &&
+        result.unknown_logs_scts.empty() &&
+        result.verified_scts[0]->log_description == kLogDescription;
+  }
+
+  bool CheckForSCTOrigin(
+      const ct::CTVerifyResult& result,
+      ct::SignedCertificateTimestamp::Origin origin) {
+    return (result.verified_scts.size() > 0) &&
+        (result.verified_scts[0]->origin == origin);
+  }
+
   bool CheckForEmbeddedSCTInNetLog(TestNetLog& net_log) {
     TestNetLogEntry::List entries;
     net_log.GetEntries(&entries);
@@ -114,6 +128,18 @@
     return true;
   }
 
+  std::string GetSCTListWithInvalidSCT() {
+    std::string sct(ct::GetTestSignedCertificateTimestamp());
+
+    // Change a byte inside the Log ID part of the SCT so it does
+    // not match the log used in the tests
+    sct[15] = 't';
+
+    std::string sct_list;
+    ct::EncodeSCTListForTesting(sct, &sct_list);
+    return sct_list;
+  }
+
   bool VerifySinglePrecertificateChain(scoped_refptr<X509Certificate> chain,
                                        const BoundNetLog& bound_net_log,
                                        ct::CTVerifyResult* result) {
@@ -143,9 +169,9 @@
     BoundNetLog bound_net_log =
       BoundNetLog::Make(&net_log, NetLog::SOURCE_CONNECT_JOB);
     return (VerifySinglePrecertificateChain(chain, bound_net_log, &result) &&
-            ct::CheckForSingleVerifiedSCTInResult(result, kLogDescription) &&
-            ct::CheckForSCTOrigin(
-                result, ct::SignedCertificateTimestamp::SCT_EMBEDDED) &&
+            CheckForSingleVerifiedSCTInResult(result) &&
+            CheckForSCTOrigin(result,
+                              ct::SignedCertificateTimestamp::SCT_EMBEDDED) &&
             CheckForEmbeddedSCTInNetLog(net_log));
   }
 
@@ -215,20 +241,25 @@
   ASSERT_TRUE(CheckPrecertificateVerification(chain));
 }
 
-TEST_F(MultiLogCTVerifierTest, VerifiesSCTOverX509Cert) {
-  std::string sct_list = ct::GetSCTListForTesting();
+TEST_F(MultiLogCTVerifierTest,
+       VerifiesSCTOverX509Cert) {
+  std::string sct(ct::GetTestSignedCertificateTimestamp());
+
+  std::string sct_list;
+  ASSERT_TRUE(ct::EncodeSCTListForTesting(sct, &sct_list));
 
   ct::CTVerifyResult result;
   EXPECT_EQ(OK,
             verifier_->Verify(
                 chain_.get(), std::string(), sct_list, &result, BoundNetLog()));
-  ASSERT_TRUE(ct::CheckForSingleVerifiedSCTInResult(result, kLogDescription));
-  ASSERT_TRUE(ct::CheckForSCTOrigin(
+  ASSERT_TRUE(CheckForSingleVerifiedSCTInResult(result));
+  ASSERT_TRUE(CheckForSCTOrigin(
       result, ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION));
 }
 
-TEST_F(MultiLogCTVerifierTest, IdentifiesSCTFromUnknownLog) {
-  std::string sct_list = ct::GetSCTListWithInvalidSCT();
+TEST_F(MultiLogCTVerifierTest,
+       IdentifiesSCTFromUnknownLog) {
+  std::string sct_list = GetSCTListWithInvalidSCT();
   ct::CTVerifyResult result;
 
   EXPECT_NE(OK,
@@ -247,7 +278,7 @@
 }
 
 TEST_F(MultiLogCTVerifierTest, CountsInvalidSCTsInStatusHistogram) {
-  std::string sct_list = ct::GetSCTListWithInvalidSCT();
+  std::string sct_list = GetSCTListWithInvalidSCT();
   ct::CTVerifyResult result;
   int num_valid_scts = NumValidSCTsInStatusHistogram();
   int num_invalid_scts = GetValueFromHistogram(
diff --git a/net/cert/test_root_certs_win.cc b/net/cert/test_root_certs_win.cc
index a83ac04..67bf1b0 100644
--- a/net/cert/test_root_certs_win.cc
+++ b/net/cert/test_root_certs_win.cc
@@ -100,8 +100,8 @@
   // If the high word is all zeroes, then |store_provider| is a numeric ID.
   // Otherwise, it's a pointer to a null-terminated ASCII string. See the
   // documentation for CryptGetOIDFunctionAddress for more information.
-  uint32_t store_as_uint = reinterpret_cast<uint32_t>(store_provider);
-  if (store_as_uint > 0xFFFF || store_provider != CERT_STORE_PROV_SYSTEM_W ||
+  uintptr_t store_as_uintptr = reinterpret_cast<uintptr_t>(store_provider);
+  if (store_as_uintptr > 0xFFFF || store_provider != CERT_STORE_PROV_SYSTEM_W ||
       !g_capi_injector.Get().original_function)
     return FALSE;
 
@@ -148,7 +148,7 @@
       CERT_STORE_ADD_NEW, NULL);
   if (!ok) {
     // If the certificate is already added, return successfully.
-    return GetLastError() == CRYPT_E_EXISTS;
+    return GetLastError() == static_cast<DWORD>(CRYPT_E_EXISTS);
   }
 
   empty_ = false;
diff --git a/net/cert/x509_util.h b/net/cert/x509_util.h
index a1c29689..816a3c5 100644
--- a/net/cert/x509_util.h
+++ b/net/cert/x509_util.h
@@ -30,14 +30,6 @@
   DIGEST_SHA256
 };
 
-// Returns true if the times can be used to create an X.509 certificate.
-// Certificates can accept dates from Jan 1st, 1 to Dec 31, 9999.  A bug in NSS
-// limited the range to 1950-9999
-// (https://bugzilla.mozilla.org/show_bug.cgi?id=786531).  This function will
-// return whether it is supported by the currently used crypto library.
-NET_EXPORT_PRIVATE bool IsSupportedValidityRange(base::Time not_valid_before,
-                                                 base::Time not_valid_after);
-
 // Creates a public-private keypair and a self-signed certificate.
 // Subject, serial number and validity period are given as parameters.
 // The certificate is signed by the private key in |key|. The key length and
diff --git a/net/cert/x509_util_nss.cc b/net/cert/x509_util_nss.cc
index fa6dc1c..2dbff2c 100644
--- a/net/cert/x509_util_nss.cc
+++ b/net/cert/x509_util_nss.cc
@@ -180,19 +180,6 @@
   return true;
 }
 
-bool IsSupportedValidityRange(base::Time not_valid_before,
-                              base::Time not_valid_after) {
-  CERTValidity* validity = CERT_CreateValidity(
-      crypto::BaseTimeToPRTime(not_valid_before),
-      crypto::BaseTimeToPRTime(not_valid_after));
-
-  if (!validity)
-    return false;
-
-  CERT_DestroyValidity(validity);
-  return true;
-}
-
 } // namespace x509_util
 
 } // namespace net
diff --git a/net/cert/x509_util_openssl.cc b/net/cert/x509_util_openssl.cc
index baf7d127..4d0c5d85 100644
--- a/net/cert/x509_util_openssl.cc
+++ b/net/cert/x509_util_openssl.cc
@@ -197,39 +197,6 @@
 
 }  // namespace
 
-bool IsSupportedValidityRange(base::Time not_valid_before,
-                              base::Time not_valid_after) {
-  if (not_valid_before > not_valid_after)
-    return false;
-
-  // The validity field of a certificate can only encode years 1-9999.
-
-  // Compute the base::Time values corresponding to Jan 1st,0001 and
-  // Jan 1st, 10000 respectively. Done by using the pre-computed numbers
-  // of days between these dates and the Unix epoch, i.e. Jan 1st, 1970,
-  // using the following Python script:
-  //
-  //     from datetime import date as D
-  //     print (D(1970,1,1)-D(1,1,1))        # -> 719162 days
-  //     print (D(9999,12,31)-D(1970,1,1))   # -> 2932896 days
-  //
-  // Note: This ignores leap seconds, but should be enough in practice.
-  //
-  const int64_t kDaysFromYear0001ToUnixEpoch = 719162;
-  const int64_t kDaysFromUnixEpochToYear10000 = 2932896 + 1;
-  const base::Time kEpoch = base::Time::UnixEpoch();
-  const base::Time kYear0001 = kEpoch -
-      base::TimeDelta::FromDays(kDaysFromYear0001ToUnixEpoch);
-  const base::Time kYear10000 = kEpoch +
-      base::TimeDelta::FromDays(kDaysFromUnixEpochToYear10000);
-
-  if (not_valid_before < kYear0001 || not_valid_before >= kYear10000 ||
-      not_valid_after < kYear0001 || not_valid_after >= kYear10000)
-    return false;
-
-  return true;
-}
-
 bool CreateSelfSignedCert(crypto::RSAPrivateKey* key,
                           DigestAlgorithm alg,
                           const std::string& common_name,
diff --git a/net/cert/x509_util_openssl_unittest.cc b/net/cert/x509_util_openssl_unittest.cc
deleted file mode 100644
index 9eebff8..0000000
--- a/net/cert/x509_util_openssl_unittest.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/memory/scoped_ptr.h"
-#include "crypto/ec_private_key.h"
-#include "crypto/openssl_util.h"
-#include "crypto/scoped_openssl_types.h"
-#include "net/cert/x509_util.h"
-#include "net/cert/x509_util_openssl.h"
-#include "net/ssl/scoped_openssl_types.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-TEST(X509UtilOpenSSLTest, IsSupportedValidityRange) {
-  base::Time now = base::Time::Now();
-  EXPECT_TRUE(x509_util::IsSupportedValidityRange(now, now));
-  EXPECT_FALSE(x509_util::IsSupportedValidityRange(
-      now, now - base::TimeDelta::FromSeconds(1)));
-
-  // See x509_util_openssl.cc to see how these were computed.
-  const int64_t kDaysFromYear0001ToUnixEpoch = 719162;
-  const int64_t kDaysFromUnixEpochToYear10000 = 2932896 + 1;
-
-  // When computing too_old / too_late, add one day to account for
-  // possible leap seconds.
-  base::Time too_old = base::Time::UnixEpoch() -
-      base::TimeDelta::FromDays(kDaysFromYear0001ToUnixEpoch + 1);
-
-  base::Time too_late = base::Time::UnixEpoch() +
-      base::TimeDelta::FromDays(kDaysFromUnixEpochToYear10000 + 1);
-
-  EXPECT_FALSE(x509_util::IsSupportedValidityRange(too_old, too_old));
-  EXPECT_FALSE(x509_util::IsSupportedValidityRange(too_old, now));
-
-  EXPECT_FALSE(x509_util::IsSupportedValidityRange(now, too_late));
-  EXPECT_FALSE(x509_util::IsSupportedValidityRange(too_late, too_late));
-}
-
-}  // namespace net
diff --git a/net/disk_cache/simple/simple_entry_impl.cc b/net/disk_cache/simple/simple_entry_impl.cc
index 3910792..f0ce25d 100644
--- a/net/disk_cache/simple/simple_entry_impl.cc
+++ b/net/disk_cache/simple/simple_entry_impl.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 #include <cstring>
+#include <limits>
 #include <vector>
 
 #include "base/bind.h"
@@ -34,7 +35,7 @@
 
 // An entry can store sparse data taking up to 1 / kMaxSparseDataSizeDivisor of
 // the cache.
-const int64 kMaxSparseDataSizeDivisor = 10;
+const int64_t kMaxSparseDataSizeDivisor = 10;
 
 // Used in histograms, please only add entries at the end.
 enum ReadResult {
@@ -164,7 +165,7 @@
 
 SimpleEntryImpl::SimpleEntryImpl(net::CacheType cache_type,
                                  const FilePath& path,
-                                 const uint64 entry_hash,
+                                 const uint64_t entry_hash,
                                  OperationsMode operations_mode,
                                  SimpleBackendImpl* backend,
                                  net::NetLog* net_log)
@@ -181,8 +182,8 @@
       doomed_(false),
       state_(STATE_UNINITIALIZED),
       synchronous_entry_(NULL),
-      net_log_(net::BoundNetLog::Make(
-          net_log, net::NetLog::SOURCE_DISK_CACHE_ENTRY)),
+      net_log_(net::BoundNetLog::Make(net_log,
+                                      net::NetLog::SOURCE_DISK_CACHE_ENTRY)),
       stream_0_data_(new net::GrowableIOBuffer()) {
   static_assert(arraysize(data_size_) == arraysize(crc32s_end_offset_),
                 "arrays should be the same size");
@@ -333,7 +334,7 @@
   return last_modified_;
 }
 
-int32 SimpleEntryImpl::GetDataSize(int stream_index) const {
+int32_t SimpleEntryImpl::GetDataSize(int stream_index) const {
   DCHECK(io_thread_checker_.CalledOnValidThread());
   DCHECK_LE(0, data_size_[stream_index]);
   return data_size_[stream_index];
@@ -471,7 +472,7 @@
   return ret_value;
 }
 
-int SimpleEntryImpl::ReadSparseData(int64 offset,
+int SimpleEntryImpl::ReadSparseData(int64_t offset,
                                     net::IOBuffer* buf,
                                     int buf_len,
                                     const CompletionCallback& callback) {
@@ -483,7 +484,7 @@
   return net::ERR_IO_PENDING;
 }
 
-int SimpleEntryImpl::WriteSparseData(int64 offset,
+int SimpleEntryImpl::WriteSparseData(int64_t offset,
                                      net::IOBuffer* buf,
                                      int buf_len,
                                      const CompletionCallback& callback) {
@@ -495,9 +496,9 @@
   return net::ERR_IO_PENDING;
 }
 
-int SimpleEntryImpl::GetAvailableRange(int64 offset,
+int SimpleEntryImpl::GetAvailableRange(int64_t offset,
                                        int len,
-                                       int64* start,
+                                       int64_t* start,
                                        const CompletionCallback& callback) {
   DCHECK(io_thread_checker_.CalledOnValidThread());
 
@@ -765,7 +766,7 @@
     for (int i = 0; i < kSimpleEntryStreamCount; ++i) {
       if (have_written_[i]) {
         if (GetDataSize(i) == crc32s_end_offset_[i]) {
-          int32 crc = GetDataSize(i) == 0 ? crc32(0, Z_NULL, 0) : crc32s_[i];
+          int32_t crc = GetDataSize(i) == 0 ? crc32(0, Z_NULL, 0) : crc32s_[i];
           crc32s_to_write->push_back(CRCRecord(i, true, crc));
         } else {
           crc32s_to_write->push_back(CRCRecord(i, false, 0));
@@ -858,7 +859,7 @@
   if (!doomed_ && backend_.get())
     backend_->index()->UseIfExists(entry_hash_);
 
-  scoped_ptr<uint32> read_crc32(new uint32());
+  scoped_ptr<uint32_t> read_crc32(new uint32_t());
   scoped_ptr<int> result(new int());
   scoped_ptr<SimpleEntryStat> entry_stat(
       new SimpleEntryStat(last_used_, last_modified_, data_size_,
@@ -927,7 +928,7 @@
 
   // Ignore zero-length writes that do not change the file size.
   if (buf_len == 0) {
-    int32 data_size = data_size_[stream_index];
+    int32_t data_size = data_size_[stream_index];
     if (truncate ? (offset == data_size) : (offset <= data_size)) {
       RecordWriteResult(cache_type_, WRITE_RESULT_FAST_EMPTY_RETURN);
       if (!callback.is_null()) {
@@ -983,7 +984,7 @@
 }
 
 void SimpleEntryImpl::ReadSparseDataInternal(
-    int64 sparse_offset,
+    int64_t sparse_offset,
     net::IOBuffer* buf,
     int buf_len,
     const CompletionCallback& callback) {
@@ -1011,7 +1012,7 @@
 }
 
 void SimpleEntryImpl::WriteSparseDataInternal(
-    int64 sparse_offset,
+    int64_t sparse_offset,
     net::IOBuffer* buf,
     int buf_len,
     const CompletionCallback& callback) {
@@ -1021,9 +1022,9 @@
   DCHECK_EQ(STATE_READY, state_);
   state_ = STATE_IO_PENDING;
 
-  uint64 max_sparse_data_size = kint64max;
+  uint64_t max_sparse_data_size = std::numeric_limits<int64_t>::max();
   if (backend_.get()) {
-    uint64 max_cache_size = backend_->index()->max_size();
+    uint64_t max_cache_size = backend_->index()->max_size();
     max_sparse_data_size = max_cache_size / kMaxSparseDataSizeDivisor;
   }
 
@@ -1051,9 +1052,9 @@
 }
 
 void SimpleEntryImpl::GetAvailableRangeInternal(
-    int64 sparse_offset,
+    int64_t sparse_offset,
     int len,
-    int64* out_start,
+    int64_t* out_start,
     const CompletionCallback& callback) {
   DCHECK(io_thread_checker_.CalledOnValidThread());
   ScopedOperationRunner operation_runner(this);
@@ -1166,7 +1167,7 @@
     int stream_index,
     int offset,
     const CompletionCallback& completion_callback,
-    scoped_ptr<uint32> read_crc32,
+    scoped_ptr<uint32_t> read_crc32,
     scoped_ptr<SimpleEntryStat> entry_stat,
     scoped_ptr<int> result) {
   DCHECK(io_thread_checker_.CalledOnValidThread());
@@ -1181,8 +1182,8 @@
   }
 
   if (*result > 0 && crc32s_end_offset_[stream_index] == offset) {
-    uint32 current_crc = offset == 0 ? crc32(0, Z_NULL, 0)
-                                     : crc32s_[stream_index];
+    uint32_t current_crc =
+        offset == 0 ? crc32(0, Z_NULL, 0) : crc32s_[stream_index];
     crc32s_[stream_index] = crc32_combine(current_crc, *read_crc32, *result);
     crc32s_end_offset_[stream_index] += *result;
     if (!have_written_[stream_index] &&
@@ -1365,8 +1366,8 @@
     backend_->index()->UpdateEntrySize(entry_hash_, GetDiskUsage());
 }
 
-int64 SimpleEntryImpl::GetDiskUsage() const {
-  int64 file_size = 0;
+int64_t SimpleEntryImpl::GetDiskUsage() const {
+  int64_t file_size = 0;
   for (int i = 0; i < kSimpleEntryStreamCount; ++i) {
     file_size +=
         simple_util::GetFileSizeFromKeyAndDataSize(key_, data_size_[i]);
@@ -1510,7 +1511,7 @@
   // the crc of the data. When we write to an entry and close without having
   // done a sequential write, we don't check the CRC on read.
   if (offset == 0 || crc32s_end_offset_[stream_index] == offset) {
-    uint32 initial_crc =
+    uint32_t initial_crc =
         (offset != 0) ? crc32s_[stream_index] : crc32(0, Z_NULL, 0);
     if (length > 0) {
       crc32s_[stream_index] = crc32(
diff --git a/net/disk_cache/simple/simple_entry_impl.h b/net/disk_cache/simple/simple_entry_impl.h
index 94f145d..df9d240 100644
--- a/net/disk_cache/simple/simple_entry_impl.h
+++ b/net/disk_cache/simple/simple_entry_impl.h
@@ -5,6 +5,8 @@
 #ifndef NET_DISK_CACHE_SIMPLE_SIMPLE_ENTRY_IMPL_H_
 #define NET_DISK_CACHE_SIMPLE_SIMPLE_ENTRY_IMPL_H_
 
+#include <stdint.h>
+
 #include <queue>
 #include <string>
 
@@ -57,7 +59,7 @@
 
   SimpleEntryImpl(net::CacheType cache_type,
                   const base::FilePath& path,
-                  uint64 entry_hash,
+                  uint64_t entry_hash,
                   OperationsMode operations_mode,
                   SimpleBackendImpl* backend,
                   net::NetLog* net_log);
@@ -76,7 +78,7 @@
   int DoomEntry(const CompletionCallback& callback);
 
   const std::string& key() const { return key_; }
-  uint64 entry_hash() const { return entry_hash_; }
+  uint64_t entry_hash() const { return entry_hash_; }
   void SetKey(const std::string& key);
 
   // From Entry:
@@ -85,7 +87,7 @@
   std::string GetKey() const override;
   base::Time GetLastUsed() const override;
   base::Time GetLastModified() const override;
-  int32 GetDataSize(int index) const override;
+  int32_t GetDataSize(int index) const override;
   int ReadData(int stream_index,
                int offset,
                net::IOBuffer* buf,
@@ -97,17 +99,17 @@
                 int buf_len,
                 const CompletionCallback& callback,
                 bool truncate) override;
-  int ReadSparseData(int64 offset,
+  int ReadSparseData(int64_t offset,
                      net::IOBuffer* buf,
                      int buf_len,
                      const CompletionCallback& callback) override;
-  int WriteSparseData(int64 offset,
+  int WriteSparseData(int64_t offset,
                       net::IOBuffer* buf,
                       int buf_len,
                       const CompletionCallback& callback) override;
-  int GetAvailableRange(int64 offset,
+  int GetAvailableRange(int64_t offset,
                         int len,
-                        int64* start,
+                        int64_t* start,
                         const CompletionCallback& callback) override;
   bool CouldBeSparse() const override;
   void CancelSparseIO() override;
@@ -193,19 +195,19 @@
                          const CompletionCallback& callback,
                          bool truncate);
 
-  void ReadSparseDataInternal(int64 sparse_offset,
+  void ReadSparseDataInternal(int64_t sparse_offset,
                               net::IOBuffer* buf,
                               int buf_len,
                               const CompletionCallback& callback);
 
-  void WriteSparseDataInternal(int64 sparse_offset,
+  void WriteSparseDataInternal(int64_t sparse_offset,
                                net::IOBuffer* buf,
                                int buf_len,
                                const CompletionCallback& callback);
 
-  void GetAvailableRangeInternal(int64 sparse_offset,
+  void GetAvailableRangeInternal(int64_t sparse_offset,
                                  int len,
-                                 int64* out_start,
+                                 int64_t* out_start,
                                  const CompletionCallback& callback);
 
   void DoomEntryInternal(const CompletionCallback& callback);
@@ -236,7 +238,7 @@
   void ReadOperationComplete(int stream_index,
                              int offset,
                              const CompletionCallback& completion_callback,
-                             scoped_ptr<uint32> read_crc32,
+                             scoped_ptr<uint32_t> read_crc32,
                              scoped_ptr<SimpleEntryStat> entry_stat,
                              scoped_ptr<int> result);
 
@@ -279,7 +281,7 @@
   // index to make them available on next IO operations.
   void UpdateDataFromEntryStat(const SimpleEntryStat& entry_stat);
 
-  int64 GetDiskUsage() const;
+  int64_t GetDiskUsage() const;
 
   // Used to report histograms.
   void RecordReadIsParallelizable(const SimpleEntryOperation& operation) const;
@@ -312,7 +314,7 @@
   const net::CacheType cache_type_;
   const scoped_refptr<base::TaskRunner> worker_pool_;
   const base::FilePath path_;
-  const uint64 entry_hash_;
+  const uint64_t entry_hash_;
   const bool use_optimistic_operations_;
   std::string key_;
 
@@ -321,8 +323,8 @@
   // TODO(clamy): Unify last_used_ with data in the index.
   base::Time last_used_;
   base::Time last_modified_;
-  int32 data_size_[kSimpleEntryStreamCount];
-  int32 sparse_data_size_;
+  int32_t data_size_[kSimpleEntryStreamCount];
+  int32_t sparse_data_size_;
 
   // Number of times this object has been returned from Backend::OpenEntry() and
   // Backend::CreateEntry() without subsequent Entry::Close() calls. Used to
@@ -341,8 +343,8 @@
   // a single entry reader that reads serially through the entire file.
   // Extending this to multiple readers is possible, but isn't currently worth
   // it; see http://crbug.com/488076#c3 for details.
-  int32 crc32s_end_offset_[kSimpleEntryStreamCount];
-  uint32 crc32s_[kSimpleEntryStreamCount];
+  int32_t crc32s_end_offset_[kSimpleEntryStreamCount];
+  uint32_t crc32s_[kSimpleEntryStreamCount];
 
   // If |have_written_[index]| is true, we have written to the file that
   // contains stream |index|.
diff --git a/net/dns/address_sorter_posix_unittest.cc b/net/dns/address_sorter_posix_unittest.cc
index ab63ac4..9d7916d 100644
--- a/net/dns/address_sorter_posix_unittest.cc
+++ b/net/dns/address_sorter_posix_unittest.cc
@@ -59,7 +59,14 @@
   }
   int BindToNetwork(NetworkChangeNotifier::NetworkHandle network) override {
     NOTIMPLEMENTED();
-    return OK;
+    return ERR_NOT_IMPLEMENTED;
+  }
+  int BindToDefaultNetwork() override {
+    NOTIMPLEMENTED();
+    return ERR_NOT_IMPLEMENTED;
+  }
+  NetworkChangeNotifier::NetworkHandle GetBoundNetwork() override {
+    return NetworkChangeNotifier::kInvalidNetworkHandle;
   }
 
   int Connect(const IPEndPoint& remote) override {
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 7389d085..875f778 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -124,6 +124,7 @@
       quic_threshold_timeouts_streams_open(0),
       quic_close_sessions_on_ip_change(false),
       quic_idle_connection_timeout_seconds(kIdleConnectionTimeoutSeconds),
+      quic_disable_preconnect_if_0rtt(false),
       proxy_delegate(NULL) {
   quic_supported_versions.push_back(QUIC_VERSION_25);
 }
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index d9194e1..563c4a9 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -174,6 +174,8 @@
     bool quic_close_sessions_on_ip_change;
     // Specifes QUIC idle connection state lifetime.
     int quic_idle_connection_timeout_seconds;
+    // If true, disable preconnections if QUIC can do 0RTT.
+    bool quic_disable_preconnect_if_0rtt;
     ProxyDelegate* proxy_delegate;
   };
 
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index bd538f5..c1a1761b 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -8,6 +8,7 @@
 #include <stdarg.h>
 #include <stdint.h>
 
+#include <limits>
 #include <string>
 #include <vector>
 
@@ -546,10 +547,9 @@
 #if defined(NTLM_PORTABLE)
 // Alternative functions that eliminate randomness and dependency on the local
 // host name so that the generated NTLM messages are reproducible.
-void MockGenerateRandom1(uint8* output, size_t n) {
-  static const uint8 bytes[] = {
-    0x55, 0x29, 0x66, 0x26, 0x6b, 0x9c, 0x73, 0x54
-  };
+void MockGenerateRandom1(uint8_t* output, size_t n) {
+  static const uint8_t bytes[] = {0x55, 0x29, 0x66, 0x26,
+                                  0x6b, 0x9c, 0x73, 0x54};
   static size_t current_byte = 0;
   for (size_t i = 0; i < n; ++i) {
     output[i] = bytes[current_byte++];
@@ -557,11 +557,10 @@
   }
 }
 
-void MockGenerateRandom2(uint8* output, size_t n) {
-  static const uint8 bytes[] = {
-    0x96, 0x79, 0x85, 0xe7, 0x49, 0x93, 0x70, 0xa1,
-    0x4e, 0xe7, 0x87, 0x45, 0x31, 0x5b, 0xd3, 0x1f
-  };
+void MockGenerateRandom2(uint8_t* output, size_t n) {
+  static const uint8_t bytes[] = {0x96, 0x79, 0x85, 0xe7, 0x49, 0x93,
+                                  0x70, 0xa1, 0x4e, 0xe7, 0x87, 0x45,
+                                  0x31, 0x5b, 0xd3, 0x1f};
   static size_t current_byte = 0;
   for (size_t i = 0; i < n; ++i) {
     output[i] = bytes[current_byte++];
@@ -1087,12 +1086,11 @@
                 "Connection: keep-alive\r\n\r\n"),
   };
   MockRead data_reads1[] = {
-    MockRead("HTTP/1.1 404 Not Found\r\n"),
-    MockRead("Server: Blah\r\n"),
-    MockRead("Content-Length: 1234\r\n\r\n"),
+      MockRead("HTTP/1.1 404 Not Found\r\n"), MockRead("Server: Blah\r\n"),
+      MockRead("Content-Length: 1234\r\n\r\n"),
 
-    // No response body because the test stops reading here.
-    MockRead(SYNCHRONOUS, ERR_UNEXPECTED),  // Should not be reached.
+      // No response body because the test stops reading here.
+      MockRead(SYNCHRONOUS, ERR_UNEXPECTED),
   };
 
   StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
@@ -1376,7 +1374,7 @@
     "hello", "world"
   };
 
-  uint32 first_socket_log_id = NetLog::Source::kInvalidId;
+  uint32_t first_socket_log_id = NetLog::Source::kInvalidId;
   for (int i = 0; i < 2; ++i) {
     TestCompletionCallback callback;
 
@@ -1904,7 +1902,7 @@
   const int kNumUnreadBodies = arraysize(data_writes) - 1;
   std::string response_lines[kNumUnreadBodies];
 
-  uint32 first_socket_log_id = NetLog::Source::kInvalidId;
+  uint32_t first_socket_log_id = NetLog::Source::kInvalidId;
   for (size_t i = 0; i < kNumUnreadBodies; ++i) {
     TestCompletionCallback callback;
 
@@ -2840,169 +2838,305 @@
 // Test the request-challenge-retry sequence for basic auth, over a keep-alive
 // proxy connection with HTTP/1.0 responses, when setting up an SSL tunnel.
 TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp10) {
-  HttpRequestInfo request;
-  request.method = "GET";
-  request.url = GURL("https://www.example.org/");
-  // Ensure that proxy authentication is attempted even
-  // when the no authentication data flag is set.
-  request.load_flags = LOAD_DO_NOT_SEND_AUTH_DATA;
+  // On the second pass, the body read of the auth challenge is synchronous, so
+  // IsConnectedAndIdle returns false.  The socket should still be drained and
+  // reused.  See http://crbug.com/544255.
+  for (int i = 0; i < 2; ++i) {
+    HttpRequestInfo request;
+    request.method = "GET";
+    request.url = GURL("https://www.example.org/");
+    // Ensure that proxy authentication is attempted even
+    // when the no authentication data flag is set.
+    request.load_flags = LOAD_DO_NOT_SEND_AUTH_DATA;
 
-  // Configure against proxy server "myproxy:70".
-  session_deps_.proxy_service = ProxyService::CreateFixed("myproxy:70");
-  BoundTestNetLog log;
-  session_deps_.net_log = log.bound().net_log();
-  scoped_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+    // Configure against proxy server "myproxy:70".
+    session_deps_.proxy_service = ProxyService::CreateFixed("myproxy:70");
+    BoundTestNetLog log;
+    session_deps_.net_log = log.bound().net_log();
+    scoped_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
 
-  scoped_ptr<HttpTransaction> trans(
-      new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+    scoped_ptr<HttpTransaction> trans(
+        new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
 
-  // Since we have proxy, should try to establish tunnel.
-  MockWrite data_writes1[] = {
-      MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
-                "Host: www.example.org:443\r\n"
-                "Proxy-Connection: keep-alive\r\n\r\n"),
+    // Since we have proxy, should try to establish tunnel.
+    MockWrite data_writes1[] = {
+        MockWrite(ASYNC, 0,
+                  "CONNECT www.example.org:443 HTTP/1.1\r\n"
+                  "Host: www.example.org:443\r\n"
+                  "Proxy-Connection: keep-alive\r\n\r\n"),
 
-      // After calling trans->RestartWithAuth(), this is the request we should
-      // be issuing -- the final header line contains the credentials.
-      MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
-                "Host: www.example.org:443\r\n"
-                "Proxy-Connection: keep-alive\r\n"
-                "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
-  };
+        // After calling trans->RestartWithAuth(), this is the request we should
+        // be issuing -- the final header line contains the credentials.
+        MockWrite(ASYNC, 3,
+                  "CONNECT www.example.org:443 HTTP/1.1\r\n"
+                  "Host: www.example.org:443\r\n"
+                  "Proxy-Connection: keep-alive\r\n"
+                  "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
+    };
 
-  // The proxy responds to the connect with a 407, using a persistent
-  // connection. (Since it's HTTP/1.0, keep-alive has to be explicit.)
-  MockRead data_reads1[] = {
-      // No credentials.
-      MockRead("HTTP/1.0 407 Proxy Authentication Required\r\n"),
-      MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
-      MockRead("Proxy-Connection: keep-alive\r\n"),
-      MockRead("Content-Length: 10\r\n\r\n"),
-      MockRead("0123456789"),
+    // The proxy responds to the connect with a 407, using a persistent
+    // connection. (Since it's HTTP/1.0, keep-alive has to be explicit.)
+    MockRead data_reads1[] = {
+        // No credentials.
+        MockRead(ASYNC, 1,
+                 "HTTP/1.0 407 Proxy Authentication Required\r\n"
+                 "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"
+                 "Proxy-Connection: keep-alive\r\n"
+                 "Content-Length: 10\r\n\r\n"),
+        MockRead(i == 0 ? ASYNC : SYNCHRONOUS, 2, "0123456789"),
 
-      // Wrong credentials (wrong password).
-      MockRead("HTTP/1.0 407 Proxy Authentication Required\r\n"),
-      MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
-      MockRead("Proxy-Connection: keep-alive\r\n"),
-      MockRead("Content-Length: 10\r\n\r\n"),
-      // No response body because the test stops reading here.
-      MockRead(SYNCHRONOUS, ERR_UNEXPECTED),  // Should not be reached.
-  };
+        // Wrong credentials (wrong password).
+        MockRead(ASYNC, 4,
+                 "HTTP/1.0 407 Proxy Authentication Required\r\n"
+                 "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"
+                 "Proxy-Connection: keep-alive\r\n"
+                 "Content-Length: 10\r\n\r\n"),
+        // No response body because the test stops reading here.
+        MockRead(SYNCHRONOUS, ERR_UNEXPECTED, 5),
+    };
 
-  StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
-                                 data_writes1, arraysize(data_writes1));
-  session_deps_.socket_factory->AddSocketDataProvider(&data1);
+    SequencedSocketData data1(data_reads1, arraysize(data_reads1), data_writes1,
+                              arraysize(data_writes1));
+    data1.set_busy_before_sync_reads(true);
+    session_deps_.socket_factory->AddSocketDataProvider(&data1);
 
-  TestCompletionCallback callback1;
+    TestCompletionCallback callback1;
 
-  int rv = trans->Start(&request, callback1.callback(), log.bound());
-  EXPECT_EQ(ERR_IO_PENDING, rv);
+    int rv = trans->Start(&request, callback1.callback(), log.bound());
+    EXPECT_EQ(OK, callback1.GetResult(rv));
 
-  rv = callback1.WaitForResult();
-  EXPECT_EQ(OK, rv);
-  TestNetLogEntry::List entries;
-  log.GetEntries(&entries);
-  size_t pos = ExpectLogContainsSomewhere(
-      entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
-      NetLog::PHASE_NONE);
-  ExpectLogContainsSomewhere(
-      entries, pos, NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
-      NetLog::PHASE_NONE);
+    TestNetLogEntry::List entries;
+    log.GetEntries(&entries);
+    size_t pos = ExpectLogContainsSomewhere(
+        entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+        NetLog::PHASE_NONE);
+    ExpectLogContainsSomewhere(
+        entries, pos,
+        NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+        NetLog::PHASE_NONE);
 
-  const HttpResponseInfo* response = trans->GetResponseInfo();
-  ASSERT_TRUE(response);
-  ASSERT_TRUE(response->headers);
-  EXPECT_TRUE(response->headers->IsKeepAlive());
-  EXPECT_EQ(407, response->headers->response_code());
-  EXPECT_EQ(10, response->headers->GetContentLength());
-  EXPECT_TRUE(HttpVersion(1, 0) == response->headers->GetHttpVersion());
-  EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get()));
+    const HttpResponseInfo* response = trans->GetResponseInfo();
+    ASSERT_TRUE(response);
+    ASSERT_TRUE(response->headers);
+    EXPECT_TRUE(response->headers->IsKeepAlive());
+    EXPECT_EQ(407, response->headers->response_code());
+    EXPECT_EQ(10, response->headers->GetContentLength());
+    EXPECT_TRUE(HttpVersion(1, 0) == response->headers->GetHttpVersion());
+    EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get()));
 
-  TestCompletionCallback callback2;
+    TestCompletionCallback callback2;
 
-  // Wrong password (should be "bar").
-  rv =
-      trans->RestartWithAuth(AuthCredentials(kFoo, kBaz), callback2.callback());
-  EXPECT_EQ(ERR_IO_PENDING, rv);
+    // Wrong password (should be "bar").
+    rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBaz),
+                                callback2.callback());
+    EXPECT_EQ(OK, callback2.GetResult(rv));
 
-  rv = callback2.WaitForResult();
-  EXPECT_EQ(OK, rv);
+    response = trans->GetResponseInfo();
+    ASSERT_TRUE(response);
+    ASSERT_TRUE(response->headers);
+    EXPECT_TRUE(response->headers->IsKeepAlive());
+    EXPECT_EQ(407, response->headers->response_code());
+    EXPECT_EQ(10, response->headers->GetContentLength());
+    EXPECT_TRUE(HttpVersion(1, 0) == response->headers->GetHttpVersion());
+    EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get()));
 
-  response = trans->GetResponseInfo();
-  ASSERT_TRUE(response);
-  ASSERT_TRUE(response->headers);
-  EXPECT_TRUE(response->headers->IsKeepAlive());
-  EXPECT_EQ(407, response->headers->response_code());
-  EXPECT_EQ(10, response->headers->GetContentLength());
-  EXPECT_TRUE(HttpVersion(1, 0) == response->headers->GetHttpVersion());
-  EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get()));
-
-  // Flush the idle socket before the NetLog and HttpNetworkTransaction go
-  // out of scope.
-  session->CloseAllConnections();
+    // Flush the idle socket before the NetLog and HttpNetworkTransaction go
+    // out of scope.
+    session->CloseAllConnections();
+  }
 }
 
 // Test the request-challenge-retry sequence for basic auth, over a keep-alive
 // proxy connection with HTTP/1.1 responses, when setting up an SSL tunnel.
 TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp11) {
+  // On the second pass, the body read of the auth challenge is synchronous, so
+  // IsConnectedAndIdle returns false.  The socket should still be drained and
+  // reused.  See http://crbug.com/544255.
+  for (int i = 0; i < 2; ++i) {
+    HttpRequestInfo request;
+    request.method = "GET";
+    request.url = GURL("https://www.example.org/");
+    // Ensure that proxy authentication is attempted even
+    // when the no authentication data flag is set.
+    request.load_flags = LOAD_DO_NOT_SEND_AUTH_DATA;
+
+    // Configure against proxy server "myproxy:70".
+    session_deps_.proxy_service = ProxyService::CreateFixed("myproxy:70");
+    BoundTestNetLog log;
+    session_deps_.net_log = log.bound().net_log();
+    scoped_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+
+    scoped_ptr<HttpTransaction> trans(
+        new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+
+    // Since we have proxy, should try to establish tunnel.
+    MockWrite data_writes1[] = {
+        MockWrite(ASYNC, 0,
+                  "CONNECT www.example.org:443 HTTP/1.1\r\n"
+                  "Host: www.example.org:443\r\n"
+                  "Proxy-Connection: keep-alive\r\n\r\n"),
+
+        // After calling trans->RestartWithAuth(), this is the request we should
+        // be issuing -- the final header line contains the credentials.
+        MockWrite(ASYNC, 3,
+                  "CONNECT www.example.org:443 HTTP/1.1\r\n"
+                  "Host: www.example.org:443\r\n"
+                  "Proxy-Connection: keep-alive\r\n"
+                  "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
+    };
+
+    // The proxy responds to the connect with a 407, using a persistent
+    // connection. (Since it's HTTP/1.0, keep-alive has to be explicit.)
+    MockRead data_reads1[] = {
+        // No credentials.
+        MockRead(ASYNC, 1,
+                 "HTTP/1.1 407 Proxy Authentication Required\r\n"
+                 "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"
+                 "Content-Length: 10\r\n\r\n"),
+        MockRead(i == 0 ? ASYNC : SYNCHRONOUS, 2, "0123456789"),
+
+        // Wrong credentials (wrong password).
+        MockRead(ASYNC, 4,
+                 "HTTP/1.1 407 Proxy Authentication Required\r\n"
+                 "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"
+                 "Content-Length: 10\r\n\r\n"),
+        // No response body because the test stops reading here.
+        MockRead(SYNCHRONOUS, ERR_UNEXPECTED, 5),
+    };
+
+    SequencedSocketData data1(data_reads1, arraysize(data_reads1), data_writes1,
+                              arraysize(data_writes1));
+    data1.set_busy_before_sync_reads(true);
+    session_deps_.socket_factory->AddSocketDataProvider(&data1);
+
+    TestCompletionCallback callback1;
+
+    int rv = trans->Start(&request, callback1.callback(), log.bound());
+    EXPECT_EQ(OK, callback1.GetResult(rv));
+
+    TestNetLogEntry::List entries;
+    log.GetEntries(&entries);
+    size_t pos = ExpectLogContainsSomewhere(
+        entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+        NetLog::PHASE_NONE);
+    ExpectLogContainsSomewhere(
+        entries, pos,
+        NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+        NetLog::PHASE_NONE);
+
+    const HttpResponseInfo* response = trans->GetResponseInfo();
+    ASSERT_TRUE(response);
+    ASSERT_TRUE(response->headers);
+    EXPECT_TRUE(response->headers->IsKeepAlive());
+    EXPECT_EQ(407, response->headers->response_code());
+    EXPECT_EQ(10, response->headers->GetContentLength());
+    EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
+    EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get()));
+
+    TestCompletionCallback callback2;
+
+    // Wrong password (should be "bar").
+    rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBaz),
+                                callback2.callback());
+    EXPECT_EQ(OK, callback2.GetResult(rv));
+
+    response = trans->GetResponseInfo();
+    ASSERT_TRUE(response);
+    ASSERT_TRUE(response->headers);
+    EXPECT_TRUE(response->headers->IsKeepAlive());
+    EXPECT_EQ(407, response->headers->response_code());
+    EXPECT_EQ(10, response->headers->GetContentLength());
+    EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
+    EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get()));
+
+    // Flush the idle socket before the NetLog and HttpNetworkTransaction go
+    // out of scope.
+    session->CloseAllConnections();
+  }
+}
+
+// Test the request-challenge-retry sequence for basic auth, over a keep-alive
+// proxy connection with HTTP/1.1 responses, when setting up an SSL tunnel, in
+// the case the server sends extra data on the original socket, so it can't be
+// reused.
+TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveExtraData) {
   HttpRequestInfo request;
   request.method = "GET";
   request.url = GURL("https://www.example.org/");
-  // Ensure that proxy authentication is attempted even
   // when the no authentication data flag is set.
   request.load_flags = LOAD_DO_NOT_SEND_AUTH_DATA;
 
   // Configure against proxy server "myproxy:70".
-  session_deps_.proxy_service = ProxyService::CreateFixed("myproxy:70");
+  session_deps_.proxy_service =
+      ProxyService::CreateFixedFromPacResult("PROXY myproxy:70");
   BoundTestNetLog log;
   session_deps_.net_log = log.bound().net_log();
   scoped_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
 
-  scoped_ptr<HttpTransaction> trans(
-      new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
-
   // Since we have proxy, should try to establish tunnel.
   MockWrite data_writes1[] = {
-      MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
+      MockWrite(ASYNC, 0,
+                "CONNECT www.example.org:443 HTTP/1.1\r\n"
                 "Host: www.example.org:443\r\n"
                 "Proxy-Connection: keep-alive\r\n\r\n"),
+  };
 
+  // The proxy responds to the connect with a 407, using a persistent, but sends
+  // extra data, so the socket cannot be reused.
+  MockRead data_reads1[] = {
+      // No credentials.
+      MockRead(ASYNC, 1,
+               "HTTP/1.1 407 Proxy Authentication Required\r\n"
+               "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"
+               "Content-Length: 10\r\n\r\n"),
+      MockRead(SYNCHRONOUS, 2, "0123456789"),
+      MockRead(SYNCHRONOUS, 3, "I'm broken!"),
+  };
+
+  MockWrite data_writes2[] = {
       // After calling trans->RestartWithAuth(), this is the request we should
       // be issuing -- the final header line contains the credentials.
-      MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
+      MockWrite(ASYNC, 0,
+                "CONNECT www.example.org:443 HTTP/1.1\r\n"
                 "Host: www.example.org:443\r\n"
                 "Proxy-Connection: keep-alive\r\n"
-                "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
+                "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
+
+      MockWrite(ASYNC, 2,
+                "GET / HTTP/1.1\r\n"
+                "Host: www.example.org\r\n"
+                "Connection: keep-alive\r\n\r\n"),
   };
 
-  // The proxy responds to the connect with a 407, using a persistent
-  // connection.
-  MockRead data_reads1[] = {
-    // No credentials.
-    MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
-    MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
-    MockRead("Content-Length: 10\r\n\r\n"),
-    MockRead("0123456789"),
+  MockRead data_reads2[] = {
+      MockRead(ASYNC, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
 
-    // Wrong credentials (wrong password).
-    MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
-    MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
-    MockRead("Content-Length: 10\r\n\r\n"),
-    // No response body because the test stops reading here.
-    MockRead(SYNCHRONOUS, ERR_UNEXPECTED),  // Should not be reached.
+      MockRead(ASYNC, 3,
+               "HTTP/1.1 200 OK\r\n"
+               "Content-Type: text/html; charset=iso-8859-1\r\n"
+               "Content-Length: 5\r\n\r\n"),
+      // No response body because the test stops reading here.
+      MockRead(SYNCHRONOUS, ERR_UNEXPECTED, 4),
   };
 
-  StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
-                                 data_writes1, arraysize(data_writes1));
+  SequencedSocketData data1(data_reads1, arraysize(data_reads1), data_writes1,
+                            arraysize(data_writes1));
+  data1.set_busy_before_sync_reads(true);
   session_deps_.socket_factory->AddSocketDataProvider(&data1);
+  SequencedSocketData data2(data_reads2, arraysize(data_reads2), data_writes2,
+                            arraysize(data_writes2));
+  session_deps_.socket_factory->AddSocketDataProvider(&data2);
+  SSLSocketDataProvider ssl(ASYNC, OK);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
   TestCompletionCallback callback1;
 
-  int rv = trans->Start(&request, callback1.callback(), log.bound());
-  EXPECT_EQ(ERR_IO_PENDING, rv);
+  scoped_ptr<HttpTransaction> trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
 
-  rv = callback1.WaitForResult();
-  EXPECT_EQ(OK, rv);
+  int rv = trans->Start(&request, callback1.callback(), log.bound());
+  EXPECT_EQ(OK, callback1.GetResult(rv));
+
   TestNetLogEntry::List entries;
   log.GetEntries(&entries);
   size_t pos = ExpectLogContainsSomewhere(
@@ -3018,31 +3152,33 @@
   ASSERT_TRUE(response->headers);
   EXPECT_TRUE(response->headers->IsKeepAlive());
   EXPECT_EQ(407, response->headers->response_code());
-  EXPECT_EQ(10, response->headers->GetContentLength());
   EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
   EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get()));
 
+  LoadTimingInfo load_timing_info;
+  // CONNECT requests and responses are handled at the connect job level, so
+  // the transaction does not yet have a connection.
+  EXPECT_FALSE(trans->GetLoadTimingInfo(&load_timing_info));
+
   TestCompletionCallback callback2;
 
-  // Wrong password (should be "bar").
-  rv = trans->RestartWithAuth(
-      AuthCredentials(kFoo, kBaz), callback2.callback());
-  EXPECT_EQ(ERR_IO_PENDING, rv);
+  rv =
+      trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
+  EXPECT_EQ(OK, callback2.GetResult(rv));
 
-  rv = callback2.WaitForResult();
-  EXPECT_EQ(OK, rv);
-
-  response = trans->GetResponseInfo();
-  ASSERT_TRUE(response);
-  ASSERT_TRUE(response->headers);
   EXPECT_TRUE(response->headers->IsKeepAlive());
-  EXPECT_EQ(407, response->headers->response_code());
-  EXPECT_EQ(10, response->headers->GetContentLength());
+  EXPECT_EQ(200, response->headers->response_code());
+  EXPECT_EQ(5, response->headers->GetContentLength());
   EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
-  EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get()));
 
-  // Flush the idle socket before the NetLog and HttpNetworkTransaction go
-  // out of scope.
+  // The password prompt info should not be set.
+  EXPECT_FALSE(response->auth_challenge);
+
+  EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+  TestLoadTimingNotReusedWithPac(load_timing_info,
+                                 CONNECT_TIMING_HAS_SSL_TIMES);
+
+  trans.reset();
   session->CloseAllConnections();
 }
 
@@ -3165,7 +3301,7 @@
       MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
       MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
       MockRead("Content-Length: 10\r\n\r\n"),
-      MockRead("0123456789"),  // Should not be reached.
+      MockRead("0123456789"),
       MockRead(SYNCHRONOUS, ERR_UNEXPECTED),
   };
 
@@ -3226,7 +3362,7 @@
       MockRead("Set-Cookie: foo=bar\r\n"),
       MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
       MockRead("Content-Length: 10\r\n\r\n"),
-      MockRead(SYNCHRONOUS, ERR_UNEXPECTED),  // Should not be reached.
+      MockRead(SYNCHRONOUS, ERR_UNEXPECTED),
   };
 
   StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes,
@@ -5009,10 +5145,9 @@
   };
 
   MockRead data_reads[] = {
-    status,
-    MockRead("Content-Length: 10\r\n\r\n"),
-    // No response body because the test stops reading here.
-    MockRead(SYNCHRONOUS, ERR_UNEXPECTED),  // Should not be reached.
+      status, MockRead("Content-Length: 10\r\n\r\n"),
+      // No response body because the test stops reading here.
+      MockRead(SYNCHRONOUS, ERR_UNEXPECTED),
   };
 
   StaticSocketDataProvider data(data_reads, arraysize(data_reads),
@@ -5736,9 +5871,9 @@
   // connection. Usually a proxy would return 501 (not implemented),
   // or 200 (tunnel established).
   MockRead data_reads1[] = {
-    MockRead("HTTP/1.1 404 Not Found\r\n"),
-    MockRead("Content-Length: 10\r\n\r\n"),
-    MockRead(SYNCHRONOUS, ERR_UNEXPECTED),  // Should not be reached.
+      MockRead("HTTP/1.1 404 Not Found\r\n"),
+      MockRead("Content-Length: 10\r\n\r\n"),
+      MockRead(SYNCHRONOUS, ERR_UNEXPECTED),
   };
 
   StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
@@ -9127,14 +9262,14 @@
 TEST_P(HttpNetworkTransactionTest, UploadFileSmallerThanLength) {
   base::FilePath temp_file_path;
   ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path));
-  const uint64 kFakeSize = 100000;  // file is actually blank
+  const uint64_t kFakeSize = 100000;  // file is actually blank
   UploadFileElementReader::ScopedOverridingContentLengthForTests
       overriding_content_length(kFakeSize);
 
   std::vector<scoped_ptr<UploadElementReader>> element_readers;
   element_readers.push_back(make_scoped_ptr(new UploadFileElementReader(
-      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0, kuint64max,
-      base::Time())));
+      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0,
+      std::numeric_limits<uint64_t>::max(), base::Time())));
   ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
 
   HttpRequestInfo request;
@@ -9186,9 +9321,9 @@
   ASSERT_TRUE(base::MakeFileUnreadable(temp_file));
 
   std::vector<scoped_ptr<UploadElementReader>> element_readers;
-  element_readers.push_back(make_scoped_ptr(
-      new UploadFileElementReader(base::ThreadTaskRunnerHandle::Get().get(),
-                                  temp_file, 0, kuint64max, base::Time())));
+  element_readers.push_back(make_scoped_ptr(new UploadFileElementReader(
+      base::ThreadTaskRunnerHandle::Get().get(), temp_file, 0,
+      std::numeric_limits<uint64_t>::max(), base::Time())));
   ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
 
   HttpRequestInfo request;
@@ -9229,8 +9364,8 @@
       callback_ = callback;
       return ERR_IO_PENDING;
     }
-    uint64 GetContentLength() const override { return 0; }
-    uint64 BytesRemaining() const override { return 0; }
+    uint64_t GetContentLength() const override { return 0; }
+    uint64_t BytesRemaining() const override { return 0; }
     int Read(IOBuffer* buf,
              int buf_length,
              const CompletionCallback& callback) override {
diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc
index e3e4e57..5a3ec4b9 100644
--- a/net/http/http_proxy_client_socket.cc
+++ b/net/http/http_proxy_client_socket.cc
@@ -268,7 +268,7 @@
   // The request should be retried at a higher layer.
   if (!response_.headers->IsKeepAlive() ||
       !http_stream_parser_->CanFindEndOfResponse() ||
-      !transport_->socket()->IsConnectedAndIdle()) {
+      !transport_->socket()->IsConnected()) {
     transport_->socket()->Disconnect();
     return ERR_UNABLE_TO_REUSE_CONNECTION_FOR_PROXY_AUTH;
   }
@@ -284,6 +284,10 @@
 }
 
 int HttpProxyClientSocket::DidDrainBodyForAuthRestart() {
+  // Can't reuse the socket if there's still unread data on it.
+  if (!transport_->socket()->IsConnectedAndIdle())
+    return ERR_UNABLE_TO_REUSE_CONNECTION_FOR_PROXY_AUTH;
+
   next_state_ = STATE_GENERATE_AUTH_TOKEN;
   transport_->set_reuse_type(ClientSocketHandle::REUSED_IDLE);
 
diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc
index 81bfd5f..93b85df 100644
--- a/net/http/http_stream_factory_impl.cc
+++ b/net/http/http_stream_factory_impl.cc
@@ -14,6 +14,7 @@
 #include "net/http/http_stream_factory_impl_job.h"
 #include "net/http/http_stream_factory_impl_request.h"
 #include "net/log/net_log.h"
+#include "net/quic/quic_server_id.h"
 #include "net/spdy/spdy_http_stream.h"
 #include "url/gurl.h"
 
@@ -134,6 +135,12 @@
   if (!alternative_service_vector.empty()) {
     // TODO(bnc): Pass on multiple alternative services to Job.
     alternative_service = alternative_service_vector[0];
+    if (session_->params().quic_disable_preconnect_if_0rtt &&
+        alternative_service.protocol == QUIC &&
+        session_->quic_stream_factory()->ZeroRTTEnabledFor(QuicServerId(
+            alternative_service.host_port_pair(), request_info.privacy_mode))) {
+      return;
+    }
   }
 
   // Due to how the socket pools handle priorities and idle sockets, only IDLE
@@ -219,9 +226,8 @@
     if (session_->quic_stream_factory()->IsQuicDisabled(origin.port()))
       continue;
 
-    if (!original_url.SchemeIs("https")) {
+    if (!original_url.SchemeIs("https"))
       continue;
-    }
 
     enabled_alternative_service_vector.push_back(alternative_service);
   }
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc
index 45f52dc..8191ee1 100644
--- a/net/http/http_stream_factory_impl_unittest.cc
+++ b/net/http/http_stream_factory_impl_unittest.cc
@@ -27,6 +27,8 @@
 #include "net/log/net_log.h"
 #include "net/proxy/proxy_info.h"
 #include "net/proxy/proxy_service.h"
+#include "net/quic/quic_server_id.h"
+#include "net/quic/test_tools/quic_stream_factory_peer.h"
 #include "net/socket/client_socket_handle.h"
 #include "net/socket/mock_client_socket_pool_manager.h"
 #include "net/socket/next_proto.h"
@@ -116,7 +118,6 @@
         preconnect_done_(false),
         waiting_for_preconnect_(false) {}
 
-
   void WaitForPreconnects() {
     while (!preconnect_done_) {
       waiting_for_preconnect_ = true;
@@ -641,6 +642,7 @@
 
     HttpNetworkSession::Params params;
     params.enable_quic = true;
+    params.quic_disable_preconnect_if_0rtt = false;
     params.enable_quic_for_proxies = true;
     scoped_refptr<SSLConfigServiceDefaults> ssl_config_service(
         new SSLConfigServiceDefaults);
@@ -702,6 +704,7 @@
   HttpNetworkSession::Params params;
   params.enable_quic = true;
   params.enable_quic_for_proxies = true;
+  params.quic_disable_preconnect_if_0rtt = false;
   scoped_refptr<SSLConfigServiceDefaults> ssl_config_service(
       new SSLConfigServiceDefaults);
   HttpServerPropertiesImpl http_server_properties;
@@ -750,6 +753,105 @@
   EXPECT_TRUE(iter != retry_info.end());
 }
 
+TEST_P(HttpStreamFactoryTest, UsePreConnectIfNoZeroRTT) {
+  for (int num_streams = 1; num_streams < 3; ++num_streams) {
+    GURL url = GURL("https://www.google.com");
+
+    // Set up QUIC as alternative_service.
+    HttpServerPropertiesImpl http_server_properties;
+    const AlternativeService alternative_service(QUIC, url.host().c_str(),
+                                                 url.IntPort());
+    AlternativeServiceInfoVector alternative_service_info_vector;
+    base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
+    alternative_service_info_vector.push_back(
+        AlternativeServiceInfo(alternative_service, 1.0, expiration));
+    HostPortPair host_port_pair(alternative_service.host_port_pair());
+    http_server_properties.SetAlternativeServices(
+        host_port_pair, alternative_service_info_vector);
+
+    SpdySessionDependencies session_deps(
+        GetParam(), ProxyService::CreateFixed("http_proxy"));
+
+    // Setup params to disable preconnect, but QUIC doesn't 0RTT.
+    HttpNetworkSession::Params params =
+        SpdySessionDependencies::CreateSessionParams(&session_deps);
+    params.enable_quic = true;
+    params.quic_disable_preconnect_if_0rtt = true;
+    params.http_server_properties = http_server_properties.GetWeakPtr();
+
+    scoped_ptr<HttpNetworkSession> session(new HttpNetworkSession(params));
+    HttpNetworkSessionPeer peer(session.get());
+    HostPortPair proxy_host("http_proxy", 80);
+    CapturePreconnectsHttpProxySocketPool* http_proxy_pool =
+        new CapturePreconnectsHttpProxySocketPool(
+            session_deps.host_resolver.get(), session_deps.cert_verifier.get());
+    CapturePreconnectsSSLSocketPool* ssl_conn_pool =
+        new CapturePreconnectsSSLSocketPool(session_deps.host_resolver.get(),
+                                            session_deps.cert_verifier.get());
+    scoped_ptr<MockClientSocketPoolManager> mock_pool_manager(
+        new MockClientSocketPoolManager);
+    mock_pool_manager->SetSocketPoolForHTTPProxy(proxy_host, http_proxy_pool);
+    mock_pool_manager->SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool);
+    peer.SetClientSocketPoolManager(mock_pool_manager.Pass());
+    PreconnectHelperForURL(num_streams, url, session.get());
+    EXPECT_EQ(num_streams, ssl_conn_pool->last_num_streams());
+  }
+}
+
+TEST_P(HttpStreamFactoryTest, QuicDisablePreConnectIfZeroRtt) {
+  for (int num_streams = 1; num_streams < 3; ++num_streams) {
+    GURL url = GURL("https://www.google.com");
+
+    // Set up QUIC as alternative_service.
+    HttpServerPropertiesImpl http_server_properties;
+    const AlternativeService alternative_service(QUIC, "www.google.com", 443);
+    AlternativeServiceInfoVector alternative_service_info_vector;
+    base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
+    alternative_service_info_vector.push_back(
+        AlternativeServiceInfo(alternative_service, 1.0, expiration));
+    HostPortPair host_port_pair(alternative_service.host_port_pair());
+    http_server_properties.SetAlternativeServices(
+        host_port_pair, alternative_service_info_vector);
+
+    SpdySessionDependencies session_deps(GetParam());
+
+    // Setup params to disable preconnect, but QUIC does 0RTT.
+    HttpNetworkSession::Params params =
+        SpdySessionDependencies::CreateSessionParams(&session_deps);
+    params.enable_quic = true;
+    params.quic_disable_preconnect_if_0rtt = true;
+    params.http_server_properties = http_server_properties.GetWeakPtr();
+
+    scoped_ptr<HttpNetworkSession> session(new HttpNetworkSession(params));
+
+    // Setup 0RTT for QUIC.
+    QuicStreamFactory* factory = session->quic_stream_factory();
+    factory->set_require_confirmation(false);
+    test::QuicStreamFactoryPeer::CacheDummyServerConfig(
+        factory, QuicServerId(host_port_pair, PRIVACY_MODE_DISABLED));
+
+    HttpNetworkSessionPeer peer(session.get());
+    CapturePreconnectsTransportSocketPool* transport_conn_pool =
+        new CapturePreconnectsTransportSocketPool(
+            session_deps.host_resolver.get(), session_deps.cert_verifier.get());
+    scoped_ptr<MockClientSocketPoolManager> mock_pool_manager(
+        new MockClientSocketPoolManager);
+    mock_pool_manager->SetTransportSocketPool(transport_conn_pool);
+    peer.SetClientSocketPoolManager(mock_pool_manager.Pass());
+
+    HttpRequestInfo request;
+    request.method = "GET";
+    request.url = url;
+    request.load_flags = 0;
+
+    SSLConfig ssl_config;
+    session->ssl_config_service()->GetSSLConfig(&ssl_config);
+    session->http_stream_factory()->PreconnectStreams(num_streams, request,
+                                                      ssl_config, ssl_config);
+    EXPECT_EQ(-1, transport_conn_pool->last_num_streams());
+  }
+}
+
 namespace {
 
 TEST_P(HttpStreamFactoryTest, PrivacyModeDisablesChannelId) {
diff --git a/net/net.gyp b/net/net.gyp
index 32dbf4cc..6579e158 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -235,25 +235,19 @@
             'http/http_auth_handler_negotiate_unittest.cc',
           ],
         }],
-        [ 'use_openssl == 1 or (desktop_linux == 0 and chromeos == 0 and OS != "ios")', {
-          # Only include this test when on Posix and using NSS for
-          # cert verification or on iOS (which also uses NSS for certs).
+        [ 'use_nss_certs == 0 and OS != "ios"', {
+          # Only include this test when using system NSS for cert verification
+          # or on iOS (which also uses NSS for certs).
           'sources!': [
             'cert_net/nss_ocsp_unittest.cc',
           ],
         }],
         [ 'use_openssl==1', {
-            # When building for OpenSSL, we need to exclude NSS specific tests
-            # or functionality not supported by OpenSSL yet.
-            # TODO(bulach): Add equivalent tests when the underlying
-            #               functionality is ported to OpenSSL.
             'sources!': [
-              'cert/x509_util_nss_unittest.cc',
               'quic/test_tools/crypto_test_utils_nss.cc',
             ],
           }, {  # else !use_openssl: remove the unneeded files and pull in NSS.
             'sources!': [
-              'cert/x509_util_openssl_unittest.cc',
               'quic/test_tools/crypto_test_utils_openssl.cc',
               'socket/ssl_client_socket_openssl_unittest.cc',
               'ssl/ssl_client_session_cache_openssl_unittest.cc',
@@ -693,7 +687,6 @@
         {
           'action_name': 'net_resources',
           'variables': {
-            'grit_whitelist': '',
             'grit_grd_file': 'base/net_resources.grd',
           },
           'includes': [ '../build/grit_action.gypi' ],
diff --git a/net/net.gypi b/net/net.gypi
index d8f9ffa..616ec45d 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -1350,7 +1350,6 @@
       'cert/test_root_certs_unittest.cc',
       'cert/x509_cert_types_unittest.cc',
       'cert/x509_certificate_unittest.cc',
-      'cert/x509_util_openssl_unittest.cc',
       'cert/x509_util_unittest.cc',
       'cert_net/cert_net_fetcher_impl_unittest.cc',
       'cert_net/nss_ocsp_unittest.cc',
@@ -1626,6 +1625,8 @@
       'quic/test_tools/quic_spdy_session_peer.h',
       'quic/test_tools/quic_spdy_stream_peer.cc',
       'quic/test_tools/quic_spdy_stream_peer.h',
+      'quic/test_tools/quic_stream_factory_peer.cc',
+      'quic/test_tools/quic_stream_factory_peer.h',
       'quic/test_tools/quic_stream_sequencer_peer.cc',
       'quic/test_tools/quic_stream_sequencer_peer.h',
       'quic/test_tools/quic_sustained_bandwidth_recorder_peer.cc',
diff --git a/net/proxy/proxy_resolver_factory_mojo_unittest.cc b/net/proxy/proxy_resolver_factory_mojo_unittest.cc
index 69e0f4e..27d371e 100644
--- a/net/proxy/proxy_resolver_factory_mojo_unittest.cc
+++ b/net/proxy/proxy_resolver_factory_mojo_unittest.cc
@@ -8,10 +8,10 @@
 #include <map>
 #include <queue>
 #include <string>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "base/values.h"
@@ -201,7 +201,8 @@
 
   base::Closure quit_closure_;
 
-  ScopedVector<interfaces::ProxyResolverRequestClientPtr> blocked_clients_;
+  std::vector<scoped_ptr<interfaces::ProxyResolverRequestClientPtr>>
+      blocked_clients_;
   mojo::Binding<interfaces::ProxyResolver> binding_;
 };
 
@@ -275,8 +276,8 @@
       interfaces::HostResolverRequestClientPtr dns_client;
       mojo::GetProxy(&dns_client);
       client->ResolveDns(request.Pass(), dns_client.Pass());
-      blocked_clients_.push_back(
-          new interfaces::ProxyResolverRequestClientPtr(client.Pass()));
+      blocked_clients_.push_back(make_scoped_ptr(
+          new interfaces::ProxyResolverRequestClientPtr(std::move(client))));
       break;
     }
   }
@@ -351,9 +352,9 @@
 
   base::Closure quit_closure_;
 
-  ScopedVector<interfaces::ProxyResolverFactoryRequestClientPtr>
+  std::vector<scoped_ptr<interfaces::ProxyResolverFactoryRequestClientPtr>>
       blocked_clients_;
-  ScopedVector<mojo::InterfaceRequest<interfaces::ProxyResolver>>
+  std::vector<scoped_ptr<mojo::InterfaceRequest<interfaces::ProxyResolver>>>
       blocked_resolver_requests_;
   mojo::Binding<interfaces::ProxyResolverFactory> binding_;
 };
@@ -411,14 +412,15 @@
     case CreateProxyResolverAction::DROP_CLIENT: {
       // Save |request| so its pipe isn't closed.
       blocked_resolver_requests_.push_back(
-          new mojo::InterfaceRequest<interfaces::ProxyResolver>(
-              request.Pass()));
+          make_scoped_ptr(new mojo::InterfaceRequest<interfaces::ProxyResolver>(
+              std::move(request))));
       break;
     }
     case CreateProxyResolverAction::DROP_RESOLVER: {
       // Save |client| so its pipe isn't closed.
       blocked_clients_.push_back(
-          new interfaces::ProxyResolverFactoryRequestClientPtr(client.Pass()));
+          make_scoped_ptr(new interfaces::ProxyResolverFactoryRequestClientPtr(
+              std::move(client))));
       break;
     }
     case CreateProxyResolverAction::DROP_BOTH: {
@@ -436,9 +438,10 @@
       request->port = 12345;
       interfaces::HostResolverRequestClientPtr dns_client;
       mojo::GetProxy(&dns_client);
-      client->ResolveDns(request.Pass(), dns_client.Pass());
+      client->ResolveDns(request.Pass(), std::move(dns_client));
       blocked_clients_.push_back(
-          new interfaces::ProxyResolverFactoryRequestClientPtr(client.Pass()));
+          make_scoped_ptr(new interfaces::ProxyResolverFactoryRequestClientPtr(
+              std::move(client))));
       break;
     }
   }
diff --git a/net/quic/congestion_control/general_loss_algorithm_test.cc b/net/quic/congestion_control/general_loss_algorithm_test.cc
index 03f20a0e..5e71df1 100644
--- a/net/quic/congestion_control/general_loss_algorithm_test.cc
+++ b/net/quic/congestion_control/general_loss_algorithm_test.cc
@@ -33,9 +33,9 @@
 
   void SendDataPacket(QuicPacketNumber packet_number) {
     packets_.push_back(new QuicEncryptedPacket(nullptr, kDefaultLength));
-    SerializedPacket packet(
-        packet_number, PACKET_1BYTE_PACKET_NUMBER, packets_.back(), 0,
-        new RetransmittableFrames(ENCRYPTION_NONE), false, false);
+    SerializedPacket packet(packet_number, PACKET_1BYTE_PACKET_NUMBER,
+                            packets_.back(), 0, new RetransmittableFrames(),
+                            false, false);
     unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, clock_.Now(),
                                    1000, true);
   }
diff --git a/net/quic/congestion_control/send_algorithm_simulator.cc b/net/quic/congestion_control/send_algorithm_simulator.cc
index a295708..08004f2 100644
--- a/net/quic/congestion_control/send_algorithm_simulator.cc
+++ b/net/quic/congestion_control/send_algorithm_simulator.cc
@@ -4,6 +4,8 @@
 
 #include "net/quic/congestion_control/send_algorithm_simulator.h"
 
+#include <stdint.h>
+
 #include <limits>
 
 #include "base/logging.h"
@@ -69,7 +71,7 @@
       rtt_(rtt),
       buffer_size_(1000000),
       delayed_ack_timer_(QuicTime::Delta::FromMilliseconds(100)) {
-  uint32 seed = base::RandInt(0, std::numeric_limits<int32>::max());
+  uint32_t seed = base::RandInt(0, std::numeric_limits<int32_t>::max());
   DVLOG(1) << "Seeding SendAlgorithmSimulator with " << seed;
   simple_random_.set_seed(seed);
 }
@@ -89,7 +91,8 @@
 }
 
 void SendAlgorithmSimulator::TransferBytes() {
-  TransferBytes(kuint64max, QuicTime::Delta::Infinite());
+  TransferBytes(std::numeric_limits<uint64_t>::max(),
+                QuicTime::Delta::Infinite());
 }
 
 void SendAlgorithmSimulator::TransferBytes(QuicByteCount max_bytes,
@@ -186,8 +189,8 @@
   Sender* sender = transfer->sender;
   if (sender->next_acked == sender->last_acked) {
     // Determine if the next ack is lost only once, to ensure determinism.
-    lose_next_ack_ =
-        reverse_loss_rate_ * kuint64max > simple_random_.RandUint64();
+    lose_next_ack_ = reverse_loss_rate_ * std::numeric_limits<uint64_t>::max() >
+                     simple_random_.RandUint64();
   }
 
   QuicPacketNumber next_acked = sender->last_acked;
@@ -357,10 +360,12 @@
     // TODO(ianswett): This buffer simulation is an approximation.
     // An ack time of zero means loss.
     bool packet_lost =
-        forward_loss_rate_ * kuint64max > simple_random_.RandUint64();
+        forward_loss_rate_ * std::numeric_limits<uint64_t>::max() >
+        simple_random_.RandUint64();
     // Handle correlated loss.
     if (!sent_packets_.empty() && sent_packets_.back().lost &&
-        loss_correlation_ * kuint64max > simple_random_.RandUint64()) {
+        loss_correlation_ * std::numeric_limits<uint64_t>::max() >
+            simple_random_.RandUint64()) {
       packet_lost = true;
     }
     DVLOG(1) << "losing packet:" << sender->last_sent
diff --git a/net/quic/congestion_control/tcp_loss_algorithm_test.cc b/net/quic/congestion_control/tcp_loss_algorithm_test.cc
index c80f5ac..c8ace676 100644
--- a/net/quic/congestion_control/tcp_loss_algorithm_test.cc
+++ b/net/quic/congestion_control/tcp_loss_algorithm_test.cc
@@ -36,9 +36,9 @@
 
   void SendDataPacket(QuicPacketNumber packet_number) {
     packets_.push_back(new QuicEncryptedPacket(nullptr, kDefaultLength));
-    SerializedPacket packet(
-        packet_number, PACKET_1BYTE_PACKET_NUMBER, packets_.back(), 0,
-        new RetransmittableFrames(ENCRYPTION_NONE), false, false);
+    SerializedPacket packet(packet_number, PACKET_1BYTE_PACKET_NUMBER,
+                            packets_.back(), 0, new RetransmittableFrames(),
+                            false, false);
     unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, clock_.Now(),
                                    1000, true);
   }
diff --git a/net/quic/congestion_control/time_loss_algorithm_test.cc b/net/quic/congestion_control/time_loss_algorithm_test.cc
index b718735..22409359 100644
--- a/net/quic/congestion_control/time_loss_algorithm_test.cc
+++ b/net/quic/congestion_control/time_loss_algorithm_test.cc
@@ -36,9 +36,9 @@
 
   void SendDataPacket(QuicPacketNumber packet_number) {
     packets_.push_back(new QuicEncryptedPacket(nullptr, kDefaultLength));
-    SerializedPacket packet(
-        packet_number, PACKET_1BYTE_PACKET_NUMBER, packets_.back(), 0,
-        new RetransmittableFrames(ENCRYPTION_NONE), false, false);
+    SerializedPacket packet(packet_number, PACKET_1BYTE_PACKET_NUMBER,
+                            packets_.back(), 0, new RetransmittableFrames(),
+                            false, false);
     unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, clock_.Now(),
                                    1000, true);
   }
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index b2e3ff9..6c68886 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -168,6 +168,9 @@
 
 // Universal tags
 const QuicTag kPAD  = TAG('P', 'A', 'D', '\0');  // Padding
+
+// Sent by clients with the fix to crbug/566156
+const QuicTag kFIXD = TAG('F', 'I', 'X', 'D');   // Client hello
 // clang-format on
 
 // These tags have a special form so that they appear either at the beginning
diff --git a/net/quic/crypto/proof_verifier_chromium_test.cc b/net/quic/crypto/proof_verifier_chromium_test.cc
index ee418e84..76b56b1 100644
--- a/net/quic/crypto/proof_verifier_chromium_test.cc
+++ b/net/quic/crypto/proof_verifier_chromium_test.cc
@@ -183,15 +183,41 @@
     certs->push_back(der_bytes);
   }
 
+  std::string GetSCTListForTesting() {
+    const std::string sct = ct::GetTestSignedCertificateTimestamp();
+    std::string sct_list;
+    ct::EncodeSCTListForTesting(sct, &sct_list);
+    return sct_list;
+  }
+
+  std::string GetCorruptSCTListForTesting() {
+    std::string sct = ct::GetTestSignedCertificateTimestamp();
+    sct[15] = 't';  // Corrupt a byte inside SCT.
+    std::string sct_list;
+    ct::EncodeSCTListForTesting(sct, &sct_list);
+    return sct_list;
+  }
+
+  bool CheckForSingleVerifiedSCTInResult(const ct::CTVerifyResult& result) {
+    return (result.verified_scts.size() == 1U) && result.invalid_scts.empty() &&
+           result.unknown_logs_scts.empty() &&
+           result.verified_scts[0]->log_description == kLogDescription;
+  }
+
+  bool CheckForSCTOrigin(const ct::CTVerifyResult& result,
+                         ct::SignedCertificateTimestamp::Origin origin) {
+    return (result.verified_scts.size() > 0) &&
+           (result.verified_scts[0]->origin == origin);
+  }
+
   void CheckSCT(bool sct_expected_ok) {
     ProofVerifyDetailsChromium* proof_details =
         reinterpret_cast<ProofVerifyDetailsChromium*>(details_.get());
     const ct::CTVerifyResult& ct_verify_result =
         proof_details->ct_verify_result;
     if (sct_expected_ok) {
-      ASSERT_TRUE(ct::CheckForSingleVerifiedSCTInResult(ct_verify_result,
-                                                        kLogDescription));
-      ASSERT_TRUE(ct::CheckForSCTOrigin(
+      ASSERT_TRUE(CheckForSingleVerifiedSCTInResult(ct_verify_result));
+      ASSERT_TRUE(CheckForSCTOrigin(
           ct_verify_result,
           ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION));
     } else {
@@ -235,7 +261,7 @@
   scoped_ptr<DummyProofVerifierCallback> callback(
       new DummyProofVerifierCallback);
   QuicAsyncStatus status = proof_verifier.VerifyProof(
-      kTestHostname, kTestConfig, certs_, ct::GetSCTListForTesting(), "",
+      kTestHostname, kTestConfig, certs_, GetSCTListForTesting(), "",
       verify_context_.get(), &error_details_, &details_, callback.get());
   ASSERT_EQ(QUIC_FAILURE, status);
   CheckSCT(/*sct_expected_ok=*/true);
@@ -253,7 +279,7 @@
   scoped_ptr<DummyProofVerifierCallback> callback(
       new DummyProofVerifierCallback);
   QuicAsyncStatus status = proof_verifier.VerifyProof(
-      kTestHostname, kTestConfig, certs_, ct::GetSCTListWithInvalidSCT(), "",
+      kTestHostname, kTestConfig, certs_, GetCorruptSCTListForTesting(), "",
       verify_context_.get(), &error_details_, &details_, callback.get());
   ASSERT_EQ(QUIC_FAILURE, status);
   CheckSCT(/*sct_expected_ok=*/false);
diff --git a/net/quic/crypto/quic_crypto_client_config.cc b/net/quic/crypto/quic_crypto_client_config.cc
index a07871d..ac592b6 100644
--- a/net/quic/crypto/quic_crypto_client_config.cc
+++ b/net/quic/crypto/quic_crypto_client_config.cc
@@ -5,7 +5,6 @@
 #include "net/quic/crypto/quic_crypto_client_config.h"
 
 #include "base/metrics/histogram_macros.h"
-#include "base/metrics/sparse_histogram.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "net/quic/crypto/cert_compressor.h"
@@ -773,26 +772,6 @@
     out_params->server_nonce = nonce.as_string();
   }
 
-  const uint32* reject_reasons;
-  size_t num_reject_reasons;
-  static_assert(sizeof(QuicTag) == sizeof(uint32), "header out of sync");
-  if (rej.GetTaglist(kRREJ, &reject_reasons,
-                     &num_reject_reasons) == QUIC_NO_ERROR) {
-    uint32 packed_error = 0;
-    for (size_t i = 0; i < num_reject_reasons; ++i) {
-      // HANDSHAKE_OK is 0 and don't report that as error.
-      if (reject_reasons[i] == HANDSHAKE_OK || reject_reasons[i] >= 32) {
-        continue;
-      }
-      HandshakeFailureReason reason =
-          static_cast<HandshakeFailureReason>(reject_reasons[i]);
-      packed_error |= 1 << (reason - 1);
-    }
-    DVLOG(1) << "Reasons for rejection: " << packed_error;
-    UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Secure",
-                                packed_error);
-  }
-
   if (rej.tag() == kSREJ) {
     QuicConnectionId connection_id;
     if (rej.GetUint64(kRCID, &connection_id) != QUIC_NO_ERROR) {
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc
index c082a653d..108c6cf8 100644
--- a/net/quic/quic_chromium_client_session.cc
+++ b/net/quic/quic_chromium_client_session.cc
@@ -661,6 +661,12 @@
 void QuicChromiumClientSession::OnCryptoHandshakeMessageSent(
     const CryptoHandshakeMessage& message) {
   logger_->OnCryptoHandshakeMessageSent(message);
+
+  if (message.tag() == kREJ || message.tag() == kSREJ) {
+    UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.RejectLength",
+                                message.GetSerialized().length(), 1000, 10000,
+                                50);
+  }
 }
 
 void QuicChromiumClientSession::OnCryptoHandshakeMessageReceived(
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 2bb8d0e..6be348c 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -237,20 +237,16 @@
 
 }  // namespace
 
-QuicConnection::QueuedPacket::QueuedPacket(SerializedPacket packet,
-                                           EncryptionLevel level)
+QuicConnection::QueuedPacket::QueuedPacket(SerializedPacket packet)
     : serialized_packet(packet),
-      encryption_level(level),
       transmission_type(NOT_RETRANSMISSION),
       original_packet_number(0) {}
 
 QuicConnection::QueuedPacket::QueuedPacket(
     SerializedPacket packet,
-    EncryptionLevel level,
     TransmissionType transmission_type,
     QuicPacketNumber original_packet_number)
     : serialized_packet(packet),
-      encryption_level(level),
       transmission_type(transmission_type),
       original_packet_number(original_packet_number) {}
 
@@ -623,6 +619,19 @@
   // routed to this QuicConnection has been redirected before control reaches
   // here.
   DCHECK_EQ(connection_id_, header.public_header.connection_id);
+
+  // If this packet has already been seen, or the sender has told us that it
+  // will not be retransmitted, then stop processing the packet.
+  if (!received_packet_manager_.IsAwaitingPacket(header.packet_number)) {
+    DVLOG(1) << ENDPOINT << "Packet " << header.packet_number
+             << " no longer being waited for.  Discarding.";
+    if (debug_visitor_ != nullptr) {
+      debug_visitor_->OnDuplicatePacket(header.packet_number);
+    }
+    ++stats_.packets_dropped;
+    return false;
+  }
+
   return true;
 }
 
@@ -678,7 +687,7 @@
     return false;
   }
   visitor_->OnStreamFrame(frame);
-  stats_.stream_bytes_received += frame.data.size();
+  stats_.stream_bytes_received += frame.frame_length;
   should_last_packet_instigate_acks_ = true;
   return connected_;
 }
@@ -1353,17 +1362,6 @@
     return false;
   }
 
-  // If this packet has already been seen, or the sender has told us that it
-  // will not be retransmitted, then stop processing the packet.
-  if (!received_packet_manager_.IsAwaitingPacket(header.packet_number)) {
-    DVLOG(1) << ENDPOINT << "Packet " << header.packet_number
-             << " no longer being waited for.  Discarding.";
-    if (debug_visitor_ != nullptr) {
-      debug_visitor_->OnDuplicatePacket(header.packet_number);
-    }
-    return false;
-  }
-
   if (version_negotiation_state_ != NEGOTIATED_VERSION) {
     if (perspective_ == Perspective::IS_SERVER) {
       if (!header.public_header.version_flag) {
@@ -1462,8 +1460,8 @@
     packet_generator_.FlushAllQueuedFrames();
     char buffer[kMaxPacketSize];
     SerializedPacket serialized_packet = packet_generator_.ReserializeAllFrames(
-        pending.retransmittable_frames, pending.packet_number_length, buffer,
-        kMaxPacketSize);
+        pending.retransmittable_frames, pending.encryption_level,
+        pending.packet_number_length, buffer, kMaxPacketSize);
     if (serialized_packet.packet == nullptr) {
       // We failed to serialize the packet, so close the connection.
       // CloseConnection does not send close packet, so no infinite loop here.
@@ -1473,9 +1471,8 @@
 
     DVLOG(1) << ENDPOINT << "Retransmitting " << pending.packet_number << " as "
              << serialized_packet.packet_number;
-    SendOrQueuePacket(QueuedPacket(
-        serialized_packet, pending.retransmittable_frames.encryption_level(),
-        pending.transmission_type, pending.packet_number));
+    SendOrQueuePacket(QueuedPacket(serialized_packet, pending.transmission_type,
+                                   pending.packet_number));
   }
 }
 
@@ -1601,7 +1598,8 @@
                           ? "data bearing "
                           : " ack only "))
            << ", encryption level: "
-           << QuicUtils::EncryptionLevelToString(packet->encryption_level)
+           << QuicUtils::EncryptionLevelToString(
+                  packet->serialized_packet.encryption_level)
            << ", encrypted length:" << encrypted->length();
   DVLOG(2) << ENDPOINT << "packet(" << packet_number << "): " << std::endl
            << QuicUtils::StringToHexASCIIDump(encrypted->AsStringPiece());
@@ -1632,8 +1630,7 @@
     // Pass the write result to the visitor.
     debug_visitor_->OnPacketSent(
         packet->serialized_packet, packet->original_packet_number,
-        packet->encryption_level, packet->transmission_type,
-        encrypted->length(), packet_send_time);
+        packet->transmission_type, encrypted->length(), packet_send_time);
   }
   if (packet->transmission_type == NOT_RETRANSMISSION) {
     time_of_last_sent_new_packet_ = packet_send_time;
@@ -1694,7 +1691,7 @@
 
   QuicPacketNumber packet_number = packet.serialized_packet.packet_number;
   if (encryption_level_ == ENCRYPTION_FORWARD_SECURE &&
-      packet.encryption_level == ENCRYPTION_NONE) {
+      packet.serialized_packet.encryption_level == ENCRYPTION_NONE) {
     // Drop packets that are NULL encrypted since the peer won't accept them
     // anymore.
     DVLOG(1) << ENDPOINT << "Dropping NULL encrypted packet: " << packet_number
@@ -1735,7 +1732,7 @@
     // If an FEC packet is serialized with the FEC alarm set, cancel the alarm.
     fec_alarm_->Cancel();
   }
-  SendOrQueuePacket(QueuedPacket(serialized_packet, encryption_level_));
+  SendOrQueuePacket(QueuedPacket(serialized_packet));
 }
 
 void QuicConnection::OnResetFecGroup() {
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index 146324b..971ec01 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -156,7 +156,6 @@
   // Called when a packet has been sent.
   virtual void OnPacketSent(const SerializedPacket& serialized_packet,
                             QuicPacketNumber original_packet_number,
-                            EncryptionLevel level,
                             TransmissionType transmission_type,
                             size_t encrypted_length,
                             QuicTime sent_time) {}
@@ -632,17 +631,13 @@
 
  protected:
   // Packets which have not been written to the wire.
-  // Owns the QuicPacket* packet.
   struct QueuedPacket {
+    explicit QueuedPacket(SerializedPacket packet);
     QueuedPacket(SerializedPacket packet,
-                 EncryptionLevel level);
-    QueuedPacket(SerializedPacket packet,
-                 EncryptionLevel level,
                  TransmissionType transmission_type,
                  QuicPacketNumber original_packet_number);
 
     SerializedPacket serialized_packet;
-    const EncryptionLevel encryption_level;
     TransmissionType transmission_type;
     // The packet's original packet number if it is a retransmission.
     // Otherwise it must be 0.
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index b1446a4..f4d4f6aa 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -49,13 +49,11 @@
 
 scoped_ptr<base::Value> NetLogQuicPacketSentCallback(
     const SerializedPacket& serialized_packet,
-    EncryptionLevel level,
     TransmissionType transmission_type,
     size_t packet_size,
     QuicTime sent_time,
     NetLogCaptureMode /* capture_mode */) {
   scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-  dict->SetInteger("encryption_level", level);
   dict->SetInteger("transmission_type", transmission_type);
   dict->SetString("packet_number",
                   base::Uint64ToString(serialized_packet.packet_number));
@@ -105,7 +103,7 @@
   dict->SetInteger("stream_id", frame->stream_id);
   dict->SetBoolean("fin", frame->fin);
   dict->SetString("offset", base::Uint64ToString(frame->offset));
-  dict->SetInteger("length", frame->data.size());
+  dict->SetInteger("length", frame->frame_length);
   return dict.Pass();
 }
 
@@ -436,14 +434,13 @@
 void QuicConnectionLogger::OnPacketSent(
     const SerializedPacket& serialized_packet,
     QuicPacketNumber original_packet_number,
-    EncryptionLevel level,
     TransmissionType transmission_type,
     size_t encrypted_length,
     QuicTime sent_time) {
   if (original_packet_number == 0) {
     net_log_.AddEvent(
         NetLog::TYPE_QUIC_SESSION_PACKET_SENT,
-        base::Bind(&NetLogQuicPacketSentCallback, serialized_packet, level,
+        base::Bind(&NetLogQuicPacketSentCallback, serialized_packet,
                    transmission_type, encrypted_length, sent_time));
   }  else {
     net_log_.AddEvent(
diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h
index 358bd80..7bf86eab 100644
--- a/net/quic/quic_connection_logger.h
+++ b/net/quic/quic_connection_logger.h
@@ -42,7 +42,6 @@
   // QuicConnectionDebugVisitorInterface
   void OnPacketSent(const SerializedPacket& serialized_packet,
                     QuicPacketNumber original_packet_number,
-                    EncryptionLevel level,
                     TransmissionType transmission_type,
                     size_t encrypted_length,
                     QuicTime sent_time) override;
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index f33696a..cf8d3a2 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -453,17 +453,17 @@
                   bool has_pending_frames) {
     RetransmittableFrames* retransmittable_frames =
         retransmittable == HAS_RETRANSMITTABLE_DATA
-            ? new RetransmittableFrames(ENCRYPTION_NONE)
+            ? new RetransmittableFrames()
             : nullptr;
     char buffer[kMaxPacketSize];
     size_t encrypted_length =
         QuicConnectionPeer::GetFramer(this)->EncryptPayload(
             ENCRYPTION_NONE, packet_number, *packet, buffer, kMaxPacketSize);
     delete packet;
-    OnSerializedPacket(
-        SerializedPacket(packet_number, PACKET_6BYTE_PACKET_NUMBER, buffer,
-                         encrypted_length, false, entropy_hash,
-                         retransmittable_frames, has_ack, has_pending_frames));
+    OnSerializedPacket(SerializedPacket(
+        packet_number, PACKET_6BYTE_PACKET_NUMBER, buffer, encrypted_length,
+        false, entropy_hash, retransmittable_frames, has_ack,
+        has_pending_frames, ENCRYPTION_NONE));
   }
 
   QuicConsumedData SendStreamDataWithString(
@@ -2374,7 +2374,7 @@
   EXPECT_EQ(1u, writer_->stream_frames().size());
   QuicStreamFrame* frame = writer_->stream_frames()[0];
   EXPECT_EQ(1u, frame->stream_id);
-  EXPECT_EQ("ABCD", frame->data);
+  EXPECT_EQ("ABCD", StringPiece(frame->frame_buffer, frame->frame_length));
 }
 
 TEST_P(QuicConnectionTest, FramePackingSendvQueued) {
@@ -5377,6 +5377,8 @@
       new MockQuicConnectionDebugVisitor());
   connection_.set_debug_visitor(debug_visitor.get());
   EXPECT_CALL(*debug_visitor, OnPacketHeader(Ref(header))).Times(1);
+  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)).Times(1);
+  EXPECT_CALL(*debug_visitor, OnSuccessfulVersionNegotiation(_)).Times(1);
   connection_.OnPacketHeader(header);
 }
 
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index 668cff9..ce32893ab 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -4,7 +4,10 @@
 
 #include "net/quic/quic_crypto_client_stream.h"
 
+#include <vector>
+
 #include "base/metrics/histogram_macros.h"
+#include "base/metrics/sparse_histogram.h"
 #include "net/quic/crypto/crypto_protocol.h"
 #include "net/quic/crypto/crypto_utils.h"
 #include "net/quic/crypto/null_encrypter.h"
@@ -14,9 +17,30 @@
 #include "net/quic/quic_session.h"
 
 using std::string;
+using std::vector;
 
 namespace net {
 
+namespace {
+
+void AppendFixed(CryptoHandshakeMessage* message) {
+  vector<QuicTag> tags;
+  tags.push_back(kFIXD);
+
+  const QuicTag* received_tags;
+  size_t received_tags_length;
+  QuicErrorCode error =
+      message->GetTaglist(kCOPT, &received_tags, &received_tags_length);
+  if (error == QUIC_NO_ERROR) {
+    for (size_t i = 0; i < received_tags_length; ++i) {
+      tags.push_back(received_tags[i]);
+    }
+  }
+  message->SetVector(kCOPT, tags);
+}
+
+}  // namespace
+
 QuicCryptoClientStreamBase::QuicCryptoClientStreamBase(
     QuicClientSessionBase* session)
     : QuicCryptoStream(session) {}
@@ -268,6 +292,12 @@
   // Send all the options, regardless of whether we're sending an
   // inchoate or subsequent hello.
   session()->config()->ToHandshakeMessage(&out);
+
+  // This block and function should be removed after removing QUIC_VERSION_25.
+  if (FLAGS_quic_require_fix) {
+    AppendFixed(&out);
+  }
+
   if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
     crypto_config_->FillInchoateClientHello(
         server_id_,
@@ -366,6 +396,31 @@
                                "Expected REJ");
     return;
   }
+
+  const uint32* reject_reasons;
+  size_t num_reject_reasons;
+  static_assert(sizeof(QuicTag) == sizeof(uint32), "header out of sync");
+  if (in->GetTaglist(kRREJ, &reject_reasons, &num_reject_reasons) ==
+      QUIC_NO_ERROR) {
+    uint32 packed_error = 0;
+    for (size_t i = 0; i < num_reject_reasons; ++i) {
+      // HANDSHAKE_OK is 0 and don't report that as error.
+      if (reject_reasons[i] == HANDSHAKE_OK || reject_reasons[i] >= 32) {
+        continue;
+      }
+      HandshakeFailureReason reason =
+          static_cast<HandshakeFailureReason>(reject_reasons[i]);
+      packed_error |= 1 << (reason - 1);
+    }
+    DVLOG(1) << "Reasons for rejection: " << packed_error;
+    if (num_client_hellos_ == kMaxClientHellos) {
+      UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.TooMany",
+                                  packed_error);
+    }
+    UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Secure",
+                                packed_error);
+  }
+
   stateless_reject_received_ = in->tag() == kSREJ;
   string error_details;
   QuicErrorCode error = crypto_config_->ProcessRejection(
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index e041724..ea4b35d5 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -20,6 +20,24 @@
 
 namespace net {
 
+namespace {
+bool HasFixedTag(const CryptoHandshakeMessage& message) {
+  const QuicTag* received_tags;
+  size_t received_tags_length;
+  QuicErrorCode error =
+      message.GetTaglist(kCOPT, &received_tags, &received_tags_length);
+  if (error == QUIC_NO_ERROR) {
+    DCHECK(received_tags);
+    for (size_t i = 0; i < received_tags_length; ++i) {
+      if (received_tags[i] == kFIXD) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+}  // namespace
+
 void ServerHelloNotifier::OnPacketAcked(
     int acked_bytes,
     QuicTime::Delta delta_largest_observed) {
@@ -63,6 +81,12 @@
   QuicCryptoServerStreamBase::OnHandshakeMessage(message);
   ++num_handshake_messages_;
 
+  // This block should be removed with support for QUIC_VERSION_25.
+  if (FLAGS_quic_require_fix && !HasFixedTag(message)) {
+    CloseConnection(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND);
+    return;
+  }
+
   // Do not process handshake messages after the handshake is confirmed.
   if (handshake_confirmed_) {
     CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc
index 232bb17..3358147 100644
--- a/net/quic/quic_crypto_server_stream_test.cc
+++ b/net/quic/quic_crypto_server_stream_test.cc
@@ -375,6 +375,7 @@
 }
 
 TEST_P(QuicCryptoServerStreamTest, MessageAfterHandshake) {
+  FLAGS_quic_require_fix = false;
   Initialize();
   CompleteCryptoHandshake();
   EXPECT_CALL(
@@ -388,6 +389,7 @@
 }
 
 TEST_P(QuicCryptoServerStreamTest, BadMessageType) {
+  FLAGS_quic_require_fix = false;
   Initialize();
 
   message_.set_tag(kSHLO);
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc
index 2cf2450..4d5209e 100644
--- a/net/quic/quic_flags.cc
+++ b/net/quic/quic_flags.cc
@@ -108,3 +108,6 @@
 
 // If true, Close the connection instead of writing unencrypted stream data.
 bool FLAGS_quic_never_write_unencrypted_data = true;
+
+// If true, reject any incoming QUIC which does not have the FIXD tag.
+bool FLAGS_quic_require_fix = true;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h
index 9e680687..7e426e0 100644
--- a/net/quic/quic_flags.h
+++ b/net/quic/quic_flags.h
@@ -34,5 +34,6 @@
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_batch_writes;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_block_unencrypted_writes;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_never_write_unencrypted_data;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_require_fix;
 
 #endif  // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index d7849fb..dea85da 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -1291,17 +1291,21 @@
     return false;
   }
 
+  // TODO(ianswett): Don't use StringPiece as an intermediary.
+  StringPiece data;
   if (has_data_length) {
-    if (!reader->ReadStringPiece16(&frame->data)) {
+    if (!reader->ReadStringPiece16(&data)) {
       set_detailed_error("Unable to read frame data.");
       return false;
     }
   } else {
-    if (!reader->ReadStringPiece(&frame->data, reader->BytesRemaining())) {
+    if (!reader->ReadStringPiece(&data, reader->BytesRemaining())) {
       set_detailed_error("Unable to read frame data.");
       return false;
     }
   }
+  frame->frame_buffer = data.data();
+  frame->frame_length = static_cast<uint16>(data.length());
 
   return true;
 }
@@ -1768,7 +1772,7 @@
       return GetMinStreamFrameSize(frame.stream_frame->stream_id,
                                    frame.stream_frame->offset,
                                    last_frame_in_packet, is_in_fec_group) +
-             frame.stream_frame->data.length();
+             frame.stream_frame->frame_length;
     case ACK_FRAME: {
       return GetAckFrameSize(*frame.ack_frame, packet_number_length);
     }
@@ -1886,14 +1890,14 @@
     return false;
   }
   if (!no_stream_frame_length) {
-    if ((frame.data.size() > numeric_limits<uint16>::max()) ||
-        !writer->WriteUInt16(static_cast<uint16>(frame.data.size()))) {
+    if ((frame.frame_length > numeric_limits<uint16>::max()) ||
+        !writer->WriteUInt16(static_cast<uint16>(frame.frame_length))) {
       LOG(DFATAL) << "Writing stream frame length failed";
       return false;
     }
   }
 
-  if (!writer->WriteBytes(frame.data.data(), frame.data.size())) {
+  if (!writer->WriteBytes(frame.frame_buffer, frame.frame_length)) {
     LOG(DFATAL) << "Writing frame data failed.";
     return false;
   }
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index 4f7e6f48..d967c22 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -263,10 +263,11 @@
     ++frame_count_;
     // Save a copy of the data so it is valid after the packet is processed.
     string* string_data = new string();
-    frame.data.AppendToString(string_data);
+    StringPiece(frame.frame_buffer, frame.frame_length)
+        .AppendToString(string_data);
     stream_data_.push_back(string_data);
-    stream_frames_.push_back(new QuicStreamFrame(
-        frame.stream_id, frame.fin, frame.offset, StringPiece(*string_data)));
+    stream_frames_.push_back(new QuicStreamFrame(frame.stream_id, frame.fin,
+                                                 frame.offset, *string_data));
     return true;
   }
 
@@ -444,7 +445,7 @@
 
   // Checks if the supplied string matches data in the supplied StreamFrame.
   void CheckStreamFrameData(string str, QuicStreamFrame* frame) {
-    EXPECT_EQ(str, frame->data);
+    EXPECT_EQ(str, string(frame->frame_buffer, frame->frame_length));
   }
 
   void CheckStreamFrameBoundaries(unsigned char* packet,
@@ -4540,7 +4541,8 @@
 static QuicStreamId kTestQuicStreamId = 1;
 static bool ExpectedStreamFrame(const QuicStreamFrame& frame) {
   return frame.stream_id == kTestQuicStreamId && !frame.fin &&
-         frame.offset == 0 && frame.data == kTestString;
+         frame.offset == 0 &&
+         string(frame.frame_buffer, frame.frame_length) == kTestString;
   // FIN is hard-coded false in ConstructEncryptedPacket.
   // Offset 0 is hard-coded in ConstructEncryptedPacket.
 }
diff --git a/net/quic/quic_headers_stream_test.cc b/net/quic/quic_headers_stream_test.cc
index 1c70050..680bdf2 100644
--- a/net/quic/quic_headers_stream_test.cc
+++ b/net/quic/quic_headers_stream_test.cc
@@ -328,7 +328,8 @@
                        &QuicHeadersStreamTest::SaveHeaderDataStringPiece)));
         EXPECT_CALL(session_,
                     OnStreamHeadersComplete(stream_id, fin, frame->size()));
-        stream_frame_.data = StringPiece(frame->data(), frame->size());
+        stream_frame_.frame_buffer = frame->data();
+        stream_frame_.frame_length = frame->size();
         headers_stream_->OnStreamFrame(stream_frame_);
         stream_frame_.offset += frame->size();
         CheckHeaders();
@@ -361,7 +362,8 @@
     EXPECT_CALL(session_, OnStreamHeaders(stream_id, _));
     EXPECT_CALL(session_,
                 OnStreamHeadersComplete(stream_id, fin, frame->size()));
-    stream_frame_.data = StringPiece(frame->data(), frame->size());
+    stream_frame_.frame_buffer = frame->data();
+    stream_frame_.frame_length = frame->size();
     headers_stream_->OnStreamFrame(stream_frame_);
     connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
     stream_frame_.offset += frame->size();
@@ -393,8 +395,8 @@
       }
       stream_frames[stream_num].stream_id = stream_frame_.stream_id;
       stream_frames[stream_num].offset = stream_frame_.offset;
-      stream_frames[stream_num].data =
-          StringPiece(frames[stream_num]->data(), frames[stream_num]->size());
+      stream_frames[stream_num].frame_buffer = frames[stream_num]->data();
+      stream_frames[stream_num].frame_length = frames[stream_num]->size();
       DVLOG(1) << "make frame for stream " << stream_num << " offset "
                << stream_frames[stream_num].offset;
       stream_frame_.offset += frames[stream_num]->size();
@@ -446,7 +448,8 @@
                 this, &QuicHeadersStreamTest::SaveHeaderDataStringPiece)));
         EXPECT_CALL(session_,
                     OnStreamHeadersComplete(stream_id, fin, frame->size()));
-        stream_frame_.data = StringPiece(frame->data(), frame->size());
+        stream_frame_.frame_buffer = frame->data();
+        stream_frame_.frame_length = frame->size();
         headers_stream_->OnStreamFrame(stream_frame_);
         stream_frame_.offset += frame->size();
         CheckHeaders();
@@ -460,7 +463,8 @@
   EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(
                                 QUIC_INVALID_HEADERS_STREAM_DATA, _))
       .Times(::testing::AnyNumber());
-  stream_frame_.data = StringPiece(kBadData, strlen(kBadData));
+  stream_frame_.frame_buffer = kBadData;
+  stream_frame_.frame_length = strlen(kBadData);
   headers_stream_->OnStreamFrame(stream_frame_);
 }
 
@@ -472,7 +476,8 @@
                                              "SPDY DATA frame received."))
       .WillOnce(InvokeWithoutArgs(this,
                                   &QuicHeadersStreamTest::CloseConnection));
-  stream_frame_.data = StringPiece(frame->data(), frame->size());
+  stream_frame_.frame_buffer = frame->data();
+  stream_frame_.frame_length = frame->size();
   headers_stream_->OnStreamFrame(stream_frame_);
 }
 
@@ -485,7 +490,8 @@
                   "SPDY RST_STREAM frame received."))
       .WillOnce(InvokeWithoutArgs(this,
                                   &QuicHeadersStreamTest::CloseConnection));
-  stream_frame_.data = StringPiece(frame->data(), frame->size());
+  stream_frame_.frame_buffer = frame->data();
+  stream_frame_.frame_length = frame->size();
   headers_stream_->OnStreamFrame(stream_frame_);
 }
 
@@ -499,7 +505,8 @@
                   "SPDY SETTINGS frame received."))
       .WillOnce(InvokeWithoutArgs(this,
                                   &QuicHeadersStreamTest::CloseConnection));
-  stream_frame_.data = StringPiece(frame->data(), frame->size());
+  stream_frame_.frame_buffer = frame->data();
+  stream_frame_.frame_length = frame->size();
   headers_stream_->OnStreamFrame(stream_frame_);
 }
 
@@ -511,7 +518,8 @@
                                              "SPDY PING frame received."))
       .WillOnce(InvokeWithoutArgs(this,
                                   &QuicHeadersStreamTest::CloseConnection));
-  stream_frame_.data = StringPiece(frame->data(), frame->size());
+  stream_frame_.frame_buffer = frame->data();
+  stream_frame_.frame_length = frame->size();
   headers_stream_->OnStreamFrame(stream_frame_);
 }
 
@@ -523,7 +531,8 @@
                                              "SPDY GOAWAY frame received."))
       .WillOnce(InvokeWithoutArgs(this,
                                   &QuicHeadersStreamTest::CloseConnection));
-  stream_frame_.data = StringPiece(frame->data(), frame->size());
+  stream_frame_.frame_buffer = frame->data();
+  stream_frame_.frame_length = frame->size();
   headers_stream_->OnStreamFrame(stream_frame_);
 }
 
@@ -536,7 +545,8 @@
                   "SPDY WINDOW_UPDATE frame received."))
       .WillOnce(InvokeWithoutArgs(this,
                                   &QuicHeadersStreamTest::CloseConnection));
-  stream_frame_.data = StringPiece(frame->data(), frame->size());
+  stream_frame_.frame_buffer = frame->data();
+  stream_frame_.frame_length = frame->size();
   headers_stream_->OnStreamFrame(stream_frame_);
 }
 
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index 5b989583..b16133572 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -91,7 +91,7 @@
       framer_(framer),
       random_bool_source_(new QuicRandomBoolSource(random_generator)),
       packet_number_(0),
-      should_fec_protect_(false),
+      should_fec_protect_next_packet_(false),
       fec_protect_(false),
       send_version_in_packet_(framer->perspective() == Perspective::IS_CLIENT),
       max_packet_length_(0),
@@ -251,11 +251,16 @@
                                     QuicStreamOffset offset,
                                     bool fin,
                                     bool needs_padding,
-                                    QuicFrame* frame) {
+                                    QuicFrame* frame,
+                                    FecProtection fec_protection) {
   if (!HasRoomForStreamFrame(id, offset)) {
     Flush();
     return false;
   }
+  if (fec_protection == MUST_FEC_PROTECT) {
+    should_fec_protect_next_packet_ = true;
+    MaybeStartFecProtection();
+  }
   CreateStreamFrame(id, iov, iov_offset, offset, fin, frame);
   bool success = AddFrame(*frame,
                           /*save_retransmittable_frames=*/true, needs_padding);
@@ -321,10 +326,8 @@
   bool set_fin = fin && bytes_consumed == data_size;  // Last frame.
   UniqueStreamBuffer buffer = NewStreamBuffer(bytes_consumed);
   CopyToBuffer(iov, iov_offset, bytes_consumed, buffer.get());
-  // TODO(zhongyi): figure out the lifetime of data. Crashes on windows only.
-  StringPiece data(buffer.get(), bytes_consumed);
-  *frame = QuicFrame(
-      new QuicStreamFrame(id, set_fin, offset, data, std::move(buffer)));
+  *frame = QuicFrame(new QuicStreamFrame(id, set_fin, offset, bytes_consumed,
+                                         std::move(buffer)));
   return bytes_consumed;
 }
 
@@ -394,6 +397,7 @@
 
 SerializedPacket QuicPacketCreator::ReserializeAllFrames(
     const RetransmittableFrames& frames,
+    EncryptionLevel original_encryption_level,
     QuicPacketNumberLength original_length,
     char* buffer,
     size_t buffer_len) {
@@ -409,8 +413,13 @@
   packet_number_length_ = original_length;
   next_packet_number_length_ = original_length;
   fec_protect_ = false;
-  encryption_level_ = frames.encryption_level();
   needs_padding_ = frames.needs_padding();
+  // Only preserve the original encryption level if it's a handshake packet or
+  // if we haven't gone forward secure.
+  if (frames.HasCryptoHandshake() ||
+      encryption_level_ != ENCRYPTION_FORWARD_SECURE) {
+    encryption_level_ = original_encryption_level;
+  }
 
   // Serialize the packet and restore the FEC and packet number length state.
   SerializedPacket serialized_packet =
@@ -590,7 +599,8 @@
       header.packet_number, header.public_header.packet_number_length,
       encrypted_buffer, encrypted_length, /* owns_buffer*/ false,
       QuicFramer::GetPacketEntropyHash(header),
-      queued_retransmittable_frames_.release(), has_ack, has_stop_waiting);
+      queued_retransmittable_frames_.release(), has_ack, has_stop_waiting,
+      encryption_level_);
 }
 
 SerializedPacket QuicPacketCreator::SerializeFec(char* buffer,
@@ -620,10 +630,11 @@
     LOG(DFATAL) << "Failed to encrypt packet number " << packet_number_;
     return NoPacket();
   }
-  SerializedPacket serialized(
-      header.packet_number, header.public_header.packet_number_length, buffer,
-      encrypted_length, /* owns_buffer */ false,
-      QuicFramer::GetPacketEntropyHash(header), nullptr, false, false);
+  SerializedPacket serialized(header.packet_number,
+                              header.public_header.packet_number_length, buffer,
+                              encrypted_length, /* owns_buffer */ false,
+                              QuicFramer::GetPacketEntropyHash(header), nullptr,
+                              false, false, encryption_level_);
   serialized.is_fec_packet = true;
   return serialized;
 }
@@ -689,8 +700,7 @@
 
   if (save_retransmittable_frames && ShouldRetransmit(frame)) {
     if (queued_retransmittable_frames_.get() == nullptr) {
-      queued_retransmittable_frames_.reset(
-          new RetransmittableFrames(encryption_level_));
+      queued_retransmittable_frames_.reset(new RetransmittableFrames());
     }
     queued_frames_.push_back(queued_retransmittable_frames_->AddFrame(frame));
   } else {
@@ -748,7 +758,7 @@
     }
   }
 
-  if (!should_fec_protect_ && fec_protect_ && !IsFecGroupOpen()) {
+  if (!should_fec_protect_next_packet_ && fec_protect_ && !IsFecGroupOpen()) {
     StopFecProtectingPackets();
   }
 }
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h
index a3228ab1..152b44a 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -52,14 +52,11 @@
   // return true if an FEC group is open.
   bool ShouldSendFec(bool force_close) const;
 
-  // Turn on FEC protection for subsequent packets. If no FEC group is currently
-  // open, this method flushes current open packet and then turns FEC on.
-  void MaybeStartFecProtection();
-
   // If ShouldSendFec returns true, serializes currently constructed FEC packet
   // and calls the delegate on the packet. Resets current FEC group if FEC
   // protection policy is FEC_ALARM_TRIGGER but |is_fec_timeout| is false.
-  // Also tries to turn off FEC protection if should_fec_protect_ is false.
+  // Also tries to turn off FEC protection if should_fec_protect_next_packet is
+  // false.
   void MaybeSendFecPacketAndCloseGroup(bool force_send_fec,
                                        bool is_fec_timeout);
 
@@ -93,13 +90,15 @@
   // If current packet is not full, converts a raw payload into a stream frame
   // that fits into the open packet and adds it to the packet.
   // The payload begins at |iov_offset| into the |iov|.
+  // Also tries to start FEC protection depends on |fec_protection|.
   bool ConsumeData(QuicStreamId id,
                    QuicIOVector iov,
                    size_t iov_offset,
                    QuicStreamOffset offset,
                    bool fin,
                    bool needs_padding,
-                   QuicFrame* frame);
+                   QuicFrame* frame,
+                   FecProtection fec_protection);
 
   // Returns true if current open packet can accommodate more stream frames of
   // stream |id| at |offset|, false otherwise.
@@ -117,10 +116,12 @@
   // Used for retransmitting packets to ensure they aren't too long.
   // Caller must ensure that any open FEC group is closed before calling this
   // method.
-  SerializedPacket ReserializeAllFrames(const RetransmittableFrames& frames,
-                                        QuicPacketNumberLength original_length,
-                                        char* buffer,
-                                        size_t buffer_len);
+  SerializedPacket ReserializeAllFrames(
+      const RetransmittableFrames& frames,
+      EncryptionLevel original_encryption_level,
+      QuicPacketNumberLength original_length,
+      char* buffer,
+      size_t buffer_len);
 
   // Serializes all added frames into a single packet and invokes the delegate_
   // to further process the SerializedPacket.
@@ -229,10 +230,12 @@
     rtt_multiplier_for_fec_timeout_ = rtt_multiplier_for_fec_timeout;
   }
 
-  bool should_fec_protect() { return should_fec_protect_; }
+  bool should_fec_protect_next_packet() {
+    return should_fec_protect_next_packet_;
+  }
 
-  void set_should_fec_protect(bool should_fec_protect) {
-    should_fec_protect_ = should_fec_protect;
+  void set_should_fec_protect_next_packet(bool should_fec_protect_next_packet) {
+    should_fec_protect_next_packet_ = should_fec_protect_next_packet;
   }
 
  private:
@@ -297,6 +300,10 @@
   // Fails if |buffer_len| isn't long enough for the encrypted packet.
   SerializedPacket SerializePacket(char* encrypted_buffer, size_t buffer_len);
 
+  // Turn on FEC protection for subsequent packets. If no FEC group is currently
+  // open, this method flushes current open packet and then turns FEC on.
+  void MaybeStartFecProtection();
+
   // Turn on FEC protection for subsequently created packets. FEC should be
   // enabled first (max_packets_per_fec_group should be non-zero) for FEC
   // protection to start.
@@ -326,12 +333,13 @@
   scoped_ptr<QuicRandomBoolSource> random_bool_source_;
   QuicPacketNumber packet_number_;
   // True when creator is requested to turn on FEC protection. False otherwise.
-  // There could be a time difference between should_fec_protect_ is true/false
-  // and FEC is actually turned on/off (e.g., The creator may have an open FEC
-  // group even if this variable is false).
-  bool should_fec_protect_;
+  // There is a time difference between should_fec_protect_next_packet is
+  // true/false and FEC is actually turned on/off (e.g., The creator may have an
+  // open FEC group even if this variable is false).
+  bool should_fec_protect_next_packet_;
   // If true, any created packets will be FEC protected.
-  // TODO(fayang): Combine should_fec_protect_ and fec_protect_ to one variable.
+  // TODO(fayang): Combine should_fec_protect_next_packet and fec_protect_ to
+  // one variable.
   bool fec_protect_;
   scoped_ptr<QuicFecGroup> fec_group_;
   // Controls whether protocol version should be included while serializing the
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index 951738b..1e6d3b2 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -124,6 +124,9 @@
         creator_(connection_id_, &client_framer_, &mock_random_, &delegate_),
         serialized_packet_(creator_.NoPacket()) {
     creator_.set_connection_id_length(GetParam().connection_id_length);
+
+    creator_.SetEncrypter(ENCRYPTION_INITIAL, new NullEncrypter());
+    creator_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, new NullEncrypter());
     client_framer_.set_visitor(&framer_visitor_);
     client_framer_.set_received_entropy_calculator(&entropy_calculator_);
     server_framer_.set_visitor(&framer_visitor_);
@@ -132,6 +135,14 @@
 
   ~QuicPacketCreatorTest() override {}
 
+  SerializedPacket SerializeAllFrames(const QuicFrames& frames) {
+    SerializedPacket packet =
+        creator_.SerializeAllFrames(frames, buffer_, kMaxPacketSize);
+    EXPECT_EQ(QuicPacketCreatorPeer::GetEncryptionLevel(&creator_),
+              packet.encryption_level);
+    return packet;
+  }
+
   void ProcessPacket(QuicEncryptedPacket* encrypted) {
     server_framer_.ProcessPacket(*encrypted);
   }
@@ -144,7 +155,8 @@
     EXPECT_EQ(STREAM_FRAME, frame.type);
     ASSERT_TRUE(frame.stream_frame);
     EXPECT_EQ(stream_id, frame.stream_frame->stream_id);
-    EXPECT_EQ(data, frame.stream_frame->data);
+    EXPECT_EQ(data, StringPiece(frame.stream_frame->frame_buffer,
+                                frame.stream_frame->frame_length));
     EXPECT_EQ(offset, frame.stream_frame->offset);
     EXPECT_EQ(fin, frame.stream_frame->fin);
   }
@@ -172,19 +184,13 @@
                                              true, is_in_fec_group);
   }
 
-  // Enables and turns on FEC protection. Returns true if FEC protection is on.
-  bool SwitchFecProtectionOn(size_t max_packets_per_fec_group) {
-    creator_.set_max_packets_per_fec_group(max_packets_per_fec_group);
-    creator_.MaybeStartFecProtection();
-    return QuicPacketCreatorPeer::IsFecProtected(&creator_);
-  }
-
   QuicIOVector MakeIOVector(StringPiece s) {
     return ::net::MakeIOVector(s, &iov_);
   }
 
   static const QuicStreamOffset kOffset = 1u;
 
+  char buffer_[kMaxPacketSize];
   QuicFrames frames_;
   QuicFramer server_framer_;
   QuicFramer client_framer_;
@@ -207,47 +213,54 @@
                         ::testing::ValuesIn(GetTestParams()));
 
 TEST_P(QuicPacketCreatorTest, SerializeFrames) {
-  frames_.push_back(QuicFrame(new QuicAckFrame(MakeAckFrame(0u))));
-  frames_.push_back(
-      QuicFrame(new QuicStreamFrame(0u, false, 0u, StringPiece())));
-  frames_.push_back(
-      QuicFrame(new QuicStreamFrame(0u, true, 0u, StringPiece())));
-  char buffer[kMaxPacketSize];
-  SerializedPacket serialized =
-      creator_.SerializeAllFrames(frames_, buffer, kMaxPacketSize);
-  delete frames_[0].ack_frame;
-  delete frames_[1].stream_frame;
-  delete frames_[2].stream_frame;
+  for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; ++i) {
+    EncryptionLevel level = static_cast<EncryptionLevel>(i);
+    creator_.set_encryption_level(level);
+    frames_.push_back(QuicFrame(new QuicAckFrame(MakeAckFrame(0u))));
+    frames_.push_back(
+        QuicFrame(new QuicStreamFrame(0u, false, 0u, StringPiece())));
+    frames_.push_back(
+        QuicFrame(new QuicStreamFrame(0u, true, 0u, StringPiece())));
+    SerializedPacket serialized = SerializeAllFrames(frames_);
+    EXPECT_EQ(level, serialized.encryption_level);
+    delete frames_[0].ack_frame;
+    delete frames_[1].stream_frame;
+    delete frames_[2].stream_frame;
+    frames_.clear();
 
-  {
-    InSequence s;
-    EXPECT_CALL(framer_visitor_, OnPacket());
-    EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
-    EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
-    EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
-    EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
-    EXPECT_CALL(framer_visitor_, OnAckFrame(_));
-    EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
-    EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
-    EXPECT_CALL(framer_visitor_, OnPacketComplete());
+    {
+      InSequence s;
+      EXPECT_CALL(framer_visitor_, OnPacket());
+      EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+      EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+      EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+      EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+      EXPECT_CALL(framer_visitor_, OnAckFrame(_));
+      EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
+      EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
+      EXPECT_CALL(framer_visitor_, OnPacketComplete());
+    }
+    ProcessPacket(serialized.packet);
+    delete serialized.packet;
   }
-  ProcessPacket(serialized.packet);
-  delete serialized.packet;
 }
 
 TEST_P(QuicPacketCreatorTest, SerializeWithFEC) {
-  // Enable FEC protection, and send FEC packet every 6 packets.
-  EXPECT_TRUE(SwitchFecProtectionOn(6));
+  // Send FEC packet every 6 packets.
+  creator_.set_max_packets_per_fec_group(6);
   // Should return false since we do not have enough packets in the FEC group to
   // trigger an FEC packet.
   ASSERT_FALSE(creator_.ShouldSendFec(/*force_close=*/false));
-
-  frames_.push_back(
-      QuicFrame(new QuicStreamFrame(0u, false, 0u, StringPiece())));
-  char buffer[kMaxPacketSize];
-  SerializedPacket serialized =
-      creator_.SerializeAllFrames(frames_, buffer, kMaxPacketSize);
-  delete frames_[0].stream_frame;
+  // Turn on FEC protection.
+  QuicFrame frame;
+  QuicIOVector io_vector(MakeIOVector("test"));
+  ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame,
+                                   MUST_FEC_PROTECT));
+  EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_));
+  // Serialize the packet.
+  EXPECT_CALL(delegate_, OnSerializedPacket(_))
+      .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+  creator_.Flush();
 
   {
     InSequence s;
@@ -260,8 +273,8 @@
     EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
     EXPECT_CALL(framer_visitor_, OnPacketComplete());
   }
-  ProcessPacket(serialized.packet);
-  delete serialized.packet;
+  ProcessPacket(serialized_packet_.packet);
+  ClearSerializedPacket(&serialized_packet_);
 
   // Should return false since we do not have enough packets in the FEC group to
   // trigger an FEC packet.
@@ -271,7 +284,6 @@
 
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
-  creator_.set_should_fec_protect(true);
   creator_.MaybeSendFecPacketAndCloseGroup(/*force_send_fec=*/true,
                                            /*is_fec_timeout=*/false);
   ASSERT_EQ(2u, serialized_packet_.packet_number);
@@ -425,15 +437,17 @@
   // and we expect that packet number length should not change until the end
   // of the open FEC group.
 
-  // Enable FEC protection, and send FEC packet every 6 packets.
-  EXPECT_TRUE(SwitchFecProtectionOn(6));
+  // Send FEC packet every 6 packets.
+  creator_.set_max_packets_per_fec_group(6);
   // Should return false since we do not have enough packets in the FEC group to
   // trigger an FEC packet.
   ASSERT_FALSE(creator_.ShouldSendFec(/*force_close=*/false));
-  frames_.push_back(QuicFrame(new QuicAckFrame(MakeAckFrame(0u))));
 
   // Generate Packet 1.
-  creator_.AddSavedFrame(frames_[0]);
+  QuicFrame frame;
+  QuicIOVector io_vector(MakeIOVector("test"));
+  ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame,
+                                   MUST_FEC_PROTECT));
   // Change the packet number length mid-FEC group and it should not change.
   QuicPacketCreatorPeer::SetNextPacketNumberLength(&creator_,
                                                    PACKET_4BYTE_PACKET_NUMBER);
@@ -452,14 +466,15 @@
     EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
     EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
     EXPECT_CALL(framer_visitor_, OnFecProtectedPayload(_));
-    EXPECT_CALL(framer_visitor_, OnAckFrame(_));
+    EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
     EXPECT_CALL(framer_visitor_, OnPacketComplete());
   }
   ProcessPacket(serialized_packet_.packet);
   ClearSerializedPacket(&serialized_packet_);
 
   // Generate Packet 2.
-  creator_.AddSavedFrame(frames_[0]);
+  ASSERT_TRUE(creator_.ConsumeData(2u, io_vector, 0u, 0u, false, false, &frame,
+                                   MUST_FEC_PROTECT));
   creator_.Flush();
   EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
             serialized_packet_.packet_number_length);
@@ -472,7 +487,7 @@
     EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
     EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
     EXPECT_CALL(framer_visitor_, OnFecProtectedPayload(_));
-    EXPECT_CALL(framer_visitor_, OnAckFrame(_));
+    EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
     EXPECT_CALL(framer_visitor_, OnPacketComplete());
   }
   ProcessPacket(serialized_packet_.packet);
@@ -487,7 +502,8 @@
   // Force generation of FEC packet.
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
-  creator_.set_should_fec_protect(true);
+  // Turn off FEC protection.
+  creator_.set_should_fec_protect_next_packet(false);
   creator_.MaybeSendFecPacketAndCloseGroup(/*force_send_fec=*/true,
                                            /*is_fec_timeout=*/false);
   EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
@@ -508,12 +524,15 @@
   ClearSerializedPacket(&serialized_packet_);
 
   // Ensure the next FEC group starts using the new packet number length.
-  char buffer[kMaxPacketSize];
-  SerializedPacket serialized =
-      creator_.SerializeAllFrames(frames_, buffer, kMaxPacketSize);
-  EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER, serialized.packet_number_length);
-  delete frames_[0].ack_frame;
-  ClearSerializedPacket(&serialized);
+  ASSERT_TRUE(creator_.ConsumeData(3u, io_vector, 0u, 0u, false, false, &frame,
+                                   MUST_FEC_PROTECT));
+  EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_));
+  EXPECT_CALL(delegate_, OnSerializedPacket(_))
+      .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+  creator_.Flush();
+  EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
+            serialized_packet_.packet_number_length);
+  ClearSerializedPacket(&serialized_packet_);
 }
 
 TEST_P(QuicPacketCreatorTest, ReserializeFramesWithSequenceNumberLength) {
@@ -526,11 +545,12 @@
                                                PACKET_2BYTE_PACKET_NUMBER);
   QuicStreamFrame* stream_frame =
       new QuicStreamFrame(kCryptoStreamId, /*fin=*/false, 0u, StringPiece());
-  RetransmittableFrames frames(ENCRYPTION_NONE);
+  RetransmittableFrames frames;
   frames.AddFrame(QuicFrame(stream_frame));
   char buffer[kMaxPacketSize];
   SerializedPacket serialized = creator_.ReserializeAllFrames(
-      frames, PACKET_1BYTE_PACKET_NUMBER, buffer, kMaxPacketSize);
+      frames, ENCRYPTION_NONE, PACKET_1BYTE_PACKET_NUMBER, buffer,
+      kMaxPacketSize);
   EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
             QuicPacketCreatorPeer::NextPacketNumberLength(&creator_));
   EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER,
@@ -551,17 +571,48 @@
   delete serialized.packet;
 }
 
+TEST_P(QuicPacketCreatorTest, ReserializeCryptoFrameWithForwardSecurity) {
+  QuicStreamFrame* stream_frame =
+      new QuicStreamFrame(kCryptoStreamId, /*fin=*/false, 0u, StringPiece());
+  RetransmittableFrames frames;
+  frames.AddFrame(QuicFrame(stream_frame));
+  creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+  char buffer[kMaxPacketSize];
+  SerializedPacket serialized = creator_.ReserializeAllFrames(
+      frames, ENCRYPTION_NONE,
+      QuicPacketCreatorPeer::NextPacketNumberLength(&creator_), buffer,
+      kMaxPacketSize);
+  EXPECT_EQ(ENCRYPTION_NONE, serialized.encryption_level);
+  delete serialized.packet;
+}
+
+TEST_P(QuicPacketCreatorTest, ReserializeFrameWithForwardSecurity) {
+  QuicStreamFrame* stream_frame =
+      new QuicStreamFrame(0u, /*fin=*/false, 0u, StringPiece());
+  RetransmittableFrames frames;
+  frames.AddFrame(QuicFrame(stream_frame));
+  creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+  char buffer[kMaxPacketSize];
+  SerializedPacket serialized = creator_.ReserializeAllFrames(
+      frames, ENCRYPTION_NONE,
+      QuicPacketCreatorPeer::NextPacketNumberLength(&creator_), buffer,
+      kMaxPacketSize);
+  EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, serialized.encryption_level);
+  delete serialized.packet;
+}
+
 TEST_P(QuicPacketCreatorTest, ReserializeFramesWithPadding) {
   QuicFrame frame;
   QuicIOVector io_vector(MakeIOVector("fake handshake message data"));
   QuicPacketCreatorPeer::CreateStreamFrame(&creator_, kCryptoStreamId,
                                            io_vector, 0u, 0u, false, &frame);
-  RetransmittableFrames frames(ENCRYPTION_NONE);
+  RetransmittableFrames frames;
   frames.AddFrame(frame);
   frames.set_needs_padding(true);
   char buffer[kMaxPacketSize];
   SerializedPacket serialized = creator_.ReserializeAllFrames(
-      frames, QuicPacketCreatorPeer::NextPacketNumberLength(&creator_), buffer,
+      frames, ENCRYPTION_NONE,
+      QuicPacketCreatorPeer::NextPacketNumberLength(&creator_), buffer,
       kMaxPacketSize);
   EXPECT_EQ(kDefaultMaxPacketSize, serialized.packet->length());
   delete serialized.packet;
@@ -577,15 +628,17 @@
 
     QuicFrame frame;
     QuicIOVector io_vector(MakeIOVector(data));
+    UniqueStreamBuffer stream_buffer;
     QuicPacketCreatorPeer::CreateStreamFrame(
         &creator_, kCryptoStreamId, io_vector, 0, kOffset, false, &frame);
-    RetransmittableFrames frames(ENCRYPTION_NONE);
+    RetransmittableFrames frames;
     frames.AddFrame(frame);
     frames.set_needs_padding(true);
     char buffer[kMaxPacketSize];
     SerializedPacket serialized = creator_.ReserializeAllFrames(
-        frames, QuicPacketCreatorPeer::NextPacketNumberLength(&creator_),
-        buffer, kMaxPacketSize);
+        frames, ENCRYPTION_NONE,
+        QuicPacketCreatorPeer::NextPacketNumberLength(&creator_), buffer,
+        kMaxPacketSize);
 
     // If there is not enough space in the packet to fit a padding frame
     // (1 byte) and to expand the stream frame (another 2 bytes) the packet
@@ -609,9 +662,8 @@
 
   QuicFrames frames;
   frames.push_back(QuicFrame(&frame));
-  char buffer[kMaxPacketSize];
-  SerializedPacket serialized =
-      creator_.SerializeAllFrames(frames, buffer, kMaxPacketSize);
+  SerializedPacket serialized = SerializeAllFrames(frames);
+  EXPECT_EQ(ENCRYPTION_NONE, serialized.encryption_level);
   ASSERT_EQ(1u, serialized.packet_number);
   ASSERT_EQ(1u, creator_.packet_number());
 
@@ -628,36 +680,18 @@
   delete serialized.packet;
 }
 
-TEST_P(QuicPacketCreatorTest, SwitchFecOnOffWithNoGroup) {
-  // Enable FEC protection.
-  creator_.set_max_packets_per_fec_group(6);
-  EXPECT_TRUE(QuicPacketCreatorPeer::IsFecEnabled(&creator_));
-  EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(&creator_));
-
-  // Turn on FEC protection.
-  creator_.MaybeStartFecProtection();
-  EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_));
-  // We have no packets in the FEC group, so no FEC packet can be created.
-  EXPECT_FALSE(creator_.ShouldSendFec(/*force_close=*/true));
-  // Since no packets are in FEC group yet, we should be able to turn FEC
-  // off with no trouble.
-  creator_.MaybeSendFecPacketAndCloseGroup(/*force_send_fec=*/true,
-                                           /*is_fec_timeout=*/false);
-  EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(&creator_));
-}
-
 TEST_P(QuicPacketCreatorTest, SwitchFecOnOffWithGroupInProgress) {
-  // Enable FEC protection, and send FEC packet every 6 packets.
-  EXPECT_TRUE(SwitchFecProtectionOn(6));
-  frames_.push_back(
-      QuicFrame(new QuicStreamFrame(0u, false, 0u, StringPiece())));
-  char buffer[kMaxPacketSize];
-  SerializedPacket serialized =
-      creator_.SerializeAllFrames(frames_, buffer, kMaxPacketSize);
-  delete frames_[0].stream_frame;
-  delete serialized.packet;
-
+  // Send FEC packet every 6 packets.
+  creator_.set_max_packets_per_fec_group(6);
+  // Turn on FEC protection.
+  QuicFrame frame;
+  QuicIOVector io_vector(MakeIOVector("test"));
+  ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame,
+                                   MUST_FEC_PROTECT));
   EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_));
+  EXPECT_CALL(delegate_, OnSerializedPacket(_))
+      .WillOnce(Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket));
+  creator_.Flush();
   // We do not have enough packets in the FEC group to trigger an FEC packet.
   EXPECT_FALSE(creator_.ShouldSendFec(/*force_close=*/false));
   // Should return true since there are packets in the FEC group.
@@ -673,22 +707,22 @@
 
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillOnce(Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket));
-  // Switching FEC on/off should work now.
+  // Turn off FEC protection.
+  creator_.set_should_fec_protect_next_packet(false);
   creator_.MaybeSendFecPacketAndCloseGroup(/*force_send_fec=*/true,
                                            /*is_fec_timeout=*/false);
   EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(&creator_));
-  creator_.MaybeStartFecProtection();
-  EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_));
 }
 
 TEST_P(QuicPacketCreatorTest, SwitchFecOnWithStreamFrameQueued) {
   // Add a stream frame to the creator.
   QuicFrame frame;
   QuicIOVector io_vector(MakeIOVector("test"));
-  ASSERT_TRUE(
-      creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame));
+  ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame,
+                                   MAY_FEC_PROTECT));
+  EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(&creator_));
   ASSERT_TRUE(frame.stream_frame);
-  size_t consumed = frame.stream_frame->data.length();
+  size_t consumed = frame.stream_frame->frame_length;
   EXPECT_EQ(4u, consumed);
   EXPECT_TRUE(creator_.HasPendingFrames());
 
@@ -702,18 +736,22 @@
   // Start FEC protection after current open packet is flushed.
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillOnce(Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket));
-  creator_.MaybeStartFecProtection();
-  EXPECT_FALSE(creator_.HasPendingFrames());
+  ASSERT_TRUE(creator_.ConsumeData(2u, io_vector, 0u, 0u, false, false, &frame,
+                                   MUST_FEC_PROTECT));
+  ASSERT_TRUE(frame.stream_frame);
+  consumed = frame.stream_frame->frame_length;
+  EXPECT_EQ(4u, consumed);
+  EXPECT_TRUE(creator_.HasPendingFrames());
   EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_));
 }
 
 TEST_P(QuicPacketCreatorTest, ConsumeData) {
   QuicFrame frame;
   QuicIOVector io_vector(MakeIOVector("test"));
-  ASSERT_TRUE(
-      creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame));
+  ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame,
+                                   MAY_FEC_PROTECT));
   ASSERT_TRUE(frame.stream_frame);
-  size_t consumed = frame.stream_frame->data.length();
+  size_t consumed = frame.stream_frame->frame_length;
   EXPECT_EQ(4u, consumed);
   CheckStreamFrame(frame, 1u, "test", 0u, false);
   EXPECT_TRUE(creator_.HasPendingFrames());
@@ -722,10 +760,10 @@
 TEST_P(QuicPacketCreatorTest, ConsumeDataFin) {
   QuicFrame frame;
   QuicIOVector io_vector(MakeIOVector("test"));
-  ASSERT_TRUE(
-      creator_.ConsumeData(1u, io_vector, 0u, 10u, true, false, &frame));
+  ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 10u, true, false, &frame,
+                                   MAY_FEC_PROTECT));
   ASSERT_TRUE(frame.stream_frame);
-  size_t consumed = frame.stream_frame->data.length();
+  size_t consumed = frame.stream_frame->frame_length;
   EXPECT_EQ(4u, consumed);
   CheckStreamFrame(frame, 1u, "test", 10u, true);
   EXPECT_TRUE(creator_.HasPendingFrames());
@@ -734,14 +772,30 @@
 TEST_P(QuicPacketCreatorTest, ConsumeDataFinOnly) {
   QuicFrame frame;
   QuicIOVector io_vector(nullptr, 0, 0);
-  ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, true, false, &frame));
+  ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, true, false, &frame,
+                                   MAY_FEC_PROTECT));
   ASSERT_TRUE(frame.stream_frame);
-  size_t consumed = frame.stream_frame->data.length();
+  size_t consumed = frame.stream_frame->frame_length;
   EXPECT_EQ(0u, consumed);
   CheckStreamFrame(frame, 1u, string(), 0u, true);
   EXPECT_TRUE(creator_.HasPendingFrames());
 }
 
+TEST_P(QuicPacketCreatorTest, ConsumeDataWithFecProtect) {
+  creator_.set_max_packets_per_fec_group(6);
+  QuicFrame frame;
+  QuicIOVector io_vector(MakeIOVector("test"));
+  EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(&creator_));
+  ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame,
+                                   MUST_FEC_PROTECT));
+  ASSERT_TRUE(frame.stream_frame);
+  size_t consumed = frame.stream_frame->frame_length;
+  EXPECT_EQ(4u, consumed);
+  CheckStreamFrame(frame, 1u, "test", 0u, false);
+  EXPECT_TRUE(creator_.HasPendingFrames());
+  EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_));
+}
+
 TEST_P(QuicPacketCreatorTest, CreateAllFreeBytesForStreamFrames) {
   const size_t overhead = GetPacketHeaderOverhead(NOT_IN_FEC_GROUP)
                           + GetEncryptionOverhead();
@@ -758,9 +812,10 @@
           .WillRepeatedly(
               Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket));
       ASSERT_TRUE(creator_.ConsumeData(kClientDataStreamId1, io_vector, 0u,
-                                       kOffset, false, false, &frame));
+                                       kOffset, false, false, &frame,
+                                       MAY_FEC_PROTECT));
       ASSERT_TRUE(frame.stream_frame);
-      size_t bytes_consumed = frame.stream_frame->data.length();
+      size_t bytes_consumed = frame.stream_frame->frame_length;
       EXPECT_LT(0u, bytes_consumed);
       creator_.Flush();
     }
@@ -798,8 +853,18 @@
 }
 
 TEST_P(QuicPacketCreatorTest, StreamFrameConsumptionWithFec) {
-  // Enable FEC protection, and send FEC packet every 6 packets.
-  EXPECT_TRUE(SwitchFecProtectionOn(6));
+  // Send FEC packet every 6 packets.
+  creator_.set_max_packets_per_fec_group(6);
+  // Turn on FEC protection.
+  QuicFrame frame;
+  QuicIOVector io_vector(MakeIOVector("test"));
+  ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame,
+                                   MUST_FEC_PROTECT));
+  EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_));
+  // Serialize the packet.
+  EXPECT_CALL(delegate_, OnSerializedPacket(_))
+      .WillOnce(Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket));
+  creator_.Flush();
   // Compute the total overhead for a single frame in packet.
   const size_t overhead = GetPacketHeaderOverhead(IN_FEC_GROUP) +
                           GetEncryptionOverhead() +
@@ -847,9 +912,9 @@
         .WillRepeatedly(
             Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
     ASSERT_TRUE(creator_.ConsumeData(kCryptoStreamId, io_vector, 0u, kOffset,
-                                     false, true, &frame));
+                                     false, true, &frame, MAY_FEC_PROTECT));
     ASSERT_TRUE(frame.stream_frame);
-    size_t bytes_consumed = frame.stream_frame->data.length();
+    size_t bytes_consumed = frame.stream_frame->frame_length;
     EXPECT_LT(0u, bytes_consumed);
     creator_.Flush();
     ASSERT_TRUE(serialized_packet_.packet);
@@ -882,9 +947,10 @@
     EXPECT_CALL(delegate_, OnSerializedPacket(_))
         .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
     ASSERT_TRUE(creator_.ConsumeData(kClientDataStreamId1, io_vector, 0u,
-                                     kOffset, false, false, &frame));
+                                     kOffset, false, false, &frame,
+                                     MAY_FEC_PROTECT));
     ASSERT_TRUE(frame.stream_frame);
-    size_t bytes_consumed = frame.stream_frame->data.length();
+    size_t bytes_consumed = frame.stream_frame->frame_length;
     EXPECT_LT(0u, bytes_consumed);
     creator_.Flush();
     ASSERT_TRUE(serialized_packet_.packet);
@@ -976,9 +1042,7 @@
   }
   frames_.push_back(
       QuicFrame(new QuicStreamFrame(0u, false, 0u, StringPiece())));
-  char buffer[kMaxPacketSize];
-  SerializedPacket serialized =
-      creator_.SerializeAllFrames(frames_, buffer, kMaxPacketSize);
+  SerializedPacket serialized = SerializeAllFrames(frames_);
   delete frames_[0].stream_frame;
 
   QuicPacketHeader header;
@@ -1015,9 +1079,10 @@
   QuicIOVector io_vector(MakeIOVector(too_long_payload));
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
-  ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, true, false, &frame));
+  ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, true, false, &frame,
+                                   MAY_FEC_PROTECT));
   ASSERT_TRUE(frame.stream_frame);
-  size_t consumed = frame.stream_frame->data.length();
+  size_t consumed = frame.stream_frame->frame_length;
   EXPECT_EQ(payload_length, consumed);
   const string payload(payload_length, 'a');
   CheckStreamFrame(frame, 1u, payload, 0u, false);
@@ -1047,10 +1112,10 @@
 
   QuicFrame frame;
   QuicIOVector io_vector(MakeIOVector("test"));
-  ASSERT_TRUE(
-      creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame));
+  ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame,
+                                   MAY_FEC_PROTECT));
   ASSERT_TRUE(frame.stream_frame);
-  size_t consumed = frame.stream_frame->data.length();
+  size_t consumed = frame.stream_frame->frame_length;
   EXPECT_EQ(4u, consumed);
   EXPECT_TRUE(creator_.HasPendingFrames());
 
@@ -1108,10 +1173,10 @@
   // Make sure that an additional stream frame can be added to the packet.
   QuicFrame frame;
   QuicIOVector io_vector(MakeIOVector("test"));
-  ASSERT_TRUE(
-      creator_.ConsumeData(2u, io_vector, 0u, 0u, false, false, &frame));
+  ASSERT_TRUE(creator_.ConsumeData(2u, io_vector, 0u, 0u, false, false, &frame,
+                                   MAY_FEC_PROTECT));
   ASSERT_TRUE(frame.stream_frame);
-  size_t consumed = frame.stream_frame->data.length();
+  size_t consumed = frame.stream_frame->frame_length;
   EXPECT_EQ(4u, consumed);
   EXPECT_TRUE(creator_.HasPendingFrames());
 
@@ -1171,11 +1236,9 @@
   frames_.push_back(
       QuicFrame(new QuicStreamFrame(0u, false, 0u, StringPiece())));
 
-  char buffer[kMaxPacketSize];
   for (int i = 0; i < 2; ++i) {
     for (int j = 0; j < 64; ++j) {
-      SerializedPacket serialized =
-          creator_.SerializeAllFrames(frames_, buffer, kMaxPacketSize);
+      SerializedPacket serialized = SerializeAllFrames(frames_);
       // Verify both BoolSource and hash algorithm.
       bool expected_rand_bool =
           (mock_random_.RandUint64() & (UINT64_C(1) << j)) != 0;
@@ -1194,14 +1257,17 @@
 }
 
 TEST_P(QuicPacketCreatorTest, ResetFecGroup) {
-  // Enable FEC protection, and send FEC packet every 6 packets.
-  EXPECT_TRUE(SwitchFecProtectionOn(6));
-  frames_.push_back(
-      QuicFrame(new QuicStreamFrame(0u, false, 0u, StringPiece())));
-  char buffer[kMaxPacketSize];
-  SerializedPacket serialized =
-      creator_.SerializeAllFrames(frames_, buffer, kMaxPacketSize);
-  delete serialized.packet;
+  // Send FEC packet every 6 packets.
+  creator_.set_max_packets_per_fec_group(6);
+  // Add a stream frame and turn on FEC protection.
+  QuicFrame frame;
+  QuicIOVector io_vector(MakeIOVector("test"));
+  ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame,
+                                   MUST_FEC_PROTECT));
+  // Serialize the packet.
+  EXPECT_CALL(delegate_, OnSerializedPacket(_))
+      .WillOnce(Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket));
+  creator_.Flush();
 
   EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_));
   EXPECT_TRUE(creator_.IsFecGroupOpen());
@@ -1214,7 +1280,7 @@
   // not fire.
   EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
   creator_.set_fec_send_policy(FEC_ALARM_TRIGGER);
-  creator_.set_should_fec_protect(true);
+  creator_.set_should_fec_protect_next_packet(true);
   creator_.MaybeSendFecPacketAndCloseGroup(/*force_send_fec=*/true,
                                            /*is_fec_timeout=*/false);
   EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_));
@@ -1224,15 +1290,17 @@
   // Confirm that there is no FEC packet under construction.
   EXPECT_FALSE(creator_.ShouldSendFec(/*force_close=*/true));
 
-  EXPECT_DFATAL(serialized = QuicPacketCreatorPeer::SerializeFec(
-                    &creator_, buffer, kMaxPacketSize),
-                "SerializeFEC called but no group or zero packets in group.");
-  delete serialized.packet;
+  char buffer[kMaxPacketSize];
+  EXPECT_DFATAL(
+      QuicPacketCreatorPeer::SerializeFec(&creator_, buffer, kMaxPacketSize),
+      "SerializeFEC called but no group or zero packets in group.");
 
-  // Start a new FEC packet.
-  serialized = creator_.SerializeAllFrames(frames_, buffer, kMaxPacketSize);
-  delete frames_[0].stream_frame;
-  delete serialized.packet;
+  // Create and send a new FEC protected packet.
+  ASSERT_TRUE(creator_.ConsumeData(2u, io_vector, 0u, 0u, false, false, &frame,
+                                   MUST_FEC_PROTECT));
+  EXPECT_CALL(delegate_, OnSerializedPacket(_))
+      .WillOnce(Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket));
+  creator_.Flush();
 
   EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_));
   EXPECT_TRUE(creator_.IsFecGroupOpen());
@@ -1251,6 +1319,7 @@
   creator_.set_fec_send_policy(FEC_ANY_TRIGGER);
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+  creator_.set_should_fec_protect_next_packet(false);
   creator_.MaybeSendFecPacketAndCloseGroup(/*force_send_fec=*/true,
                                            /*is_fec_timeout=*/false);
   ASSERT_EQ(3u, serialized_packet_.packet_number);
@@ -1258,15 +1327,15 @@
 }
 
 TEST_P(QuicPacketCreatorTest, ResetFecGroupWithQueuedFrames) {
-  // Enable FEC protection, and send FEC packet every 6 packets.
-  EXPECT_TRUE(SwitchFecProtectionOn(6));
-  // Add a stream frame to the creator.
+  // Send FEC packet every 6 packets.
+  creator_.set_max_packets_per_fec_group(6);
+  // Add a stream frame to the creator and turn on FEC protection.
   QuicFrame frame;
   QuicIOVector io_vector(MakeIOVector("test"));
-  ASSERT_TRUE(
-      creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame));
+  ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame,
+                                   MUST_FEC_PROTECT));
   ASSERT_TRUE(frame.stream_frame);
-  size_t consumed = frame.stream_frame->data.length();
+  size_t consumed = frame.stream_frame->frame_length;
   EXPECT_EQ(4u, consumed);
   EXPECT_TRUE(creator_.HasPendingFrames());
   EXPECT_DFATAL(QuicPacketCreatorPeer::ResetFecGroup(&creator_),
@@ -1281,7 +1350,7 @@
   // not fire.
   EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
   creator_.set_fec_send_policy(FEC_ALARM_TRIGGER);
-  creator_.set_should_fec_protect(true);
+  creator_.set_should_fec_protect_next_packet(true);
   creator_.MaybeSendFecPacketAndCloseGroup(/*force_send_fec=*/true,
                                            /*is_fec_timeout=*/false);
   EXPECT_FALSE(creator_.IsFecGroupOpen());
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc
index 6176985..a83c62d 100644
--- a/net/quic/quic_packet_generator.cc
+++ b/net/quic/quic_packet_generator.cc
@@ -118,11 +118,6 @@
     packet_creator_.Flush();
   }
 
-  if (fec_protection == MUST_FEC_PROTECT) {
-    packet_creator_.set_should_fec_protect(true);
-    packet_creator_.MaybeStartFecProtection();
-  }
-
   if (!fin && (iov.total_length == 0)) {
     LOG(DFATAL) << "Attempt to consume empty data without FIN.";
     return QuicConsumedData(0, false);
@@ -133,13 +128,13 @@
     QuicFrame frame;
     if (!packet_creator_.ConsumeData(id, iov, total_bytes_consumed,
                                      offset + total_bytes_consumed, fin,
-                                     has_handshake, &frame)) {
+                                     has_handshake, &frame, fec_protection)) {
       // Current packet is full and flushed.
       continue;
     }
 
     // A stream frame is created and added.
-    size_t bytes_consumed = frame.stream_frame->data.length();
+    size_t bytes_consumed = frame.stream_frame->frame_length;
     if (debug_delegate_ != nullptr) {
       debug_delegate_->OnFrameAddedToPacket(frame);
     }
@@ -167,7 +162,7 @@
       if (fec_protection == MUST_FEC_PROTECT) {
         // Turn off FEC protection when we're done writing protected data.
         DVLOG(1) << "Turning FEC protection OFF";
-        packet_creator_.set_should_fec_protect(false);
+        packet_creator_.set_should_fec_protect_next_packet(false);
       }
       break;
     }
@@ -364,11 +359,12 @@
 
 SerializedPacket QuicPacketGenerator::ReserializeAllFrames(
     const RetransmittableFrames& frames,
+    EncryptionLevel original_encryption_level,
     QuicPacketNumberLength original_length,
     char* buffer,
     size_t buffer_len) {
-  return packet_creator_.ReserializeAllFrames(frames, original_length, buffer,
-                                              buffer_len);
+  return packet_creator_.ReserializeAllFrames(
+      frames, original_encryption_level, original_length, buffer, buffer_len);
 }
 
 void QuicPacketGenerator::UpdateSequenceNumberLength(
@@ -404,7 +400,7 @@
   if (serialized_packet->packet == nullptr) {
     LOG(DFATAL) << "Failed to SerializePacket. fec_policy:" << fec_send_policy()
                 << " should_fec_protect_:"
-                << packet_creator_.should_fec_protect();
+                << packet_creator_.should_fec_protect_next_packet();
     delegate_->CloseConnection(QUIC_FAILED_TO_SERIALIZE_PACKET, false);
     return;
   }
diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h
index 4eef5d1..d217609 100644
--- a/net/quic/quic_packet_generator.h
+++ b/net/quic/quic_packet_generator.h
@@ -158,10 +158,12 @@
   // Used for retransmitting packets to ensure they aren't too long.
   // Caller must ensure that any open FEC group is closed before calling this
   // method.
-  SerializedPacket ReserializeAllFrames(const RetransmittableFrames& frames,
-                                        QuicPacketNumberLength original_length,
-                                        char* buffer,
-                                        size_t buffer_len);
+  SerializedPacket ReserializeAllFrames(
+      const RetransmittableFrames& frames,
+      EncryptionLevel original_encryption_level,
+      QuicPacketNumberLength original_length,
+      char* buffer,
+      size_t buffer_len);
 
   // Update the packet number length to use in future packets as soon as it
   // can be safely changed.
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index 2bca0b7..19349fa 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -107,26 +107,56 @@
   return UniqueStreamBuffer(new char[size]);
 }
 
-QuicStreamFrame::QuicStreamFrame() : stream_id(0), fin(false), offset(0) {
-}
+QuicStreamFrame::QuicStreamFrame()
+    : stream_id(0),
+      fin(false),
+      frame_length(0),
+      frame_buffer(nullptr),
+      offset(0),
+      buffer(nullptr) {}
 
 QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
                                  bool fin,
                                  QuicStreamOffset offset,
                                  StringPiece data)
-    : stream_id(stream_id), fin(fin), offset(offset), data(data) {
+    : QuicStreamFrame(stream_id,
+                      fin,
+                      offset,
+                      data.data(),
+                      data.length(),
+                      nullptr) {}
+
+QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
+                                 bool fin,
+                                 QuicStreamOffset offset,
+                                 QuicPacketLength frame_length,
+                                 UniqueStreamBuffer buffer)
+    : QuicStreamFrame(stream_id,
+                      fin,
+                      offset,
+                      nullptr,
+                      frame_length,
+                      std::move(buffer)) {
+  DCHECK(this->buffer != nullptr);
+  DCHECK_EQ(frame_buffer, this->buffer.get());
 }
 
 QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
                                  bool fin,
                                  QuicStreamOffset offset,
-                                 StringPiece data,
+                                 const char* frame_buffer,
+                                 QuicPacketLength frame_length,
                                  UniqueStreamBuffer buffer)
     : stream_id(stream_id),
       fin(fin),
+      frame_length(frame_length),
+      frame_buffer(frame_buffer),
       offset(offset),
-      data(data),
-      buffer(std::move(buffer)) {}
+      buffer(std::move(buffer)) {
+  if (this->buffer != nullptr) {
+    this->frame_buffer = this->buffer.get();
+  }
+}
 
 QuicStreamFrame::~QuicStreamFrame() {}
 
@@ -597,8 +627,7 @@
   os << "stream_id { " << stream_frame.stream_id << " } "
      << "fin { " << stream_frame.fin << " } "
      << "offset { " << stream_frame.offset << " } "
-     << "data { " << QuicUtils::StringToHexASCIIDump(stream_frame.data)
-     << " }\n";
+     << "length { " << stream_frame.frame_length << " }\n";
   return os;
 }
 
@@ -695,10 +724,8 @@
                      length() - start_of_encrypted_data);
 }
 
-RetransmittableFrames::RetransmittableFrames(EncryptionLevel level)
-    : encryption_level_(level),
-      has_crypto_handshake_(NOT_HANDSHAKE),
-      needs_padding_(false) {
+RetransmittableFrames::RetransmittableFrames()
+    : has_crypto_handshake_(NOT_HANDSHAKE), needs_padding_(false) {
   // TODO(ianswett): Consider using an inlined vector instead, since this
   // is very frequently a single frame.
   frames_.reserve(2);
@@ -783,6 +810,7 @@
       retransmittable_frames(retransmittable_frames),
       packet_number(packet_number),
       packet_number_length(packet_number_length),
+      encryption_level(ENCRYPTION_NONE),
       entropy_hash(entropy_hash),
       is_fec_packet(false),
       has_ack(has_ack),
@@ -797,7 +825,8 @@
     QuicPacketEntropyHash entropy_hash,
     RetransmittableFrames* retransmittable_frames,
     bool has_ack,
-    bool has_stop_waiting)
+    bool has_stop_waiting,
+    EncryptionLevel level)
     : SerializedPacket(packet_number,
                        packet_number_length,
                        new QuicEncryptedPacket(encrypted_buffer,
@@ -806,7 +835,11 @@
                        entropy_hash,
                        retransmittable_frames,
                        has_ack,
-                       has_stop_waiting) {}
+                       has_stop_waiting) {
+  // TODO(ianswett): Move into the initializer list once SerializedPacket
+  // no longer contains an encrypted packet.
+  encryption_level = level;
+}
 
 SerializedPacket::~SerializedPacket() {}
 
@@ -823,6 +856,7 @@
 
 TransmissionInfo::TransmissionInfo()
     : retransmittable_frames(nullptr),
+      encryption_level(ENCRYPTION_NONE),
       packet_number_length(PACKET_1BYTE_PACKET_NUMBER),
       bytes_sent(0),
       nack_count(0),
@@ -836,12 +870,14 @@
 
 TransmissionInfo::TransmissionInfo(
     RetransmittableFrames* retransmittable_frames,
+    EncryptionLevel level,
     QuicPacketNumberLength packet_number_length,
     TransmissionType transmission_type,
     QuicTime sent_time,
     QuicPacketLength bytes_sent,
     bool is_fec_packet)
     : retransmittable_frames(retransmittable_frames),
+      encryption_level(level),
       packet_number_length(packet_number_length),
       bytes_sent(bytes_sent),
       nack_count(0),
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index ff35074..d817599a 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -728,7 +728,7 @@
   QuicStreamFrame(QuicStreamId stream_id,
                   bool fin,
                   QuicStreamOffset offset,
-                  base::StringPiece data,
+                  QuicPacketLength frame_length,
                   UniqueStreamBuffer buffer);
   ~QuicStreamFrame();
 
@@ -737,12 +737,20 @@
 
   QuicStreamId stream_id;
   bool fin;
+  QuicPacketLength frame_length;
+  const char* frame_buffer;
   QuicStreamOffset offset;  // Location of this data in the stream.
-  base::StringPiece data;
   // nullptr when the QuicStreamFrame is received, and non-null when sent.
   UniqueStreamBuffer buffer;
 
  private:
+  QuicStreamFrame(QuicStreamId stream_id,
+                  bool fin,
+                  QuicStreamOffset offset,
+                  const char* frame_buffer,
+                  QuicPacketLength frame_length,
+                  UniqueStreamBuffer buffer);
+
   DISALLOW_COPY_AND_ASSIGN(QuicStreamFrame);
 };
 static_assert(sizeof(QuicStreamFrame) <= 64,
@@ -1141,7 +1149,7 @@
 
 class NET_EXPORT_PRIVATE RetransmittableFrames {
  public:
-  explicit RetransmittableFrames(EncryptionLevel level);
+  RetransmittableFrames();
   ~RetransmittableFrames();
 
   // Takes ownership of the frame inside |frame|.
@@ -1155,17 +1163,12 @@
     return has_crypto_handshake_;
   }
 
-  EncryptionLevel encryption_level() const {
-    return encryption_level_;
-  }
-
   bool needs_padding() const { return needs_padding_; }
 
   void set_needs_padding(bool needs_padding) { needs_padding_ = needs_padding; }
 
  private:
   QuicFrames frames_;
-  const EncryptionLevel encryption_level_;
   IsHandshake has_crypto_handshake_;
   bool needs_padding_;
 
@@ -1197,13 +1200,15 @@
                    QuicPacketEntropyHash entropy_hash,
                    RetransmittableFrames* retransmittable_frames,
                    bool has_ack,
-                   bool has_stop_waiting);
+                   bool has_stop_waiting,
+                   EncryptionLevel level);
   ~SerializedPacket();
 
   QuicEncryptedPacket* packet;
   RetransmittableFrames* retransmittable_frames;
   QuicPacketNumber packet_number;
   QuicPacketNumberLength packet_number_length;
+  EncryptionLevel encryption_level;
   QuicPacketEntropyHash entropy_hash;
   bool is_fec_packet;
   bool has_ack;
@@ -1220,6 +1225,7 @@
   // Constructs a Transmission with a new all_tranmissions set
   // containing |packet_number|.
   TransmissionInfo(RetransmittableFrames* retransmittable_frames,
+                   EncryptionLevel level,
                    QuicPacketNumberLength packet_number_length,
                    TransmissionType transmission_type,
                    QuicTime sent_time,
@@ -1229,6 +1235,7 @@
   ~TransmissionInfo();
 
   RetransmittableFrames* retransmittable_frames;
+  EncryptionLevel encryption_level;
   QuicPacketNumberLength packet_number_length;
   QuicPacketLength bytes_sent;
   uint16 nack_count;
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index 25d72e78..a3176cc 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -347,7 +347,7 @@
     const RetransmittableFrames* frames = it->retransmittable_frames;
     if (frames != nullptr &&
         (retransmission_type == ALL_UNACKED_RETRANSMISSION ||
-         frames->encryption_level() == ENCRYPTION_INITIAL)) {
+         it->encryption_level == ENCRYPTION_INITIAL)) {
       MarkForRetransmission(packet_number, retransmission_type);
     } else if (it->is_fec_packet) {
       // Remove FEC packets from the packet map, since we can't retransmit them.
@@ -360,8 +360,8 @@
   QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
   for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
        it != unacked_packets_.end(); ++it, ++packet_number) {
-    const RetransmittableFrames* frames = it->retransmittable_frames;
-    if (frames != nullptr && frames->encryption_level() == ENCRYPTION_NONE) {
+    if (it->retransmittable_frames != nullptr &&
+        it->encryption_level == ENCRYPTION_NONE) {
       // Once you're forward secure, no unencrypted packets will be sent, crypto
       // or otherwise. Unencrypted packets are neutered and abandoned, to ensure
       // they are not retransmitted or considered lost from a congestion control
@@ -465,6 +465,7 @@
 
   return PendingRetransmission(packet_number, transmission_type,
                                *transmission_info.retransmittable_frames,
+                               transmission_info.encryption_level,
                                transmission_info.packet_number_length);
 }
 
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index 2b0d095..f0d990f 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -77,15 +77,18 @@
     PendingRetransmission(QuicPacketNumber packet_number,
                           TransmissionType transmission_type,
                           const RetransmittableFrames& retransmittable_frames,
+                          EncryptionLevel encryption_level,
                           QuicPacketNumberLength packet_number_length)
         : packet_number(packet_number),
           transmission_type(transmission_type),
           retransmittable_frames(retransmittable_frames),
+          encryption_level(encryption_level),
           packet_number_length(packet_number_length) {}
 
     QuicPacketNumber packet_number;
     TransmissionType transmission_type;
     const RetransmittableFrames& retransmittable_frames;
+    EncryptionLevel encryption_level;
     QuicPacketNumberLength packet_number_length;
   };
 
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index 8052767b..40adefa 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -185,7 +185,7 @@
     packets_.push_back(new QuicEncryptedPacket(nullptr, kDefaultLength));
     RetransmittableFrames* frames = nullptr;
     if (retransmittable) {
-      frames = new RetransmittableFrames(ENCRYPTION_NONE);
+      frames = new RetransmittableFrames();
       frames->AddFrame(
           QuicFrame(new QuicStreamFrame(kStreamId, false, 0, StringPiece())));
     }
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index ca11f6ba..609b3472 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -142,7 +142,7 @@
     // final stream byte offset sent by the peer. A frame with a FIN can give
     // us this offset.
     if (frame.fin) {
-      QuicStreamOffset final_byte_offset = frame.offset + frame.data.size();
+      QuicStreamOffset final_byte_offset = frame.offset + frame.frame_length;
       UpdateFlowControlOnFinalReceivedByteOffset(stream_id, final_byte_offset);
     }
     return;
diff --git a/net/quic/quic_spdy_stream.h b/net/quic/quic_spdy_stream.h
index e55d6aa..81673f7 100644
--- a/net/quic/quic_spdy_stream.h
+++ b/net/quic/quic_spdy_stream.h
@@ -77,7 +77,7 @@
   virtual void OnStreamHeadersPriority(SpdyPriority priority);
 
   // Called by the session when decompressed headers have been completely
-  // delilvered to this stream.  If |fin| is true, then this stream
+  // delivered to this stream.  If |fin| is true, then this stream
   // should be closed; no more data will be sent by the peer.
   virtual void OnStreamHeadersComplete(bool fin, size_t frame_len);
 
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 096ea6abc..2443381 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -685,6 +685,10 @@
   }
 }
 
+bool QuicStreamFactory::ZeroRTTEnabledFor(const QuicServerId& quic_server_id) {
+  return !(require_confirmation_ || CryptoConfigCacheIsEmpty(quic_server_id));
+}
+
 base::TimeDelta QuicStreamFactory::GetTimeDelayForWaitingJob(
     const QuicServerId& server_id) {
   if (!delay_tcp_race_ || require_confirmation_)
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h
index 0e69604..644fbc76 100644
--- a/net/quic/quic_stream_factory.h
+++ b/net/quic/quic_stream_factory.h
@@ -228,6 +228,8 @@
 
   void set_require_confirmation(bool require_confirmation);
 
+  bool ZeroRTTEnabledFor(const QuicServerId& server_id);
+
   // It returns the amount of time waiting job should be delayed.
   base::TimeDelta GetTimeDelayForWaitingJob(const QuicServerId& server_id);
 
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 95705d3..c1390a4 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -28,6 +28,7 @@
 #include "net/quic/test_tools/mock_clock.h"
 #include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
 #include "net/quic/test_tools/mock_random.h"
+#include "net/quic/test_tools/quic_stream_factory_peer.h"
 #include "net/quic/test_tools/quic_test_packet_maker.h"
 #include "net/quic/test_tools/quic_test_utils.h"
 #include "net/quic/test_tools/test_task_runner.h"
@@ -80,112 +81,6 @@
 
 }  // namespace anonymous
 
-class QuicStreamFactoryPeer {
- public:
-  static const QuicConfig* GetConfig(QuicStreamFactory* factory) {
-    return &factory->config_;
-  }
-
-  static QuicCryptoClientConfig* GetCryptoConfig(QuicStreamFactory* factory) {
-    return &factory->crypto_config_;
-  }
-
-  static bool HasActiveSession(QuicStreamFactory* factory,
-                               const HostPortPair& host_port_pair) {
-    QuicServerId server_id(host_port_pair, PRIVACY_MODE_DISABLED);
-    return factory->HasActiveSession(server_id);
-  }
-
-  static QuicChromiumClientSession* GetActiveSession(
-      QuicStreamFactory* factory,
-      const HostPortPair& host_port_pair) {
-    QuicServerId server_id(host_port_pair, PRIVACY_MODE_DISABLED);
-    DCHECK(factory->HasActiveSession(server_id));
-    return factory->active_sessions_[server_id];
-  }
-
-  static scoped_ptr<QuicHttpStream> CreateFromSession(
-      QuicStreamFactory* factory,
-      QuicChromiumClientSession* session) {
-    return factory->CreateFromSession(session);
-  }
-
-  static bool IsLiveSession(QuicStreamFactory* factory,
-                            QuicChromiumClientSession* session) {
-    for (QuicStreamFactory::SessionIdMap::iterator it =
-             factory->all_sessions_.begin();
-         it != factory->all_sessions_.end(); ++it) {
-      if (it->first == session)
-        return true;
-    }
-    return false;
-  }
-
-  static void SetTaskRunner(QuicStreamFactory* factory,
-                            base::TaskRunner* task_runner) {
-    factory->task_runner_ = task_runner;
-  }
-
-  static int GetNumberOfLossyConnections(QuicStreamFactory* factory,
-                                         uint16 port) {
-    return factory->number_of_lossy_connections_[port];
-  }
-
-  static bool IsQuicDisabled(QuicStreamFactory* factory, uint16 port) {
-    return factory->IsQuicDisabled(port);
-  }
-
-  static bool GetDelayTcpRace(QuicStreamFactory* factory) {
-    return factory->delay_tcp_race_;
-  }
-
-  static void SetDelayTcpRace(QuicStreamFactory* factory, bool delay_tcp_race) {
-    factory->delay_tcp_race_ = delay_tcp_race;
-  }
-
-  static void SetYieldAfterPackets(QuicStreamFactory* factory,
-                                   int yield_after_packets) {
-    factory->yield_after_packets_ = yield_after_packets;
-  }
-
-  static void SetYieldAfterDuration(QuicStreamFactory* factory,
-                                    QuicTime::Delta yield_after_duration) {
-    factory->yield_after_duration_ = yield_after_duration;
-  }
-
-  static size_t GetNumberOfActiveJobs(QuicStreamFactory* factory,
-                                      const QuicServerId& server_id) {
-    return (factory->active_jobs_[server_id]).size();
-  }
-
-  static int GetNumTimeoutsWithOpenStreams(QuicStreamFactory* factory) {
-    return factory->num_timeouts_with_open_streams_;
-  }
-
-  static int GetNumPublicResetsPostHandshake(QuicStreamFactory* factory) {
-    return factory->num_public_resets_post_handshake_;
-  }
-
-  static void MaybeInitialize(QuicStreamFactory* factory) {
-    factory->MaybeInitialize();
-  }
-
-  static bool HasInitializedData(QuicStreamFactory* factory) {
-    return factory->has_initialized_data_;
-  }
-
-  static bool SupportsQuicAtStartUp(QuicStreamFactory* factory,
-                                    HostPortPair host_port_pair) {
-    return ContainsKey(factory->quic_supported_servers_at_startup_,
-                       host_port_pair);
-  }
-
-  static bool CryptoConfigCacheIsEmpty(QuicStreamFactory* factory,
-                                       QuicServerId& quic_server_id) {
-    return factory->CryptoConfigCacheIsEmpty(quic_server_id);
-  }
-};
-
 class MockQuicServerInfo : public QuicServerInfo {
  public:
   MockQuicServerInfo(const QuicServerId& server_id)
@@ -2736,6 +2631,21 @@
   EXPECT_EQ(test_cert, cached->certs()[0]);
 }
 
+TEST_P(QuicStreamFactoryTest, QuicDoingZeroRTT) {
+  Initialize();
+
+  factory_->set_require_confirmation(true);
+  QuicServerId quic_server_id(host_port_pair_, PRIVACY_MODE_DISABLED);
+  EXPECT_FALSE(factory_->ZeroRTTEnabledFor(quic_server_id));
+
+  factory_->set_require_confirmation(false);
+  EXPECT_FALSE(factory_->ZeroRTTEnabledFor(quic_server_id));
+
+  // Load server config and verify QUIC will do 0RTT.
+  QuicStreamFactoryPeer::CacheDummyServerConfig(factory_.get(), quic_server_id);
+  EXPECT_TRUE(factory_->ZeroRTTEnabledFor(quic_server_id));
+}
+
 TEST_P(QuicStreamFactoryTest, YieldAfterPackets) {
   Initialize();
   QuicStreamFactoryPeer::SetYieldAfterPackets(factory_.get(), 0);
diff --git a/net/quic/quic_stream_sequencer.cc b/net/quic/quic_stream_sequencer.cc
index 34c0d25..cfa8481e 100644
--- a/net/quic/quic_stream_sequencer.cc
+++ b/net/quic/quic_stream_sequencer.cc
@@ -46,7 +46,7 @@
 void QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) {
   ++num_frames_received_;
   const QuicStreamOffset byte_offset = frame.offset;
-  const size_t data_len = frame.data.length();
+  const size_t data_len = frame.frame_length;
   if (data_len == 0 && !frame.fin) {
     // Stream frames must have data or a fin flag.
     stream_->CloseConnectionWithDetails(QUIC_INVALID_STREAM_FRAME,
@@ -62,7 +62,8 @@
   }
   size_t bytes_written;
   QuicErrorCode result = buffered_frames_->OnStreamData(
-      byte_offset, frame.data, clock_->ApproximateNow(), &bytes_written);
+      byte_offset, StringPiece(frame.frame_buffer, frame.frame_length),
+      clock_->ApproximateNow(), &bytes_written);
 
   if (result == QUIC_INVALID_STREAM_DATA) {
     stream_->CloseConnectionWithDetails(
diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc
index 83233dc..d2b2b61 100644
--- a/net/quic/quic_stream_sequencer_test.cc
+++ b/net/quic/quic_stream_sequencer_test.cc
@@ -145,7 +145,8 @@
     QuicStreamFrame frame;
     frame.stream_id = 1;
     frame.offset = byte_offset;
-    frame.data = StringPiece(data);
+    frame.frame_buffer = data;
+    frame.frame_length = strlen(data);
     frame.fin = true;
     sequencer_->OnStreamFrame(frame);
   }
@@ -154,7 +155,8 @@
     QuicStreamFrame frame;
     frame.stream_id = 1;
     frame.offset = byte_offset;
-    frame.data = StringPiece(data);
+    frame.frame_buffer = data;
+    frame.frame_length = strlen(data);
     frame.fin = false;
     sequencer_->OnStreamFrame(frame);
   }
diff --git a/net/quic/quic_time.cc b/net/quic/quic_time.cc
index 83217180..2b3684b 100644
--- a/net/quic/quic_time.cc
+++ b/net/quic/quic_time.cc
@@ -4,17 +4,17 @@
 
 #include "net/quic/quic_time.h"
 
-#include <stdint.h>
+#include <limits>
 
 #include "base/logging.h"
 
 namespace net {
 
-uint64 QuicWallTime::ToUNIXSeconds() const {
+uint64_t QuicWallTime::ToUNIXSeconds() const {
   return microseconds_ / 1000000;
 }
 
-uint64 QuicWallTime::ToUNIXMicroseconds() const {
+uint64_t QuicWallTime::ToUNIXMicroseconds() const {
   return microseconds_;
 }
 
@@ -31,7 +31,7 @@
 }
 
 QuicTime::Delta QuicWallTime::AbsoluteDifference(QuicWallTime other) const {
-  uint64 d;
+  uint64_t d;
 
   if (microseconds_ > other.microseconds_) {
     d = microseconds_ - other.microseconds_;
@@ -39,23 +39,23 @@
     d = other.microseconds_ - microseconds_;
   }
 
-  if (d > static_cast<uint64>(kint64max)) {
-    d = kint64max;
+  if (d > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
+    d = std::numeric_limits<int64_t>::max();
   }
   return QuicTime::Delta::FromMicroseconds(d);
 }
 
 QuicWallTime QuicWallTime::Add(QuicTime::Delta delta) const {
-  uint64 microseconds = microseconds_ + delta.ToMicroseconds();
+  uint64_t microseconds = microseconds_ + delta.ToMicroseconds();
   if (microseconds < microseconds_) {
-    microseconds = kuint64max;
+    microseconds = std::numeric_limits<uint64_t>::max();
   }
   return QuicWallTime(microseconds);
 }
 
 // TODO(ianswett) Test this.
 QuicWallTime QuicWallTime::Subtract(QuicTime::Delta delta) const {
-  uint64 microseconds = microseconds_ - delta.ToMicroseconds();
+  uint64_t microseconds = microseconds_ - delta.ToMicroseconds();
   if (microseconds > microseconds_) {
     microseconds = 0;
   }
diff --git a/net/quic/quic_time.h b/net/quic/quic_time.h
index 9851ca5..e6db990ec 100644
--- a/net/quic/quic_time.h
+++ b/net/quic/quic_time.h
@@ -11,7 +11,8 @@
 #ifndef NET_QUIC_QUIC_TIME_H_
 #define NET_QUIC_QUIC_TIME_H_
 
-#include "base/basictypes.h"
+#include <stdint.h>
+
 #include "base/compiler_specific.h"
 #include "base/time/time.h"
 #include "net/base/net_export.h"
@@ -22,8 +23,8 @@
 
 static const int kNumSecondsPerMinute = 60;
 static const int kNumSecondsPerHour = kNumSecondsPerMinute * 60;
-static const uint64 kNumMicrosPerSecond = base::Time::kMicrosecondsPerSecond;
-static const uint64 kNumMicrosPerMilli =
+static const uint64_t kNumMicrosPerSecond = base::Time::kMicrosecondsPerSecond;
+static const uint64_t kNumMicrosPerMilli =
     base::Time::kMicrosecondsPerMillisecond;
 
 // A QuicTime is a purely relative time. QuicTime values from different clocks
@@ -46,28 +47,28 @@
     }
 
     // Converts a number of seconds to a time offset.
-    static QUICTIME_CONSTEXPR Delta FromSeconds(int64 secs) {
+    static QUICTIME_CONSTEXPR Delta FromSeconds(int64_t secs) {
       return Delta(secs * 1000 * 1000);
     }
 
     // Converts a number of milliseconds to a time offset.
-    static QUICTIME_CONSTEXPR Delta FromMilliseconds(int64 ms) {
+    static QUICTIME_CONSTEXPR Delta FromMilliseconds(int64_t ms) {
       return Delta(ms * 1000);
     }
 
     // Converts a number of microseconds to a time offset.
-    static QUICTIME_CONSTEXPR Delta FromMicroseconds(int64 us) {
+    static QUICTIME_CONSTEXPR Delta FromMicroseconds(int64_t us) {
       return Delta(us);
     }
 
     // Converts the time offset to a rounded number of seconds.
-    inline int64 ToSeconds() const { return time_offset_ / 1000 / 1000; }
+    inline int64_t ToSeconds() const { return time_offset_ / 1000 / 1000; }
 
     // Converts the time offset to a rounded number of milliseconds.
-    inline int64 ToMilliseconds() const { return time_offset_ / 1000; }
+    inline int64_t ToMilliseconds() const { return time_offset_ / 1000; }
 
     // Converts the time offset to a rounded number of microseconds.
-    inline int64 ToMicroseconds() const { return time_offset_; }
+    inline int64_t ToMicroseconds() const { return time_offset_; }
 
     inline Delta Add(Delta delta) const WARN_UNUSED_RESULT {
       return Delta(time_offset_ + delta.time_offset_);
@@ -107,12 +108,12 @@
     friend inline bool operator<(QuicTime::Delta lhs, QuicTime::Delta rhs);
 
     // Highest number of microseconds that DateTimeOffset can hold.
-    static const int64 kQuicInfiniteTimeUs = INT64_C(0x7fffffffffffffff) / 10;
+    static const int64_t kQuicInfiniteTimeUs = INT64_C(0x7fffffffffffffff) / 10;
 
-    explicit QUICTIME_CONSTEXPR Delta(int64 time_offset)
+    explicit QUICTIME_CONSTEXPR Delta(int64_t time_offset)
         : time_offset_(time_offset) {}
 
-    int64 time_offset_;
+    int64_t time_offset_;
     friend class QuicTime;
     friend class QuicClock;
   };
@@ -137,7 +138,7 @@
   // represents the number of microseconds since some epoch.  It may
   // be the UNIX epoch on some platforms.  On others, it may
   // be a CPU ticks based value.
-  inline int64 ToDebuggingValue() const { return time_; }
+  inline int64_t ToDebuggingValue() const { return time_; }
 
   inline bool IsInitialized() const { return 0 != time_; }
 
@@ -159,9 +160,9 @@
   friend class QuicClock;
   friend class QuicClockTest;
 
-  explicit QUICTIME_CONSTEXPR QuicTime(int64 time) : time_(time) {}
+  explicit QUICTIME_CONSTEXPR QuicTime(int64_t time) : time_(time) {}
 
-  int64 time_;
+  int64_t time_;
 };
 
 // A QuicWallTime represents an absolute time that is globally consistent. In
@@ -171,12 +172,12 @@
  public:
   // FromUNIXSeconds constructs a QuicWallTime from a count of the seconds
   // since the UNIX epoch.
-  static QUICTIME_CONSTEXPR QuicWallTime FromUNIXSeconds(uint64 seconds) {
+  static QUICTIME_CONSTEXPR QuicWallTime FromUNIXSeconds(uint64_t seconds) {
     return QuicWallTime(seconds * 1000000);
   }
 
   static QUICTIME_CONSTEXPR QuicWallTime
-  FromUNIXMicroseconds(uint64 microseconds) {
+  FromUNIXMicroseconds(uint64_t microseconds) {
     return QuicWallTime(microseconds);
   }
 
@@ -185,9 +186,9 @@
   static QUICTIME_CONSTEXPR QuicWallTime Zero() { return QuicWallTime(0); }
 
   // Returns the number of seconds since the UNIX epoch.
-  uint64 ToUNIXSeconds() const;
+  uint64_t ToUNIXSeconds() const;
   // Returns the number of microseconds since the UNIX epoch.
-  uint64 ToUNIXMicroseconds() const;
+  uint64_t ToUNIXMicroseconds() const;
 
   bool IsAfter(QuicWallTime other) const;
   bool IsBefore(QuicWallTime other) const;
@@ -208,10 +209,10 @@
   QuicWallTime Subtract(QuicTime::Delta delta) const WARN_UNUSED_RESULT;
 
  private:
-  explicit QUICTIME_CONSTEXPR QuicWallTime(uint64 microseconds)
+  explicit QUICTIME_CONSTEXPR QuicWallTime(uint64_t microseconds)
       : microseconds_(microseconds) {}
 
-  uint64 microseconds_;
+  uint64_t microseconds_;
 };
 
 // Non-member relational operators for QuicTime::Delta.
diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc
index a9a9e894..be3e8ee 100644
--- a/net/quic/quic_unacked_packet_map.cc
+++ b/net/quic/quic_unacked_packet_map.cc
@@ -50,8 +50,9 @@
   }
 
   TransmissionInfo info(packet->retransmittable_frames,
-                        packet->packet_number_length, transmission_type,
-                        sent_time, bytes_sent, packet->is_fec_packet);
+                        packet->encryption_level, packet->packet_number_length,
+                        transmission_type, sent_time, bytes_sent,
+                        packet->is_fec_packet);
   if (old_packet_number > 0) {
     TransferRetransmissionInfo(old_packet_number, packet_number,
                                transmission_type, &info);
diff --git a/net/quic/quic_unacked_packet_map_test.cc b/net/quic/quic_unacked_packet_map_test.cc
index 1e302e3..adbca84 100644
--- a/net/quic/quic_unacked_packet_map_test.cc
+++ b/net/quic/quic_unacked_packet_map_test.cc
@@ -33,16 +33,16 @@
 
   SerializedPacket CreateRetransmittablePacket(QuicPacketNumber packet_number) {
     packets_.push_back(new QuicEncryptedPacket(nullptr, kDefaultLength));
-    return SerializedPacket(
-        packet_number, PACKET_1BYTE_PACKET_NUMBER, packets_.back(), 0,
-        new RetransmittableFrames(ENCRYPTION_NONE), false, false);
+    return SerializedPacket(packet_number, PACKET_1BYTE_PACKET_NUMBER,
+                            packets_.back(), 0, new RetransmittableFrames(),
+                            false, false);
   }
 
   SerializedPacket CreateRetransmittablePacketForStream(
       QuicPacketNumber packet_number,
       QuicStreamId stream_id) {
     packets_.push_back(new QuicEncryptedPacket(nullptr, kDefaultLength));
-    RetransmittableFrames* frames = new RetransmittableFrames(ENCRYPTION_NONE);
+    RetransmittableFrames* frames = new RetransmittableFrames();
     QuicStreamFrame* frame = new QuicStreamFrame();
     frame->stream_id = stream_id;
     frames->AddFrame(QuicFrame(frame));
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc
index daf0915..2682d5b8 100644
--- a/net/quic/reliable_quic_stream.cc
+++ b/net/quic/reliable_quic_stream.cc
@@ -52,7 +52,8 @@
 }
 
 ReliableQuicStream::ReliableQuicStream(QuicStreamId id, QuicSession* session)
-    : sequencer_(this, session->connection()->clock()),
+    : queued_data_bytes_(0),
+      sequencer_(this, session->connection()->clock()),
       id_(id),
       session_(session),
       stream_bytes_read_(0),
@@ -105,7 +106,7 @@
   }
 
   // This count includes duplicate data received.
-  size_t frame_payload_size = frame.data.size();
+  size_t frame_payload_size = frame.frame_length;
   stream_bytes_read_ += frame_payload_size;
 
   // Flow control is interested in tracking highest received offset.
@@ -216,6 +217,7 @@
   if (consumed_data.bytes_consumed < data.length() ||
       (fin && !consumed_data.fin_consumed)) {
     StringPiece remainder(data.substr(consumed_data.bytes_consumed));
+    queued_data_bytes_ += remainder.size();
     queued_data_.push_back(PendingData(remainder.as_string(), ack_listener));
   }
 }
@@ -242,6 +244,7 @@
         const_cast<char*>(pending_data->data.data()) + pending_data->offset,
         remaining_len};
     QuicConsumedData consumed_data = WritevData(&iov, 1, fin, ack_listener);
+    queued_data_bytes_ -= consumed_data.bytes_consumed;
     if (consumed_data.bytes_consumed == remaining_len &&
         fin == consumed_data.fin_consumed) {
       queued_data_.pop_front();
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h
index 096770c..3ea970b 100644
--- a/net/quic/reliable_quic_stream.h
+++ b/net/quic/reliable_quic_stream.h
@@ -113,6 +113,8 @@
   bool fin_received() { return fin_received_; }
   bool fin_sent() { return fin_sent_; }
 
+  uint64 queued_data_bytes() const { return queued_data_bytes_; }
+
   uint64 stream_bytes_read() const { return stream_bytes_read_; }
   uint64 stream_bytes_written() const { return stream_bytes_written_; }
 
@@ -246,6 +248,8 @@
   void MaybeSendBlocked();
 
   std::list<PendingData> queued_data_;
+  // How many bytes are queued?
+  uint64 queued_data_bytes_;
 
   QuicStreamSequencer sequencer_;
   QuicStreamId id_;
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
index 0fca992..7ef0def 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -195,6 +195,7 @@
       .WillOnce(Return(QuicConsumedData(1, false)));
   stream_->WriteOrBufferData(StringPiece(kData1, 2), false, nullptr);
   ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
+  EXPECT_EQ(1u, stream_->queued_data_bytes());
 }
 
 TEST_F(ReliableQuicStreamTest, BlockIfFinNotConsumedWithData) {
@@ -724,16 +725,6 @@
   EXPECT_EQ(FEC_PROTECT_ALWAYS, stream_->fec_policy());
 }
 
-static QuicConsumedData ConsumeAllData(
-    QuicStreamId id,
-    const QuicIOVector& data,
-    QuicStreamOffset offset,
-    bool fin,
-    FecProtection fec_protection,
-    QuicAckListenerInterface* ack_notifier_delegate) {
-  return QuicConsumedData(data.total_length, fin);
-}
-
 TEST_F(ReliableQuicStreamTest, EarlyResponseFinHandling) {
   // Verify that if the server completes the response before reading the end of
   // the request, the received FIN is recorded.
@@ -741,7 +732,7 @@
   Initialize(kShouldProcessData);
   EXPECT_CALL(*connection_, SendConnectionClose(_)).Times(0);
   EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
-      .WillRepeatedly(Invoke(ConsumeAllData));
+      .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData));
 
   // Receive data for the request.
   QuicStreamFrame frame1(stream_->id(), false, 0, StringPiece("Start"));
diff --git a/net/quic/spdy_utils.cc b/net/quic/spdy_utils.cc
index d66c200..6cfdc1e7 100644
--- a/net/quic/spdy_utils.cc
+++ b/net/quic/spdy_utils.cc
@@ -4,12 +4,18 @@
 
 #include "net/quic/spdy_utils.h"
 
+#include <vector>
+
 #include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
 #include "net/spdy/spdy_frame_builder.h"
 #include "net/spdy/spdy_framer.h"
 #include "net/spdy/spdy_protocol.h"
 
 using std::string;
+using std::vector;
 
 namespace net {
 
@@ -24,4 +30,79 @@
   return string(block->data(), length);
 }
 
+// static
+bool SpdyUtils::ParseHeaders(const char* data,
+                             uint32 data_len,
+                             int* content_length,
+                             SpdyHeaderBlock* headers) {
+  SpdyFramer framer(HTTP2);
+  if (!framer.ParseHeaderBlockInBuffer(data, data_len, headers) ||
+      headers->empty()) {
+    return false;  // Headers were invalid.
+  }
+
+  if (ContainsKey(*headers, "content-length")) {
+    // Check whether multiple values are consistent.
+    base::StringPiece content_length_header = (*headers)["content-length"];
+    vector<string> values =
+        base::SplitString(content_length_header, base::StringPiece("\0", 1),
+                          base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+    for (const string& value : values) {
+      int new_value;
+      if (!base::StringToInt(value, &new_value) || new_value < 0) {
+        return false;
+      }
+      if (*content_length < 0) {
+        *content_length = new_value;
+        continue;
+      }
+      if (new_value != *content_length) {
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+// static
+bool SpdyUtils::ParseTrailers(const char* data,
+                              uint32 data_len,
+                              size_t* final_byte_offset,
+                              SpdyHeaderBlock* trailers) {
+  SpdyFramer framer(HTTP2);
+  if (!framer.ParseHeaderBlockInBuffer(data, data_len, trailers) ||
+      trailers->empty()) {
+    DVLOG(1) << "Request Trailers are invalid.";
+    return false;  // Trailers were invalid.
+  }
+
+  // Pull out the :final-offset pseudo header which indicates the number of
+  // response body bytes expected.
+  auto it = trailers->find(":final-offset");
+  if (it == trailers->end() ||
+      !base::StringToSizeT(it->second, final_byte_offset)) {
+    DVLOG(1) << ":final-offset not present";
+    return false;  // :final-offset key must be present.
+  }
+  // :final-offset header is no longer used.
+  trailers->erase(it->first);
+
+  // Trailers must not have empty keys, and must not contain pseudo headers.
+  for (const auto& trailer : *trailers) {
+    base::StringPiece key = trailer.first;
+    base::StringPiece value = trailer.second;
+    if (key.starts_with(":")) {
+      DVLOG(1) << "Trailers must not contain pseudo-header: '" << key << "','"
+               << value << "'.";
+      return false;
+    }
+
+    // TODO(rjshade): Check for other forbidden keys, following the HTTP/2 spec.
+  }
+
+  DVLOG(1) << "Successfully parsed Trailers.";
+  return true;
+}
+
 }  // namespace net
diff --git a/net/quic/spdy_utils.h b/net/quic/spdy_utils.h
index 28b48dbe..76b667dd 100644
--- a/net/quic/spdy_utils.h
+++ b/net/quic/spdy_utils.h
@@ -5,6 +5,7 @@
 #ifndef NET_QUIC_SPDY_UTILS_H_
 #define NET_QUIC_SPDY_UTILS_H_
 
+#include <map>
 #include <string>
 
 #include "net/base/net_export.h"
@@ -18,6 +19,26 @@
   static std::string SerializeUncompressedHeaders(
       const SpdyHeaderBlock& headers);
 
+  // Parses |data| as a std::string containing serialized HTTP/2 HEADERS frame,
+  // populating |headers| with the key->value std:pairs found.
+  // |content_length| will be populated with the value of the content-length
+  // header if one or more are present.
+  // Returns true on success, false if parsing fails, or invalid keys are found.
+  static bool ParseHeaders(const char* data,
+                           uint32 data_len,
+                           int* content_length,
+                           SpdyHeaderBlock* headers);
+
+  // Parses |data| as a std::string containing serialized HTTP/2 HEADERS frame,
+  // populating |trailers| with the key->value std:pairs found.
+  // The :final-offset header will be excluded from |trailers|, and instead the
+  // value will be copied to |final_byte_offset|.
+  // Returns true on success, false if parsing fails, or invalid keys are found.
+  static bool ParseTrailers(const char* data,
+                            uint32 data_len,
+                            size_t* final_byte_offset,
+                            SpdyHeaderBlock* trailers);
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SpdyUtils);
 };
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index ed34502..5f3b728 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -635,7 +635,8 @@
     }
 
     for (const QuicStreamFrame* stream_frame : framer.stream_frames()) {
-      ASSERT_TRUE(crypto_framer.ProcessInput(stream_frame->data));
+      ASSERT_TRUE(crypto_framer.ProcessInput(
+          StringPiece(stream_frame->frame_buffer, stream_frame->frame_length)));
       ASSERT_FALSE(crypto_visitor.error());
     }
   }
diff --git a/net/quic/test_tools/quic_stream_factory_peer.cc b/net/quic/test_tools/quic_stream_factory_peer.cc
new file mode 100644
index 0000000..7f002fb
--- /dev/null
+++ b/net/quic/test_tools/quic_stream_factory_peer.cc
@@ -0,0 +1,165 @@
+// 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 "net/quic/test_tools/quic_stream_factory_peer.h"
+
+#include "net/quic/crypto/quic_crypto_client_config.h"
+#include "net/quic/quic_chromium_client_session.h"
+#include "net/quic/quic_clock.h"
+#include "net/quic/quic_http_stream.h"
+#include "net/quic/quic_stream_factory.h"
+
+using std::string;
+using std::vector;
+
+namespace net {
+namespace test {
+
+const QuicConfig* QuicStreamFactoryPeer::GetConfig(QuicStreamFactory* factory) {
+  return &factory->config_;
+}
+
+QuicCryptoClientConfig* QuicStreamFactoryPeer::GetCryptoConfig(
+    QuicStreamFactory* factory) {
+  return &factory->crypto_config_;
+}
+
+bool QuicStreamFactoryPeer::HasActiveSession(
+    QuicStreamFactory* factory,
+    const HostPortPair& host_port_pair) {
+  QuicServerId server_id(host_port_pair, PRIVACY_MODE_DISABLED);
+  return factory->HasActiveSession(server_id);
+}
+
+QuicChromiumClientSession* QuicStreamFactoryPeer::GetActiveSession(
+    QuicStreamFactory* factory,
+    const HostPortPair& host_port_pair) {
+  QuicServerId server_id(host_port_pair, PRIVACY_MODE_DISABLED);
+  DCHECK(factory->HasActiveSession(server_id));
+  return factory->active_sessions_[server_id];
+}
+
+scoped_ptr<QuicHttpStream> QuicStreamFactoryPeer::CreateFromSession(
+    QuicStreamFactory* factory,
+    QuicChromiumClientSession* session) {
+  return factory->CreateFromSession(session);
+}
+
+bool QuicStreamFactoryPeer::IsLiveSession(QuicStreamFactory* factory,
+                                          QuicChromiumClientSession* session) {
+  for (QuicStreamFactory::SessionIdMap::iterator it =
+           factory->all_sessions_.begin();
+       it != factory->all_sessions_.end(); ++it) {
+    if (it->first == session)
+      return true;
+  }
+  return false;
+}
+
+void QuicStreamFactoryPeer::SetTaskRunner(QuicStreamFactory* factory,
+                                          base::TaskRunner* task_runner) {
+  factory->task_runner_ = task_runner;
+}
+
+int QuicStreamFactoryPeer::GetNumberOfLossyConnections(
+    QuicStreamFactory* factory,
+    uint16 port) {
+  return factory->number_of_lossy_connections_[port];
+}
+
+bool QuicStreamFactoryPeer::IsQuicDisabled(QuicStreamFactory* factory,
+                                           uint16 port) {
+  return factory->IsQuicDisabled(port);
+}
+
+bool QuicStreamFactoryPeer::GetDelayTcpRace(QuicStreamFactory* factory) {
+  return factory->delay_tcp_race_;
+}
+
+void QuicStreamFactoryPeer::SetDelayTcpRace(QuicStreamFactory* factory,
+                                            bool delay_tcp_race) {
+  factory->delay_tcp_race_ = delay_tcp_race;
+}
+
+void QuicStreamFactoryPeer::SetYieldAfterPackets(QuicStreamFactory* factory,
+                                                 int yield_after_packets) {
+  factory->yield_after_packets_ = yield_after_packets;
+}
+
+void QuicStreamFactoryPeer::SetYieldAfterDuration(
+    QuicStreamFactory* factory,
+    QuicTime::Delta yield_after_duration) {
+  factory->yield_after_duration_ = yield_after_duration;
+}
+
+size_t QuicStreamFactoryPeer::GetNumberOfActiveJobs(
+    QuicStreamFactory* factory,
+    const QuicServerId& server_id) {
+  return (factory->active_jobs_[server_id]).size();
+}
+
+int QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(
+    QuicStreamFactory* factory) {
+  return factory->num_timeouts_with_open_streams_;
+}
+
+int QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(
+    QuicStreamFactory* factory) {
+  return factory->num_public_resets_post_handshake_;
+}
+
+void QuicStreamFactoryPeer::MaybeInitialize(QuicStreamFactory* factory) {
+  factory->MaybeInitialize();
+}
+
+bool QuicStreamFactoryPeer::HasInitializedData(QuicStreamFactory* factory) {
+  return factory->has_initialized_data_;
+}
+
+bool QuicStreamFactoryPeer::SupportsQuicAtStartUp(QuicStreamFactory* factory,
+                                                  HostPortPair host_port_pair) {
+  return ContainsKey(factory->quic_supported_servers_at_startup_,
+                     host_port_pair);
+}
+
+bool QuicStreamFactoryPeer::CryptoConfigCacheIsEmpty(
+    QuicStreamFactory* factory,
+    QuicServerId& quic_server_id) {
+  return factory->CryptoConfigCacheIsEmpty(quic_server_id);
+}
+
+void QuicStreamFactoryPeer::CacheDummyServerConfig(
+    QuicStreamFactory* factory,
+    const QuicServerId& quic_server_id) {
+  // Minimum SCFG that passes config validation checks.
+  const 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'};
+
+  string server_config(reinterpret_cast<const char*>(&scfg), sizeof(scfg));
+  string source_address_token("test_source_address_token");
+  string signature("test_signature");
+  string test_cert("test_cert");
+  vector<string> certs;
+  certs.push_back(test_cert);
+
+  QuicCryptoClientConfig* crypto_config = &factory->crypto_config_;
+  QuicCryptoClientConfig::CachedState* cached =
+      crypto_config->LookupOrCreate(quic_server_id);
+  QuicClock clock;
+  cached->Initialize(server_config, source_address_token, certs, "", signature,
+                     clock.WallNow());
+}
+
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/test_tools/quic_stream_factory_peer.h b/net/quic/test_tools/quic_stream_factory_peer.h
new file mode 100644
index 0000000..d8ddf2d
--- /dev/null
+++ b/net/quic/test_tools/quic_stream_factory_peer.h
@@ -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.
+
+#ifndef NET_QUIC_TEST_TOOLS_QUIC_STREAM_FACTORY_PEER_H_
+#define NET_QUIC_TEST_TOOLS_QUIC_STREAM_FACTORY_PEER_H_
+
+#include "base/basictypes.h"
+#include "base/task_runner.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/privacy_mode.h"
+#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_server_id.h"
+#include "net/quic/quic_time.h"
+
+namespace net {
+
+class QuicConfig;
+class QuicCryptoClientConfig;
+class QuicHttpStream;
+class QuicStreamFactory;
+class QuicChromiumClientSession;
+
+namespace test {
+
+class QuicStreamFactoryPeer {
+ public:
+  static const QuicConfig* GetConfig(QuicStreamFactory* factory);
+
+  static QuicCryptoClientConfig* GetCryptoConfig(QuicStreamFactory* factory);
+
+  static bool HasActiveSession(QuicStreamFactory* factory,
+                               const HostPortPair& host_port_pair);
+
+  static QuicChromiumClientSession* GetActiveSession(
+      QuicStreamFactory* factory,
+      const HostPortPair& host_port_pair);
+
+  static scoped_ptr<QuicHttpStream> CreateFromSession(
+      QuicStreamFactory* factory,
+      QuicChromiumClientSession* session);
+
+  static bool IsLiveSession(QuicStreamFactory* factory,
+                            QuicChromiumClientSession* session);
+
+  static void SetTaskRunner(QuicStreamFactory* factory,
+                            base::TaskRunner* task_runner);
+
+  static int GetNumberOfLossyConnections(QuicStreamFactory* factory,
+                                         uint16 port);
+
+  static bool IsQuicDisabled(QuicStreamFactory* factory, uint16 port);
+
+  static bool GetDelayTcpRace(QuicStreamFactory* factory);
+
+  static void SetDelayTcpRace(QuicStreamFactory* factory, bool delay_tcp_race);
+
+  static void SetYieldAfterPackets(QuicStreamFactory* factory,
+                                   int yield_after_packets);
+
+  static void SetYieldAfterDuration(QuicStreamFactory* factory,
+                                    QuicTime::Delta yield_after_duration);
+
+  static size_t GetNumberOfActiveJobs(QuicStreamFactory* factory,
+                                      const QuicServerId& server_id);
+
+  static int GetNumTimeoutsWithOpenStreams(QuicStreamFactory* factory);
+
+  static int GetNumPublicResetsPostHandshake(QuicStreamFactory* factory);
+
+  static void MaybeInitialize(QuicStreamFactory* factory);
+
+  static bool HasInitializedData(QuicStreamFactory* factory);
+
+  static bool SupportsQuicAtStartUp(QuicStreamFactory* factory,
+                                    HostPortPair host_port_pair);
+
+  static bool CryptoConfigCacheIsEmpty(QuicStreamFactory* factory,
+                                       QuicServerId& quic_server_id);
+
+  // Creates a dummy QUIC server config and caches it.
+  static void CacheDummyServerConfig(QuicStreamFactory* factory,
+                                     const QuicServerId& quic_server_id);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(QuicStreamFactoryPeer);
+};
+
+}  // namespace test
+}  // namespace net
+
+#endif  // NET_QUIC_TEST_TOOLS_QUIC_STREAM_FACTORY_PEER_H_
diff --git a/net/quic/test_tools/quic_stream_sequencer_peer.cc b/net/quic/test_tools/quic_stream_sequencer_peer.cc
index fea4579c..290e2ea 100644
--- a/net/quic/test_tools/quic_stream_sequencer_peer.cc
+++ b/net/quic/test_tools/quic_stream_sequencer_peer.cc
@@ -23,8 +23,8 @@
     QuicFrameList* buffer,
     const QuicStreamFrame& frame) {
   list<QuicFrameList::FrameData>::iterator it =
-      buffer->FindInsertionPoint(frame.offset, frame.data.length());
-  return buffer->FrameOverlapsBufferedData(frame.offset, frame.data.length(),
+      buffer->FindInsertionPoint(frame.offset, frame.frame_length);
+  return buffer->FrameOverlapsBufferedData(frame.offset, frame.frame_length,
                                            it);
 }
 
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index f46419b..7bb892f 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -325,6 +325,17 @@
 
 MockQuicSpdySession::~MockQuicSpdySession() {}
 
+// static
+QuicConsumedData MockQuicSpdySession::ConsumeAllData(
+    QuicStreamId /*id*/,
+    const QuicIOVector& data,
+    QuicStreamOffset /*offset*/,
+    bool fin,
+    FecProtection /*fec_protection*/,
+    QuicAckListenerInterface* /*ack_notifier_delegate*/) {
+  return QuicConsumedData(data.total_length, fin);
+}
+
 TestQuicSpdyServerSession::TestQuicSpdyServerSession(
     QuicConnection* connection,
     const QuicConfig& config,
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index d78916a..443f25e 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -454,6 +454,16 @@
 
   using QuicSession::ActivateStream;
 
+  // Returns a QuicConsumedData that indicates all of |data| (and |fin| if set)
+  // has been consumed.
+  static QuicConsumedData ConsumeAllData(
+      QuicStreamId id,
+      const QuicIOVector& data,
+      QuicStreamOffset offset,
+      bool fin,
+      FecProtection fec_protection,
+      QuicAckListenerInterface* ack_notifier_delegate);
+
  private:
   scoped_ptr<QuicCryptoStream> crypto_stream_;
 
@@ -693,10 +703,9 @@
 
   MOCK_METHOD1(OnFrameAddedToPacket, void(const QuicFrame&));
 
-  MOCK_METHOD6(OnPacketSent,
+  MOCK_METHOD5(OnPacketSent,
                void(const SerializedPacket&,
                     QuicPacketNumber,
-                    EncryptionLevel,
                     TransmissionType,
                     size_t encrypted_length,
                     QuicTime));
@@ -712,6 +721,8 @@
 
   MOCK_METHOD1(OnPacketHeader, void(const QuicPacketHeader& header));
 
+  MOCK_METHOD1(OnSuccessfulVersionNegotiation, void(const QuicVersion&));
+
   MOCK_METHOD1(OnStreamFrame, void(const QuicStreamFrame&));
 
   MOCK_METHOD1(OnAckFrame, void(const QuicAckFrame& frame));
diff --git a/net/quic/test_tools/simple_quic_framer.cc b/net/quic/test_tools/simple_quic_framer.cc
index 60e393b..a8ce3323 100644
--- a/net/quic/test_tools/simple_quic_framer.cc
+++ b/net/quic/test_tools/simple_quic_framer.cc
@@ -60,7 +60,8 @@
   bool OnStreamFrame(const QuicStreamFrame& frame) override {
     // Save a copy of the data so it is valid after the packet is processed.
     string* string_data = new string();
-    frame.data.AppendToString(string_data);
+    StringPiece(frame.frame_buffer, frame.frame_length)
+        .AppendToString(string_data);
     stream_data_.push_back(string_data);
     // TODO(ianswett): A pointer isn't necessary with emplace_back.
     stream_frames_.push_back(new QuicStreamFrame(
diff --git a/net/server/http_server.cc b/net/server/http_server.cc
index f3560e8..a184f4d1 100644
--- a/net/server/http_server.cc
+++ b/net/server/http_server.cc
@@ -346,17 +346,16 @@
 };
 
 // State transition table
-int parser_state[MAX_STATES][MAX_INPUTS] = {
-/* METHOD    */ { ST_URL,       ST_ERR,     ST_ERR,   ST_ERR,       ST_METHOD },
-/* URL       */ { ST_PROTO,     ST_ERR,     ST_ERR,   ST_URL,       ST_URL },
-/* PROTOCOL  */ { ST_ERR,       ST_HEADER,  ST_NAME,  ST_ERR,       ST_PROTO },
-/* HEADER    */ { ST_ERR,       ST_ERR,     ST_NAME,  ST_ERR,       ST_ERR },
-/* NAME      */ { ST_SEPARATOR, ST_DONE,    ST_ERR,   ST_VALUE,     ST_NAME },
-/* SEPARATOR */ { ST_SEPARATOR, ST_ERR,     ST_ERR,   ST_VALUE,     ST_ERR },
-/* VALUE     */ { ST_VALUE,     ST_HEADER,  ST_NAME,  ST_VALUE,     ST_VALUE },
-/* DONE      */ { ST_DONE,      ST_DONE,    ST_DONE,  ST_DONE,      ST_DONE },
-/* ERR       */ { ST_ERR,       ST_ERR,     ST_ERR,   ST_ERR,       ST_ERR }
-};
+const int parser_state[MAX_STATES][MAX_INPUTS] = {
+    /* METHOD    */ {ST_URL, ST_ERR, ST_ERR, ST_ERR, ST_METHOD},
+    /* URL       */ {ST_PROTO, ST_ERR, ST_ERR, ST_URL, ST_URL},
+    /* PROTOCOL  */ {ST_ERR, ST_HEADER, ST_NAME, ST_ERR, ST_PROTO},
+    /* HEADER    */ {ST_ERR, ST_ERR, ST_NAME, ST_ERR, ST_ERR},
+    /* NAME      */ {ST_SEPARATOR, ST_DONE, ST_ERR, ST_VALUE, ST_NAME},
+    /* SEPARATOR */ {ST_SEPARATOR, ST_ERR, ST_ERR, ST_VALUE, ST_ERR},
+    /* VALUE     */ {ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_VALUE},
+    /* DONE      */ {ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE},
+    /* ERR       */ {ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR}};
 
 // Convert an input character to the parser's input token.
 int charToInput(char ch) {
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index f4974ac..5b8c7519 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -1355,6 +1355,15 @@
   return ERR_NOT_IMPLEMENTED;
 }
 
+int DeterministicMockUDPClientSocket::BindToDefaultNetwork() {
+  return ERR_NOT_IMPLEMENTED;
+}
+
+NetworkChangeNotifier::NetworkHandle
+DeterministicMockUDPClientSocket::GetBoundNetwork() {
+  return NetworkChangeNotifier::kInvalidNetworkHandle;
+}
+
 int DeterministicMockUDPClientSocket::Connect(const IPEndPoint& address) {
   if (connected_)
     return OK;
@@ -1733,6 +1742,14 @@
   return ERR_NOT_IMPLEMENTED;
 }
 
+int MockUDPClientSocket::BindToDefaultNetwork() {
+  return ERR_NOT_IMPLEMENTED;
+}
+
+NetworkChangeNotifier::NetworkHandle MockUDPClientSocket::GetBoundNetwork() {
+  return NetworkChangeNotifier::kInvalidNetworkHandle;
+}
+
 int MockUDPClientSocket::Connect(const IPEndPoint& address) {
   if (!data_)
     return ERR_UNEXPECTED;
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index 9d4ecfb..13f7b397 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -860,6 +860,8 @@
 
   // DatagramClientSocket implementation.
   int BindToNetwork(NetworkChangeNotifier::NetworkHandle network) override;
+  int BindToDefaultNetwork() override;
+  NetworkChangeNotifier::NetworkHandle GetBoundNetwork() override;
   int Connect(const IPEndPoint& address) override;
 
   void set_source_port(uint16 port) { source_port_ = port; }
@@ -988,6 +990,8 @@
 
   // DatagramClientSocket implementation.
   int BindToNetwork(NetworkChangeNotifier::NetworkHandle network) override;
+  int BindToDefaultNetwork() override;
+  NetworkChangeNotifier::NetworkHandle GetBoundNetwork() override;
   int Connect(const IPEndPoint& address) override;
 
   // AsyncSocket implementation.
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index ee01c29..9532664d 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -38,6 +38,7 @@
                  dictionary_size);
 }
 
+#if !defined(USE_SYSTEM_ZLIB)
 // Check to see if the name and value of a cookie are both empty.
 bool IsCookieEmpty(const base::StringPiece& cookie) {
   if (cookie.size() == 0) {
@@ -56,6 +57,7 @@
   }
   return (pos == 0) && ((cookie.size() - value_start) == 0);
 }
+#endif  // !defined(USE_SYSTEM_ZLIB)
 
 // Pack parent stream ID and exclusive flag into the format used by HTTP/2
 // headers and priority frames.
diff --git a/net/ssl/client_cert_store_win.cc b/net/ssl/client_cert_store_win.cc
index c8b7501..1ebf02d 100644
--- a/net/ssl/client_cert_store_win.cc
+++ b/net/ssl/client_cert_store_win.cc
@@ -98,7 +98,7 @@
                                          &find_by_issuer_para,
                                          chain_context);
     if (!chain_context) {
-      if (GetLastError() != CRYPT_E_NOT_FOUND)
+      if (GetLastError() != static_cast<DWORD>(CRYPT_E_NOT_FOUND))
         DPLOG(ERROR) << "CertFindChainInStore failed: ";
       break;
     }
diff --git a/net/test/ct_test_util.cc b/net/test/ct_test_util.cc
index 2ad827d..3bd30ff4 100644
--- a/net/test/ct_test_util.cc
+++ b/net/test/ct_test_util.cc
@@ -14,7 +14,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "net/cert/ct_serialization.h"
-#include "net/cert/ct_verify_result.h"
+#include "net/cert/signed_certificate_timestamp.h"
 #include "net/cert/signed_tree_head.h"
 #include "net/cert/x509_certificate.h"
 
@@ -329,38 +329,6 @@
   return consistency_proof_json;
 }
 
-std::string GetSCTListForTesting() {
-  const std::string sct = ct::GetTestSignedCertificateTimestamp();
-  std::string sct_list;
-  ct::EncodeSCTListForTesting(sct, &sct_list);
-  return sct_list;
-}
-
-std::string GetSCTListWithInvalidSCT() {
-  std::string sct(ct::GetTestSignedCertificateTimestamp());
-
-  // Change a byte inside the Log ID part of the SCT so it does not match the
-  // log used in the tests.
-  sct[15] = 't';
-
-  std::string sct_list;
-  ct::EncodeSCTListForTesting(sct, &sct_list);
-  return sct_list;
-}
-
-bool CheckForSingleVerifiedSCTInResult(const ct::CTVerifyResult& result,
-                                       const std::string& log_description) {
-  return (result.verified_scts.size() == 1U) && result.invalid_scts.empty() &&
-         result.unknown_logs_scts.empty() &&
-         result.verified_scts[0]->log_description == log_description;
-}
-
-bool CheckForSCTOrigin(const ct::CTVerifyResult& result,
-                       ct::SignedCertificateTimestamp::Origin origin) {
-  return (result.verified_scts.size() > 0) &&
-         (result.verified_scts[0]->origin == origin);
-}
-
 }  // namespace ct
 
 }  // namespace net
diff --git a/net/test/ct_test_util.h b/net/test/ct_test_util.h
index c54c38b..5bb2d7a 100644
--- a/net/test/ct_test_util.h
+++ b/net/test/ct_test_util.h
@@ -9,15 +9,14 @@
 #include <vector>
 
 #include "base/memory/ref_counted.h"
-#include "net/cert/signed_certificate_timestamp.h"
 
 namespace net {
 
 namespace ct {
 
-struct CTVerifyResult;
 struct DigitallySigned;
 struct LogEntry;
+struct SignedCertificateTimestamp;
 struct SignedTreeHead;
 
 // Note: unless specified otherwise, all test data is taken from Certificate
@@ -92,23 +91,6 @@
 // the provided raw nodes (i.e. the raw nodes will be base64-encoded).
 std::string CreateConsistencyProofJsonString(
     const std::vector<std::string>& raw_nodes);
-
-// Returns SCTList for testing.
-std::string GetSCTListForTesting();
-
-// Returns a corrupted SCTList. This is done by changing a byte inside the
-// Log ID part of the SCT so it does not match the log used in the tests.
-std::string GetSCTListWithInvalidSCT();
-
-// Returns true if |log_description| is in the |result|'s |verified_scts| and
-// number of |verified_scts| in |result| is equal to 1.
-bool CheckForSingleVerifiedSCTInResult(const CTVerifyResult& result,
-                                       const std::string& log_description);
-
-// Returns true if |origin| is in the |result|'s |verified_scts|.
-bool CheckForSCTOrigin(const CTVerifyResult& result,
-                       SignedCertificateTimestamp::Origin origin);
-
 }  // namespace ct
 
 }  // namespace net
diff --git a/net/tools/quic/quic_in_memory_cache.cc b/net/tools/quic/quic_in_memory_cache.cc
index 0671099..fd77050 100644
--- a/net/tools/quic/quic_in_memory_cache.cc
+++ b/net/tools/quic/quic_in_memory_cache.cc
@@ -85,14 +85,24 @@
                                     StringPiece path,
                                     const SpdyHeaderBlock& response_headers,
                                     StringPiece response_body) {
-  AddResponseImpl(host, path, REGULAR_RESPONSE, response_headers,
-                  response_body);
+  AddResponseImpl(host, path, REGULAR_RESPONSE, response_headers, response_body,
+                  SpdyHeaderBlock());
+}
+
+void QuicInMemoryCache::AddResponse(StringPiece host,
+                                    StringPiece path,
+                                    const SpdyHeaderBlock& response_headers,
+                                    StringPiece response_body,
+                                    const SpdyHeaderBlock& response_trailers) {
+  AddResponseImpl(host, path, REGULAR_RESPONSE, response_headers, response_body,
+                  response_trailers);
 }
 
 void QuicInMemoryCache::AddSpecialResponse(StringPiece host,
                                            StringPiece path,
                                            SpecialResponseType response_type) {
-  AddResponseImpl(host, path, response_type, SpdyHeaderBlock(), "");
+  AddResponseImpl(host, path, response_type, SpdyHeaderBlock(), "",
+                  SpdyHeaderBlock());
 }
 
 QuicInMemoryCache::QuicInMemoryCache() {}
@@ -187,11 +197,13 @@
   STLDeleteValues(&responses_);
 }
 
-void QuicInMemoryCache::AddResponseImpl(StringPiece host,
-                                        StringPiece path,
-                                        SpecialResponseType response_type,
-                                        const SpdyHeaderBlock& response_headers,
-                                        StringPiece response_body) {
+void QuicInMemoryCache::AddResponseImpl(
+    StringPiece host,
+    StringPiece path,
+    SpecialResponseType response_type,
+    const SpdyHeaderBlock& response_headers,
+    StringPiece response_body,
+    const SpdyHeaderBlock& response_trailers) {
   string key = GetKey(host, path);
   if (ContainsKey(responses_, key)) {
     LOG(DFATAL) << "Response for '" << key << "' already exists!";
@@ -201,6 +213,7 @@
   new_response->set_response_type(response_type);
   new_response->set_headers(response_headers);
   new_response->set_body(response_body);
+  new_response->set_trailers(response_trailers);
   responses_[key] = new_response;
 }
 
diff --git a/net/tools/quic/quic_in_memory_cache.h b/net/tools/quic/quic_in_memory_cache.h
index 5ceaf52e..f6ef75b 100644
--- a/net/tools/quic/quic_in_memory_cache.h
+++ b/net/tools/quic/quic_in_memory_cache.h
@@ -66,6 +66,7 @@
 
     SpecialResponseType response_type() const { return response_type_; }
     const SpdyHeaderBlock& headers() const { return headers_; }
+    const SpdyHeaderBlock& trailers() const { return trailers_; }
     const base::StringPiece body() const { return base::StringPiece(body_); }
 
     void set_response_type(SpecialResponseType response_type) {
@@ -74,6 +75,7 @@
     void set_headers(const SpdyHeaderBlock& headers) {
       headers_ = headers;
     }
+    void set_trailers(const SpdyHeaderBlock& trailers) { trailers_ = trailers; }
     void set_body(base::StringPiece body) {
       body.CopyToString(&body_);
     }
@@ -81,7 +83,8 @@
    private:
     SpecialResponseType response_type_;
     SpdyHeaderBlock headers_;
-    string body_;
+    SpdyHeaderBlock trailers_;
+    std::string body_;
 
     DISALLOW_COPY_AND_ASSIGN(Response);
   };
@@ -118,6 +121,13 @@
                    const SpdyHeaderBlock& response_headers,
                    base::StringPiece response_body);
 
+  // Add a response, with trailers, to the cache.
+  void AddResponse(base::StringPiece host,
+                   base::StringPiece path,
+                   const SpdyHeaderBlock& response_headers,
+                   base::StringPiece response_body,
+                   const SpdyHeaderBlock& response_trailers);
+
   // Simulate a special behavior at a particular path.
   void AddSpecialResponse(base::StringPiece host,
                           base::StringPiece path,
@@ -148,7 +158,8 @@
                        base::StringPiece path,
                        SpecialResponseType response_type,
                        const SpdyHeaderBlock& response_headers,
-                       base::StringPiece response_body);
+                       base::StringPiece response_body,
+                       const SpdyHeaderBlock& response_trailers);
 
   string GetKey(base::StringPiece host, base::StringPiece path) const;
 
diff --git a/net/tools/quic/quic_in_memory_cache_test.cc b/net/tools/quic/quic_in_memory_cache_test.cc
index e42a91d..dbfc1a7 100644
--- a/net/tools/quic/quic_in_memory_cache_test.cc
+++ b/net/tools/quic/quic_in_memory_cache_test.cc
@@ -76,6 +76,32 @@
   EXPECT_EQ(response_body.size(), response->body().length());
 }
 
+TEST_F(QuicInMemoryCacheTest, AddResponse) {
+  const string kRequestHost = "www.foo.com";
+  const string kRequestPath = "/";
+  const string kResponseBody("hello response");
+
+  SpdyHeaderBlock response_headers;
+  response_headers[":version"] = "HTTP/1.1";
+  response_headers[":status"] = "200";
+  response_headers["content-length"] = IntToString(kResponseBody.size());
+
+  SpdyHeaderBlock response_trailers;
+  response_trailers["key-1"] = "value-1";
+  response_trailers["key-2"] = "value-2";
+  response_trailers["key-3"] = "value-3";
+
+  QuicInMemoryCache* cache = QuicInMemoryCache::GetInstance();
+  cache->AddResponse(kRequestHost, "/", response_headers, kResponseBody,
+                     response_trailers);
+
+  const QuicInMemoryCache::Response* response =
+      cache->GetResponse(kRequestHost, kRequestPath);
+  EXPECT_EQ(response->headers(), response_headers);
+  EXPECT_EQ(response->body(), kResponseBody);
+  EXPECT_EQ(response->trailers(), response_trailers);
+}
+
 TEST_F(QuicInMemoryCacheTest, ReadsCacheDir) {
   QuicInMemoryCache::GetInstance()->InitializeFromDirectory(CacheDirectory());
   const QuicInMemoryCache::Response* response =
diff --git a/net/tools/quic/quic_spdy_client_stream.cc b/net/tools/quic/quic_spdy_client_stream.cc
index 817366c..48554b5 100644
--- a/net/tools/quic/quic_spdy_client_stream.cc
+++ b/net/tools/quic/quic_spdy_client_stream.cc
@@ -44,11 +44,24 @@
                                                    size_t frame_len) {
   header_bytes_read_ = frame_len;
   QuicSpdyStream::OnStreamHeadersComplete(fin, frame_len);
-  if (!ParseResponseHeaders(decompressed_headers().data(),
-                            decompressed_headers().length())) {
+  if (!SpdyUtils::ParseHeaders(decompressed_headers().data(),
+                               decompressed_headers().length(),
+                               &content_length_, &response_headers_)) {
     Reset(QUIC_BAD_APPLICATION_PAYLOAD);
     return;
   }
+
+  string status = response_headers_[":status"].as_string();
+  size_t end = status.find(" ");
+  if (end != string::npos) {
+    status.erase(end);
+  }
+  if (!StringToInt(status, &response_code_)) {
+    // Invalid response code.
+    Reset(QUIC_BAD_APPLICATION_PAYLOAD);
+    return;
+  }
+
   MarkHeadersConsumed(decompressed_headers().length());
 }
 
@@ -77,31 +90,6 @@
   }
 }
 
-bool QuicSpdyClientStream::ParseResponseHeaders(const char* data,
-                                                uint32 data_len) {
-  DCHECK(headers_decompressed());
-  SpdyFramer framer(HTTP2);
-  if (!framer.ParseHeaderBlockInBuffer(data, data_len, &response_headers_) ||
-      response_headers_.empty()) {
-    return false;  // Headers were invalid.
-  }
-
-  if (ContainsKey(response_headers_, "content-length") &&
-      !StringToInt(StringPiece(response_headers_["content-length"]),
-                   &content_length_)) {
-    return false;  // Invalid content-length.
-  }
-  string status = response_headers_[":status"].as_string();
-  size_t end = status.find(" ");
-  if (end != string::npos) {
-    status.erase(end);
-  }
-  if (!StringToInt(status, &response_code_)) {
-    return false;  // Invalid response code.
-  }
-  return true;
-}
-
 size_t QuicSpdyClientStream::SendRequest(const SpdyHeaderBlock& headers,
                                          StringPiece body,
                                          bool fin) {
diff --git a/net/tools/quic/quic_spdy_client_stream.h b/net/tools/quic/quic_spdy_client_stream.h
index 6aa7824f..b744c21a 100644
--- a/net/tools/quic/quic_spdy_client_stream.h
+++ b/net/tools/quic/quic_spdy_client_stream.h
@@ -74,8 +74,6 @@
   bool allow_bidirectional_data() const { return allow_bidirectional_data_; }
 
  private:
-  bool ParseResponseHeaders(const char* data, uint32 data_len);
-
   // The parsed headers received from the server.
   SpdyHeaderBlock response_headers_;
   // The parsed content-length, or -1 if none is specified.
diff --git a/net/tools/quic/quic_spdy_server_stream.cc b/net/tools/quic/quic_spdy_server_stream.cc
index f10d040..dffed6e0 100644
--- a/net/tools/quic/quic_spdy_server_stream.cc
+++ b/net/tools/quic/quic_spdy_server_stream.cc
@@ -32,8 +32,9 @@
 
 void QuicSpdyServerStream::OnStreamHeadersComplete(bool fin, size_t frame_len) {
   QuicSpdyStream::OnStreamHeadersComplete(fin, frame_len);
-  if (!ParseRequestHeaders(decompressed_headers().data(),
-                           decompressed_headers().length())) {
+  if (!SpdyUtils::ParseHeaders(decompressed_headers().data(),
+                               decompressed_headers().length(),
+                               &content_length_, &request_headers_)) {
     DVLOG(1) << "Invalid headers";
     SendErrorResponse();
   }
@@ -89,40 +90,6 @@
   SendResponse();
 }
 
-bool QuicSpdyServerStream::ParseRequestHeaders(const char* data,
-                                               uint32 data_len) {
-  DCHECK(headers_decompressed());
-  SpdyFramer framer(HTTP2);
-  if (!framer.ParseHeaderBlockInBuffer(data, data_len, &request_headers_) ||
-      request_headers_.empty()) {
-    return false;  // Headers were invalid.
-  }
-
-  if (ContainsKey(request_headers_, "content-length")) {
-    string delimiter;
-    delimiter.push_back('\0');
-    std::vector<string> values =
-        base::SplitString(request_headers_["content-length"], delimiter,
-                          base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
-
-    for (const string& value : values) {
-      int new_value;
-      if (!StringToInt(value, &new_value) || new_value < 0) {
-        return false;
-      }
-      if (content_length_ < 0) {
-        content_length_ = new_value;
-        continue;
-      }
-      if (new_value != content_length_) {
-        return false;
-      }
-    }
-  }
-
-  return true;
-}
-
 void QuicSpdyServerStream::SendResponse() {
   if (!ContainsKey(request_headers_, ":authority") ||
       !ContainsKey(request_headers_, ":path")) {
diff --git a/net/tools/quic/quic_spdy_server_stream.h b/net/tools/quic/quic_spdy_server_stream.h
index 2b3feee..708749ea 100644
--- a/net/tools/quic/quic_spdy_server_stream.h
+++ b/net/tools/quic/quic_spdy_server_stream.h
@@ -58,10 +58,6 @@
  private:
   friend class test::QuicSpdyServerStreamPeer;
 
-  // Parses the request headers from |data| to |request_headers_|.
-  // Returns false if there was an error parsing the headers.
-  bool ParseRequestHeaders(const char* data, uint32 data_len);
-
   // The parsed headers received from the client.
   SpdyHeaderBlock request_headers_;
   int content_length_;
diff --git a/net/tools/quic/quic_spdy_server_stream_test.cc b/net/tools/quic/quic_spdy_server_stream_test.cc
index 4798fc5d..1a3d988 100644
--- a/net/tools/quic/quic_spdy_server_stream_test.cc
+++ b/net/tools/quic/quic_spdy_server_stream_test.cc
@@ -103,7 +103,8 @@
         kInitialStreamFlowControlWindowForTest);
     session_.config()->SetInitialSessionFlowControlWindowToSend(
         kInitialSessionFlowControlWindowForTest);
-    stream_ = new QuicSpdyServerStreamPeer(5, &session_);
+    stream_ = new QuicSpdyServerStreamPeer(::net::test::kClientDataStreamId1,
+                                           &session_);
     // Register stream_ in dynamic_stream_map_ and pass ownership to session_.
     session_.ActivateStream(stream_);
 
@@ -129,23 +130,14 @@
   string body_;
 };
 
-QuicConsumedData ConsumeAllData(
-    QuicStreamId /*id*/,
-    const QuicIOVector& data,
-    QuicStreamOffset /*offset*/,
-    bool fin,
-    FecProtection /*fec_protection_*/,
-    QuicAckListenerInterface* /*ack_notifier_delegate*/) {
-  return QuicConsumedData(data.total_length, fin);
-}
-
 INSTANTIATE_TEST_CASE_P(Tests,
                         QuicSpdyServerStreamTest,
                         ::testing::ValuesIn(QuicSupportedVersions()));
 
 TEST_P(QuicSpdyServerStreamTest, TestFraming) {
-  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(AnyNumber()).
-      WillRepeatedly(Invoke(ConsumeAllData));
+  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
+      .Times(AnyNumber())
+      .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData));
   stream_->OnStreamHeaders(headers_string_);
   stream_->OnStreamHeadersComplete(false, headers_string_.size());
   stream_->OnStreamFrame(
@@ -157,8 +149,9 @@
 }
 
 TEST_P(QuicSpdyServerStreamTest, TestFramingOnePacket) {
-  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(AnyNumber()).
-      WillRepeatedly(Invoke(ConsumeAllData));
+  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
+      .Times(AnyNumber())
+      .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData));
 
   stream_->OnStreamHeaders(headers_string_);
   stream_->OnStreamHeadersComplete(false, headers_string_.size());
@@ -173,7 +166,7 @@
 TEST_P(QuicSpdyServerStreamTest, SendQuicRstStreamNoErrorInStopReading) {
   EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
       .Times(AnyNumber())
-      .WillRepeatedly(Invoke(ConsumeAllData));
+      .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData));
 
   EXPECT_FALSE(stream_->fin_received());
   EXPECT_FALSE(stream_->rst_received());
@@ -193,8 +186,9 @@
   string large_body = "hello world!!!!!!";
 
   // We'll automatically write out an error (headers + body)
-  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(AnyNumber()).
-      WillRepeatedly(Invoke(ConsumeAllData));
+  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
+      .Times(2)
+      .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData));
   EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
 
   stream_->OnStreamHeaders(headers_string_);
@@ -327,7 +321,7 @@
 
   EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
       .Times(AnyNumber())
-      .WillRepeatedly(Invoke(ConsumeAllData));
+      .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData));
   stream_->OnStreamHeaders(headers_string_);
   stream_->OnStreamHeadersComplete(true, headers_string_.size());
 
@@ -347,7 +341,7 @@
 
   EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
       .Times(AnyNumber())
-      .WillRepeatedly(Invoke(ConsumeAllData));
+      .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData));
   stream_->OnStreamHeaders(headers_string_);
   stream_->OnStreamHeadersComplete(true, headers_string_.size());
 
diff --git a/net/udp/datagram_client_socket.h b/net/udp/datagram_client_socket.h
index ac4632e..eecd7f31 100644
--- a/net/udp/datagram_client_socket.h
+++ b/net/udp/datagram_client_socket.h
@@ -25,6 +25,15 @@
   // Returns a net error code.
   virtual int BindToNetwork(NetworkChangeNotifier::NetworkHandle network) = 0;
 
+  // Same as BindToNetwork, except that the current default network is used.
+  // Returns a net error code.
+  virtual int BindToDefaultNetwork() = 0;
+
+  // Returns the network that either BindToNetwork() or BindToDefaultNetwork()
+  // bound this socket to. Returns NetworkChangeNotifier::kInvalidNetworkHandle
+  // if not explicitly bound via BindToNetwork() or BindToDefaultNetwork().
+  virtual NetworkChangeNotifier::NetworkHandle GetBoundNetwork() = 0;
+
   // Initialize this socket as a client socket to server at |address|.
   // Returns a network error code.
   virtual int Connect(const IPEndPoint& address) = 0;
diff --git a/net/udp/udp_client_socket.cc b/net/udp/udp_client_socket.cc
index a991f10b..b64643ce 100644
--- a/net/udp/udp_client_socket.cc
+++ b/net/udp/udp_client_socket.cc
@@ -13,15 +13,48 @@
                                  const RandIntCallback& rand_int_cb,
                                  net::NetLog* net_log,
                                  const net::NetLog::Source& source)
-    : socket_(bind_type, rand_int_cb, net_log, source) {
-}
+    : socket_(bind_type, rand_int_cb, net_log, source),
+      network_(NetworkChangeNotifier::kInvalidNetworkHandle) {}
 
 UDPClientSocket::~UDPClientSocket() {
 }
 
 int UDPClientSocket::BindToNetwork(
     NetworkChangeNotifier::NetworkHandle network) {
-  return socket_.BindToNetwork(network);
+  int rv = socket_.BindToNetwork(network);
+  if (rv == OK)
+    network_ = network;
+  return rv;
+}
+
+int UDPClientSocket::BindToDefaultNetwork() {
+  if (!NetworkChangeNotifier::AreNetworkHandlesSupported())
+    return ERR_NOT_IMPLEMENTED;
+  int rv;
+  // Calling connect() will bind a socket to the default network, however there
+  // is no way to determine what network the socket got bound to.  The
+  // alternative is to query what the default network is and bind the socket to
+  // that network explicitly, however this is racy because the default network
+  // can change in between when we query it and when we bind to it.  This is
+  // rare but should be accounted for.  Since changes of the default network
+  // should not come in quick succession, we can simply try again.
+  for (int attempt = 0; attempt < 2; attempt++) {
+    NetworkChangeNotifier::NetworkHandle network =
+        NetworkChangeNotifier::GetDefaultNetwork();
+    if (network == NetworkChangeNotifier::kInvalidNetworkHandle)
+      return ERR_INTERNET_DISCONNECTED;
+    rv = BindToNetwork(network);
+    // |network| may have disconnected between the call to GetDefaultNetwork()
+    // and the call to BindToNetwork(). Loop if this is the case (|rv| will be
+    // ERR_NETWORK_CHANGED).
+    if (rv != ERR_NETWORK_CHANGED)
+      return rv;
+  }
+  return rv;
+}
+
+NetworkChangeNotifier::NetworkHandle UDPClientSocket::GetBoundNetwork() {
+  return network_;
 }
 
 int UDPClientSocket::Connect(const IPEndPoint& address) {
diff --git a/net/udp/udp_client_socket.h b/net/udp/udp_client_socket.h
index 3ca62e9..b10912d95 100644
--- a/net/udp/udp_client_socket.h
+++ b/net/udp/udp_client_socket.h
@@ -27,6 +27,8 @@
 
   // DatagramClientSocket implementation.
   int BindToNetwork(NetworkChangeNotifier::NetworkHandle network) override;
+  int BindToDefaultNetwork() override;
+  NetworkChangeNotifier::NetworkHandle GetBoundNetwork() override;
   int Connect(const IPEndPoint& address) override;
   int Read(IOBuffer* buf,
            int buf_len,
@@ -49,6 +51,7 @@
 
  private:
   UDPSocket socket_;
+  NetworkChangeNotifier::NetworkHandle network_;
   DISALLOW_COPY_AND_ASSIGN(UDPClientSocket);
 };
 
diff --git a/net/udp/udp_socket_posix.cc b/net/udp/udp_socket_posix.cc
index 5151f7b..c395b88 100644
--- a/net/udp/udp_socket_posix.cc
+++ b/net/udp/udp_socket_posix.cc
@@ -326,10 +326,12 @@
 
 int UDPSocketPosix::BindToNetwork(
     NetworkChangeNotifier::NetworkHandle network) {
-#if defined(OS_ANDROID)
   DCHECK_NE(socket_, kInvalidSocket);
   DCHECK(CalledOnValidThread());
   DCHECK(!is_connected());
+  if (network == NetworkChangeNotifier::kInvalidNetworkHandle)
+    return ERR_INVALID_ARGUMENT;
+#if defined(OS_ANDROID)
   // Android prior to Lollipop didn't have support for binding sockets to
   // networks.
   if (base::android::BuildInfo::GetInstance()->sdk_int() <
@@ -353,7 +355,13 @@
   }
   if (setNetworkForSocket == nullptr)
     return ERR_NOT_IMPLEMENTED;
-  return MapSystemError(setNetworkForSocket(network, socket_));
+  int rv = setNetworkForSocket(network, socket_);
+  // If |network| has since disconnected, |rv| will be ENONET.  Surface this as
+  // ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back
+  // the less descriptive ERR_FAILED.
+  if (rv == ENONET)
+    return ERR_NETWORK_CHANGED;
+  return MapSystemError(rv);
 #else
   NOTIMPLEMENTED();
   return ERR_NOT_IMPLEMENTED;
diff --git a/net/url_request/sdch_dictionary_fetcher_unittest.cc b/net/url_request/sdch_dictionary_fetcher_unittest.cc
index 98eecaa..6acad54 100644
--- a/net/url_request/sdch_dictionary_fetcher_unittest.cc
+++ b/net/url_request/sdch_dictionary_fetcher_unittest.cc
@@ -221,12 +221,14 @@
 
   // Block until there are no outstanding URLRequestSpecifiedResponseJobs.
   void WaitForNoJobs() {
-    if (jobs_outstanding_ == 0)
-      return;
-
-    run_loop_.reset(new base::RunLoop);
-    run_loop_->Run();
-    run_loop_.reset();
+    // A job may be started after the previous one was destroyed, with a brief
+    // period of 0 jobs in between, so may have to start the run loop multiple
+    // times.
+    while (jobs_outstanding_ != 0) {
+      run_loop_.reset(new base::RunLoop);
+      run_loop_->Run();
+      run_loop_.reset();
+    }
   }
 
   HttpResponseInfo* response_info_to_return() {
diff --git a/net/url_request/url_fetcher_impl.cc b/net/url_request/url_fetcher_impl.cc
index ab14571b..02a3ae9 100644
--- a/net/url_request/url_fetcher_impl.cc
+++ b/net/url_request/url_fetcher_impl.cc
@@ -33,8 +33,8 @@
 void URLFetcherImpl::SetUploadFilePath(
     const std::string& upload_content_type,
     const base::FilePath& file_path,
-    uint64 range_offset,
-    uint64 range_length,
+    uint64_t range_offset,
+    uint64_t range_length,
     scoped_refptr<base::TaskRunner> file_task_runner) {
   core_->SetUploadFilePath(upload_content_type,
                            file_path,
diff --git a/net/url_request/url_fetcher_impl.h b/net/url_request/url_fetcher_impl.h
index 0878469..464edca 100644
--- a/net/url_request/url_fetcher_impl.h
+++ b/net/url_request/url_fetcher_impl.h
@@ -18,8 +18,7 @@
 
 #include <string>
 
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
 #include "net/base/net_export.h"
 #include "net/url_request/url_fetcher.h"
 
@@ -44,8 +43,8 @@
   void SetUploadFilePath(
       const std::string& upload_content_type,
       const base::FilePath& file_path,
-      uint64 range_offset,
-      uint64 range_length,
+      uint64_t range_offset,
+      uint64_t range_length,
       scoped_refptr<base::TaskRunner> file_task_runner) override;
   void SetUploadStreamFactory(
       const std::string& upload_content_type,
diff --git a/net/url_request/url_fetcher_impl_unittest.cc b/net/url_request/url_fetcher_impl_unittest.cc
index f9eda54a..9b0c562 100644
--- a/net/url_request/url_fetcher_impl_unittest.cc
+++ b/net/url_request/url_fetcher_impl_unittest.cc
@@ -8,6 +8,7 @@
 #include <string.h>
 
 #include <algorithm>
+#include <limits>
 #include <string>
 
 #include "base/bind.h"
@@ -118,8 +119,8 @@
   }
 
   void OnURLFetchDownloadProgress(const URLFetcher* source,
-                                  int64 current,
-                                  int64 total) override {
+                                  int64_t current,
+                                  int64_t total) override {
     // Note that the current progress may be greater than the previous progress,
     // in the case of retrying the request.
     EXPECT_FALSE(did_complete_);
@@ -133,8 +134,8 @@
   }
 
   void OnURLFetchUploadProgress(const URLFetcher* source,
-                                int64 current,
-                                int64 total) override {
+                                int64_t current,
+                                int64_t total) override {
     // Note that the current progress may be greater than the previous progress,
     // in the case of retrying the request.
     EXPECT_FALSE(did_complete_);
@@ -700,7 +701,8 @@
   delegate.CreateFetcher(test_server_->GetURL("/echo"), URLFetcher::POST,
                          CreateSameThreadContextGetter());
   delegate.fetcher()->SetUploadFilePath("application/x-www-form-urlencoded",
-                                        upload_path, 0, kuint64max,
+                                        upload_path, 0,
+                                        std::numeric_limits<uint64_t>::max(),
                                         base::ThreadTaskRunnerHandle::Get());
   delegate.StartFetcherAndWait();
 
@@ -783,8 +785,8 @@
   ~CheckUploadProgressDelegate() override {}
 
   void OnURLFetchUploadProgress(const URLFetcher* source,
-                                int64 current,
-                                int64 total) override {
+                                int64_t current,
+                                int64_t total) override {
     // Run default checks.
     WaitingURLFetcherDelegate::OnURLFetchUploadProgress(source, current, total);
 
@@ -806,12 +808,14 @@
   }
 
  private:
-  int64 bytes_appended() const { return num_chunks_appended_ * chunk_.size(); }
+  int64_t bytes_appended() const {
+    return num_chunks_appended_ * chunk_.size();
+  }
 
   const std::string chunk_;
 
-  int64 num_chunks_appended_;
-  int64 last_seen_progress_;
+  int64_t num_chunks_appended_;
+  int64_t last_seen_progress_;
 
   DISALLOW_COPY_AND_ASSIGN(CheckUploadProgressDelegate);
 };
@@ -843,13 +847,13 @@
 // that file size is correctly reported.
 class CheckDownloadProgressDelegate : public WaitingURLFetcherDelegate {
  public:
-  CheckDownloadProgressDelegate(int64 file_size)
+  CheckDownloadProgressDelegate(int64_t file_size)
       : file_size_(file_size), last_seen_progress_(0) {}
   ~CheckDownloadProgressDelegate() override {}
 
   void OnURLFetchDownloadProgress(const URLFetcher* source,
-                                  int64 current,
-                                  int64 total) override {
+                                  int64_t current,
+                                  int64_t total) override {
     // Run default checks.
     WaitingURLFetcherDelegate::OnURLFetchDownloadProgress(source, current,
                                                           total);
@@ -860,8 +864,8 @@
   }
 
  private:
-  int64 file_size_;
-  int64 last_seen_progress_;
+  int64_t file_size_;
+  int64_t last_seen_progress_;
 
   DISALLOW_COPY_AND_ASSIGN(CheckDownloadProgressDelegate);
 };
@@ -898,8 +902,8 @@
   ~CancelOnUploadProgressDelegate() override {}
 
   void OnURLFetchUploadProgress(const URLFetcher* source,
-                                int64 current,
-                                int64 total) override {
+                                int64_t current,
+                                int64_t total) override {
     CancelFetch();
   }
 
@@ -935,8 +939,8 @@
   ~CancelOnDownloadProgressDelegate() override {}
 
   void OnURLFetchDownloadProgress(const URLFetcher* source,
-                                  int64 current,
-                                  int64 total) override {
+                                  int64_t current,
+                                  int64_t total) override {
     CancelFetch();
   }
 
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index 3db47d2b2..6cd44b0 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -56,14 +56,14 @@
 // TODO(battre): Delete this, see http://crbug.com/89321:
 // This counter keeps track of the identifiers used for URL requests so far.
 // 0 is reserved to represent an invalid ID.
-uint64 g_next_url_request_identifier = 1;
+uint64_t g_next_url_request_identifier = 1;
 
 // This lock protects g_next_url_request_identifier.
 base::LazyInstance<base::Lock>::Leaky
     g_next_url_request_identifier_lock = LAZY_INSTANCE_INITIALIZER;
 
 // Returns an prior unused identifier for URL requests.
-uint64 GenerateURLRequestIdentifier() {
+uint64_t GenerateURLRequestIdentifier() {
   base::AutoLock lock(g_next_url_request_identifier_lock.Get());
   return g_next_url_request_identifier++;
 }
@@ -621,7 +621,7 @@
                  &url(), &method_, load_flags_, priority_,
                  upload_data_stream_ ? upload_data_stream_->identifier() : -1));
 
-  job_ = job;
+  job_.reset(job);
   job_->SetExtraRequestHeaders(extra_request_headers_);
   job_->SetPriority(priority_);
 
@@ -694,7 +694,7 @@
   // ~500,000 ERR_ABORTED < 100ms in Canary channel a day. Sample .01% to get
   // ~50 reports a day.
   // TODO(csharrison) Remove this code when crbug.com/557430 is resolved.
-  int64 request_time =
+  int64_t request_time =
       (base::TimeTicks::Now() - creation_time_).InMilliseconds();
   if (!has_notified_completion_ && error == ERR_ABORTED &&
       request_time <= 100 && load_flags_ & LOAD_MAIN_FRAME &&
@@ -915,7 +915,6 @@
   //   NetworkDelegate::NotifyURLRequestDestroyed notifies the NetworkDelegate
   //   that the callback becomes invalid.
   job_->Kill();
-  job_->DetachRequest();  // ensures that the job will not call us again
   job_ = NULL;
 }
 
@@ -1005,8 +1004,8 @@
   return context_;
 }
 
-int64 URLRequest::GetExpectedContentSize() const {
-  int64 expected_content_size = -1;
+int64_t URLRequest::GetExpectedContentSize() const {
+  int64_t expected_content_size = -1;
   if (job_.get())
     expected_content_size = job_->expected_content_size();
 
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index 33b28594..f1d90ed 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -12,7 +12,6 @@
 
 #include "base/debug/leak_tracker.h"
 #include "base/logging.h"
-#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "base/supports_user_data.h"
@@ -608,7 +607,7 @@
   const BoundNetLog& net_log() const { return net_log_; }
 
   // Returns the expected content size if available
-  int64 GetExpectedContentSize() const;
+  int64_t GetExpectedContentSize() const;
 
   // Returns the priority level for this request.
   RequestPriority priority() const { return priority_; }
@@ -631,14 +630,14 @@
   void set_stack_trace(const base::debug::StackTrace& stack_trace);
   const base::debug::StackTrace* stack_trace() const;
 
-  void set_received_response_content_length(int64 received_content_length) {
+  void set_received_response_content_length(int64_t received_content_length) {
     received_response_content_length_ = received_content_length;
   }
 
   // The number of bytes in the raw response body (before any decompression,
   // etc.). This is only available after the final Read completes. Not available
   // for FTP responses.
-  int64 received_response_content_length() const {
+  int64_t received_response_content_length() const {
     return received_response_content_length_;
   }
 
@@ -697,6 +696,7 @@
   // paused).
   void BeforeRequestComplete(int error);
 
+  // TODO(mmenke):  Make this take a scoped_ptr.
   void StartJob(URLRequestJob* job);
 
   // Restarting involves replacing the current job with a new one such as what
@@ -759,7 +759,7 @@
   // Tracks the time spent in various load states throughout this request.
   BoundNetLog net_log_;
 
-  scoped_refptr<URLRequestJob> job_;
+  scoped_ptr<URLRequestJob> job_;
   scoped_ptr<UploadDataStream> upload_data_stream_;
   // TODO(mmenke):  Make whether or not an upload is chunked transparent to the
   // URLRequest.
@@ -818,7 +818,7 @@
   // needs to be done outside of the URLRequest anyway. Therefore, this
   // identifier should be deleted here. http://crbug.com/89321
   // A globally unique identifier for this request.
-  const uint64 identifier_;
+  const uint64_t identifier_;
 
   // True if this request is currently calling a delegate, or is blocked waiting
   // for the URL request or network delegate to resume it.
@@ -847,7 +847,7 @@
   AuthCredentials auth_credentials_;
   scoped_refptr<AuthChallengeInfo> auth_info_;
 
-  int64 received_response_content_length_;
+  int64_t received_response_content_length_;
 
   base::TimeTicks creation_time_;
 
diff --git a/net/url_request/url_request_file_job_unittest.cc b/net/url_request/url_request_file_job_unittest.cc
index 458728cd2..17af363f 100644
--- a/net/url_request/url_request_file_job_unittest.cc
+++ b/net/url_request/url_request_file_job_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
@@ -21,62 +22,72 @@
 
 namespace {
 
-// A URLRequestFileJob for testing OnSeekComplete / OnReadComplete callbacks.
-class URLRequestFileJobWithCallbacks : public URLRequestFileJob {
+// A URLRequestFileJob for testing values passed to OnSeekComplete and
+// OnReadComplete.
+class TestURLRequestFileJob : public URLRequestFileJob {
  public:
-  URLRequestFileJobWithCallbacks(
-      URLRequest* request,
-      NetworkDelegate* network_delegate,
-      const base::FilePath& file_path,
-      const scoped_refptr<base::TaskRunner>& file_task_runner)
+  // |seek_position| will be set to the value passed in to OnSeekComplete.
+  // |observed_content| will be set to the concatenated data from all calls to
+  // OnReadComplete.
+  TestURLRequestFileJob(URLRequest* request,
+                        NetworkDelegate* network_delegate,
+                        const base::FilePath& file_path,
+                        const scoped_refptr<base::TaskRunner>& file_task_runner,
+                        int64* seek_position,
+                        std::string* observed_content)
       : URLRequestFileJob(request,
                           network_delegate,
                           file_path,
                           file_task_runner),
-        seek_position_(0) {
+        seek_position_(seek_position),
+        observed_content_(observed_content) {
+    *seek_position_ = 0;
+    observed_content_->clear();
   }
 
-  int64 seek_position() { return seek_position_; }
-  const std::vector<std::string>& data_chunks() { return data_chunks_; }
+  ~TestURLRequestFileJob() override {}
 
  protected:
-  ~URLRequestFileJobWithCallbacks() override {}
-
   void OnSeekComplete(int64 result) override {
-    ASSERT_EQ(seek_position_, 0);
-    seek_position_ = result;
+    ASSERT_EQ(*seek_position_, 0);
+    *seek_position_ = result;
   }
 
   void OnReadComplete(IOBuffer* buf, int result) override {
-    data_chunks_.push_back(std::string(buf->data(), result));
+    observed_content_->append(std::string(buf->data(), result));
   }
 
-  int64 seek_position_;
-  std::vector<std::string> data_chunks_;
+  int64* const seek_position_;
+  std::string* const observed_content_;
 };
 
-// A URLRequestJobFactory that will return URLRequestFileJobWithCallbacks
-// instances for file:// scheme URLs.
-class CallbacksJobFactory : public URLRequestJobFactory {
+// A URLRequestJobFactory that will return TestURLRequestFileJob instances for
+// file:// scheme URLs.  Can only be used to create a single job.
+class TestJobFactory : public URLRequestJobFactory {
  public:
-  class JobObserver {
-   public:
-    virtual void OnJobCreated(URLRequestFileJobWithCallbacks* job) = 0;
-  };
-
-  CallbacksJobFactory(const base::FilePath& path, JobObserver* observer)
-      : path_(path), observer_(observer) {
+  TestJobFactory(const base::FilePath& path,
+                 int64* seek_position,
+                 std::string* observed_content)
+      : path_(path),
+        seek_position_(seek_position),
+        observed_content_(observed_content) {
+    CHECK(seek_position_);
+    CHECK(observed_content_);
   }
 
-  ~CallbacksJobFactory() override {}
+  ~TestJobFactory() override {}
 
   URLRequestJob* MaybeCreateJobWithProtocolHandler(
       const std::string& scheme,
       URLRequest* request,
       NetworkDelegate* network_delegate) const override {
-    URLRequestFileJobWithCallbacks* job = new URLRequestFileJobWithCallbacks(
-        request, network_delegate, path_, base::ThreadTaskRunnerHandle::Get());
-    observer_->OnJobCreated(job);
+    CHECK(seek_position_);
+    CHECK(observed_content_);
+    URLRequestJob* job = new TestURLRequestFileJob(
+        request, network_delegate, path_, base::ThreadTaskRunnerHandle::Get(),
+        seek_position_, observed_content_);
+    seek_position_ = nullptr;
+    observed_content_ = nullptr;
     return job;
   }
 
@@ -105,8 +116,11 @@
   }
 
  private:
-  base::FilePath path_;
-  JobObserver* observer_;
+  const base::FilePath path_;
+
+  // These are mutable because MaybeCreateJobWithProtocolHandler is const.
+  mutable int64* seek_position_;
+  mutable std::string* observed_content_;
 };
 
 // Helper function to create a file in |directory| filled with
@@ -124,20 +138,6 @@
   return base::WriteFile(*path, content.c_str(), content.length());
 }
 
-class JobObserverImpl : public CallbacksJobFactory::JobObserver {
- public:
-  void OnJobCreated(URLRequestFileJobWithCallbacks* job) override {
-    jobs_.push_back(job);
-  }
-
-  typedef std::vector<scoped_refptr<URLRequestFileJobWithCallbacks> > JobList;
-
-  const JobList& jobs() { return jobs_; }
-
- protected:
-  JobList jobs_;
-};
-
 // A simple holder for start/end used in http range requests.
 struct Range {
   int start;
@@ -169,7 +169,6 @@
   // observed.
   void RunRequest(const std::string& content, const Range* range);
 
-  JobObserverImpl observer_;
   TestURLRequestContext context_;
   TestDelegate delegate_;
 };
@@ -184,7 +183,9 @@
   ASSERT_TRUE(CreateTempFileWithContent(content, directory, &path));
 
   {
-    CallbacksJobFactory factory(path, &observer_);
+    int64 seek_position;
+    std::string observed_content;
+    TestJobFactory factory(path, &seek_position, &observed_content);
     context_.set_job_factory(&factory);
 
     scoped_ptr<URLRequest> request(context_.CreateRequest(
@@ -216,17 +217,7 @@
     }
     EXPECT_TRUE(delegate_.data_received() == expected_content);
 
-    ASSERT_EQ(observer_.jobs().size(), 1u);
-    ASSERT_EQ(observer_.jobs().at(0)->seek_position(),
-              range ? range->start : 0);
-
-    std::string observed_content;
-    const std::vector<std::string>& chunks =
-        observer_.jobs().at(0)->data_chunks();
-    for (std::vector<std::string>::const_iterator i = chunks.begin();
-         i != chunks.end(); ++i) {
-      observed_content.append(*i);
-    }
+    EXPECT_EQ(seek_position, range ? range->start : 0);
     EXPECT_EQ(expected_content, observed_content);
   }
 
diff --git a/net/url_request/url_request_filter_unittest.cc b/net/url_request/url_request_filter_unittest.cc
index a7f8ca9..fc319bb 100644
--- a/net/url_request/url_request_filter_unittest.cc
+++ b/net/url_request/url_request_filter_unittest.cc
@@ -66,8 +66,8 @@
   EXPECT_TRUE(filter->AddUrlInterceptor(
       kUrl1, scoped_ptr<URLRequestInterceptor>(interceptor)));
   {
-    scoped_refptr<URLRequestJob> found =
-        filter->MaybeInterceptRequest(request1.get(), NULL);
+    scoped_ptr<URLRequestJob> found(
+        filter->MaybeInterceptRequest(request1.get(), NULL));
     EXPECT_TRUE(interceptor->WasLastJobCreated(found.get()));
   }
   EXPECT_EQ(filter->hit_count(), 1);
@@ -89,8 +89,8 @@
       kUrl1.scheme(), kUrl1.host(),
       scoped_ptr<URLRequestInterceptor>(interceptor));
   {
-    scoped_refptr<URLRequestJob> found =
-        filter->MaybeInterceptRequest(request1.get(), NULL);
+    scoped_ptr<URLRequestJob> found(
+        filter->MaybeInterceptRequest(request1.get(), NULL));
     EXPECT_TRUE(interceptor->WasLastJobCreated(found.get()));
   }
   EXPECT_EQ(1, filter->hit_count());
diff --git a/net/url_request/url_request_ftp_job_unittest.cc b/net/url_request/url_request_ftp_job_unittest.cc
index 6ee12a94..48e70522 100644
--- a/net/url_request/url_request_ftp_job_unittest.cc
+++ b/net/url_request/url_request_ftp_job_unittest.cc
@@ -128,6 +128,7 @@
                        FtpTransactionFactory* ftp_factory,
                        FtpAuthCache* ftp_auth_cache)
       : URLRequestFtpJob(request, NULL, ftp_factory, ftp_auth_cache) {}
+  ~TestURLRequestFtpJob() override {}
 
   using URLRequestFtpJob::SetPriority;
   using URLRequestFtpJob::Start;
@@ -135,7 +136,6 @@
   using URLRequestFtpJob::priority;
 
  protected:
-  ~TestURLRequestFtpJob() override {}
 };
 
 class MockFtpTransactionFactory : public FtpTransactionFactory {
@@ -172,8 +172,8 @@
 // Make sure that SetPriority actually sets the URLRequestFtpJob's
 // priority, both before and after start.
 TEST_F(URLRequestFtpJobPriorityTest, SetPriorityBasic) {
-  scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob(
-      req_.get(), &ftp_factory_, &ftp_auth_cache_));
+  scoped_ptr<TestURLRequestFtpJob> job(
+      new TestURLRequestFtpJob(req_.get(), &ftp_factory_, &ftp_auth_cache_));
   EXPECT_EQ(DEFAULT_PRIORITY, job->priority());
 
   job->SetPriority(LOWEST);
@@ -192,8 +192,8 @@
 // Make sure that URLRequestFtpJob passes on its priority to its
 // transaction on start.
 TEST_F(URLRequestFtpJobPriorityTest, SetTransactionPriorityOnStart) {
-  scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob(
-      req_.get(), &ftp_factory_, &ftp_auth_cache_));
+  scoped_ptr<TestURLRequestFtpJob> job(
+      new TestURLRequestFtpJob(req_.get(), &ftp_factory_, &ftp_auth_cache_));
   job->SetPriority(LOW);
 
   EXPECT_FALSE(network_layer_.last_transaction());
@@ -207,8 +207,8 @@
 // Make sure that URLRequestFtpJob passes on its priority updates to
 // its transaction.
 TEST_F(URLRequestFtpJobPriorityTest, SetTransactionPriority) {
-  scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob(
-      req_.get(), &ftp_factory_, &ftp_auth_cache_));
+  scoped_ptr<TestURLRequestFtpJob> job(
+      new TestURLRequestFtpJob(req_.get(), &ftp_factory_, &ftp_auth_cache_));
   job->SetPriority(LOW);
   job->Start();
   ASSERT_TRUE(network_layer_.last_transaction());
@@ -221,8 +221,8 @@
 // Make sure that URLRequestFtpJob passes on its priority updates to
 // newly-created transactions after the first one.
 TEST_F(URLRequestFtpJobPriorityTest, SetSubsequentTransactionPriority) {
-  scoped_refptr<TestURLRequestFtpJob> job(new TestURLRequestFtpJob(
-      req_.get(), &ftp_factory_, &ftp_auth_cache_));
+  scoped_ptr<TestURLRequestFtpJob> job(
+      new TestURLRequestFtpJob(req_.get(), &ftp_factory_, &ftp_auth_cache_));
   job->Start();
 
   job->SetPriority(LOW);
diff --git a/net/url_request/url_request_http_job_unittest.cc b/net/url_request/url_request_http_job_unittest.cc
index b4175ae..170be22 100644
--- a/net/url_request/url_request_http_job_unittest.cc
+++ b/net/url_request/url_request_http_job_unittest.cc
@@ -42,14 +42,12 @@
   explicit TestURLRequestHttpJob(URLRequest* request)
       : URLRequestHttpJob(request, request->context()->network_delegate(),
                           request->context()->http_user_agent_settings()) {}
+  ~TestURLRequestHttpJob() override {}
 
   using URLRequestHttpJob::SetPriority;
   using URLRequestHttpJob::Start;
   using URLRequestHttpJob::Kill;
   using URLRequestHttpJob::priority;
-
- protected:
-  ~TestURLRequestHttpJob() override {}
 };
 
 class URLRequestHttpJobTest : public ::testing::Test {
@@ -572,8 +570,7 @@
 // Make sure that SetPriority actually sets the URLRequestHttpJob's
 // priority, both before and after start.
 TEST_F(URLRequestHttpJobTest, SetPriorityBasic) {
-  scoped_refptr<TestURLRequestHttpJob> job(
-      new TestURLRequestHttpJob(req_.get()));
+  scoped_ptr<TestURLRequestHttpJob> job(new TestURLRequestHttpJob(req_.get()));
   EXPECT_EQ(DEFAULT_PRIORITY, job->priority());
 
   job->SetPriority(LOWEST);
@@ -592,8 +589,7 @@
 // Make sure that URLRequestHttpJob passes on its priority to its
 // transaction on start.
 TEST_F(URLRequestHttpJobTest, SetTransactionPriorityOnStart) {
-  scoped_refptr<TestURLRequestHttpJob> job(
-      new TestURLRequestHttpJob(req_.get()));
+  scoped_ptr<TestURLRequestHttpJob> job(new TestURLRequestHttpJob(req_.get()));
   job->SetPriority(LOW);
 
   EXPECT_FALSE(network_layer_.last_transaction());
@@ -607,8 +603,7 @@
 // Make sure that URLRequestHttpJob passes on its priority updates to
 // its transaction.
 TEST_F(URLRequestHttpJobTest, SetTransactionPriority) {
-  scoped_refptr<TestURLRequestHttpJob> job(
-      new TestURLRequestHttpJob(req_.get()));
+  scoped_ptr<TestURLRequestHttpJob> job(new TestURLRequestHttpJob(req_.get()));
   job->SetPriority(LOW);
   job->Start();
   ASSERT_TRUE(network_layer_.last_transaction());
@@ -622,8 +617,7 @@
 TEST_F(URLRequestHttpJobTest, SdchAdvertisementGet) {
   EnableSdch();
   req_->set_method("GET");  // Redundant with default.
-  scoped_refptr<TestURLRequestHttpJob> job(
-      new TestURLRequestHttpJob(req_.get()));
+  scoped_ptr<TestURLRequestHttpJob> job(new TestURLRequestHttpJob(req_.get()));
   job->Start();
   EXPECT_TRUE(TransactionAcceptsSdchEncoding());
 }
@@ -632,8 +626,7 @@
 TEST_F(URLRequestHttpJobTest, SdchAdvertisementPost) {
   EnableSdch();
   req_->set_method("POST");
-  scoped_refptr<TestURLRequestHttpJob> job(
-      new TestURLRequestHttpJob(req_.get()));
+  scoped_ptr<TestURLRequestHttpJob> job(new TestURLRequestHttpJob(req_.get()));
   job->Start();
   EXPECT_FALSE(TransactionAcceptsSdchEncoding());
 }
@@ -774,8 +767,7 @@
 };
 
 TEST_F(URLRequestHttpJobWebSocketTest, RejectedWithoutCreateHelper) {
-  scoped_refptr<TestURLRequestHttpJob> job(
-      new TestURLRequestHttpJob(req_.get()));
+  scoped_ptr<TestURLRequestHttpJob> job(new TestURLRequestHttpJob(req_.get()));
   job->Start();
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(URLRequestStatus::FAILED, req_->status().status());
@@ -783,8 +775,7 @@
 }
 
 TEST_F(URLRequestHttpJobWebSocketTest, CreateHelperPassedThrough) {
-  scoped_refptr<TestURLRequestHttpJob> job(
-      new TestURLRequestHttpJob(req_.get()));
+  scoped_ptr<TestURLRequestHttpJob> job(new TestURLRequestHttpJob(req_.get()));
   scoped_ptr<MockCreateHelper> create_helper(
       new ::testing::StrictMock<MockCreateHelper>());
   FakeWebSocketHandshakeStream* fake_handshake_stream(
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index fc9f4a96..80170d5 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -80,6 +80,12 @@
     power_monitor->AddObserver(this);
 }
 
+URLRequestJob::~URLRequestJob() {
+  base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
+  if (power_monitor)
+    power_monitor->RemoveObserver(this);
+}
+
 void URLRequestJob::SetUpload(UploadDataStream* upload) {
 }
 
@@ -91,14 +97,13 @@
 
 void URLRequestJob::Kill() {
   weak_factory_.InvalidateWeakPtrs();
-  // Make sure the request is notified that we are done.  We assume that the
-  // request took care of setting its error status before calling Kill.
-  if (request_)
-    NotifyCanceled();
-}
-
-void URLRequestJob::DetachRequest() {
-  request_ = NULL;
+  // Make sure the URLRequest is notified that the job is done.  This assumes
+  // that the URLRequest took care of setting its error status before calling
+  // Kill().
+  // TODO(mmenke):  The URLRequest is currently deleted before this method
+  // invokes its async callback whenever this is called by the URLRequest.
+  // Try to simplify how cancellation works.
+  NotifyCanceled();
 }
 
 // This function calls ReadRawData to get stream data. If a filter exists, it
@@ -262,8 +267,8 @@
   // will fail inside FollowRedirect.  The DCHECK above asserts that we called
   // OnReceivedRedirect.
 
-  // It is also possible that FollowRedirect will drop the last reference to
-  // this job, so we need to reset our members before calling it.
+  // It is also possible that FollowRedirect will delete |this|, so not safe to
+  // pass along reference to |deferred_redirect_info_|.
 
   RedirectInfo redirect_info = deferred_redirect_info_;
   deferred_redirect_info_ = RedirectInfo();
@@ -346,59 +351,35 @@
   return GURL();
 }
 
-URLRequestJob::~URLRequestJob() {
-  base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
-  if (power_monitor)
-    power_monitor->RemoveObserver(this);
-}
-
 void URLRequestJob::NotifyCertificateRequested(
     SSLCertRequestInfo* cert_request_info) {
-  if (!request_)
-    return;  // The request was destroyed, so there is no more work to do.
-
   request_->NotifyCertificateRequested(cert_request_info);
 }
 
 void URLRequestJob::NotifySSLCertificateError(const SSLInfo& ssl_info,
                                               bool fatal) {
-  if (!request_)
-    return;  // The request was destroyed, so there is no more work to do.
-
   request_->NotifySSLCertificateError(ssl_info, fatal);
 }
 
 bool URLRequestJob::CanGetCookies(const CookieList& cookie_list) const {
-  if (!request_)
-    return false;  // The request was destroyed, so there is no more work to do.
-
   return request_->CanGetCookies(cookie_list);
 }
 
 bool URLRequestJob::CanSetCookie(const std::string& cookie_line,
                                  CookieOptions* options) const {
-  if (!request_)
-    return false;  // The request was destroyed, so there is no more work to do.
-
   return request_->CanSetCookie(cookie_line, options);
 }
 
 bool URLRequestJob::CanEnablePrivacyMode() const {
-  if (!request_)
-    return false;  // The request was destroyed, so there is no more work to do.
-
   return request_->CanEnablePrivacyMode();
 }
 
 void URLRequestJob::NotifyBeforeNetworkStart(bool* defer) {
-  if (!request_)
-    return;
-
   request_->NotifyBeforeNetworkStart(defer);
 }
 
 void URLRequestJob::NotifyHeadersComplete() {
-  if (!request_ || !request_->has_delegate())
+  if (!request_->has_delegate())
     return;  // The request was destroyed, so there is no more work to do.
 
   if (has_handled_response_)
@@ -416,17 +397,8 @@
   request_->response_info_.response_time = base::Time::Now();
   GetResponseInfo(&request_->response_info_);
 
-  // When notifying the delegate, the delegate can release the request
-  // (and thus release 'this').  After calling to the delgate, we must
-  // check the request pointer to see if it still exists, and return
-  // immediately if it has been destroyed.  self_preservation ensures our
-  // survival until we can get out of this method.
-  scoped_refptr<URLRequestJob> self_preservation(this);
-
   MaybeNotifyNetworkBytes();
-
-  if (request_)
-    request_->OnHeadersComplete();
+  request_->OnHeadersComplete();
 
   GURL new_location;
   int http_status_code;
@@ -435,6 +407,12 @@
     // so it does not treat being stopped as an error.
     DoneReadingRedirectResponse();
 
+    // When notifying the URLRequest::Delegate, it can destroy the request,
+    // which will destroy |this|.  After calling to the URLRequest::Delegate,
+    // pointer must be checked to see if |this| still exists, and if not, the
+    // code must return immediately.
+    base::WeakPtr<URLRequestJob> weak_this(weak_factory_.GetWeakPtr());
+
     RedirectInfo redirect_info =
         ComputeRedirectInfo(new_location, http_status_code);
     bool defer_redirect = false;
@@ -442,7 +420,7 @@
 
     // Ensure that the request wasn't detached, destroyed, or canceled in
     // NotifyReceivedRedirect.
-    if (!request_ || !request_->has_delegate() ||
+    if (!weak_this || !request_->has_delegate() ||
         !request_->status().is_success()) {
       return;
     }
@@ -484,6 +462,8 @@
   }
 
   request_->NotifyResponseStarted();
+
+  // |this| may be destroyed at this point.
 }
 
 void URLRequestJob::ConvertResultToError(int result, Error* error, int* count) {
@@ -502,7 +482,7 @@
       FROM_HERE_WITH_EXPLICIT_FUNCTION(
           "475755 URLRequestJob::RawReadCompleted"));
 
-  if (!request_ || !request_->has_delegate())
+  if (!request_->has_delegate())
     return;  // The request was destroyed, so there is no more work to do.
 
   // TODO(darin): Bug 1004233. Re-enable this test once all of the chrome
@@ -547,44 +527,37 @@
       DoneReading();
 
     DVLOG(1) << __FUNCTION__ << "() "
-             << "\"" << (request_ ? request_->url().spec() : "???") << "\""
+             << "\"" << request_->url().spec() << "\""
              << " pre bytes read = " << bytes_read
              << " pre total = " << prefilter_bytes_read_
              << " post total = " << postfilter_bytes_read_;
     bytes_read = filter_bytes_read;
   } else {
     DVLOG(1) << __FUNCTION__ << "() "
-             << "\"" << (request_ ? request_->url().spec() : "???") << "\""
+             << "\"" << request_->url().spec() << "\""
              << " pre bytes read = " << bytes_read
              << " pre total = " << prefilter_bytes_read_
              << " post total = " << postfilter_bytes_read_;
   }
 
-  // When notifying the delegate, the delegate can release the request
-  // (and thus release 'this').  After calling to the delegate, we must
-  // check the request pointer to see if it still exists, and return
-  // immediately if it has been destroyed.  self_preservation ensures our
-  // survival until we can get out of this method.
-  scoped_refptr<URLRequestJob> self_preservation(this);
-
   // NotifyReadCompleted should be called after SetStatus or NotifyDone updates
   // the status.
   if (error == OK)
     request_->NotifyReadCompleted(bytes_read);
+
+  // |this| may be destroyed at this point.
 }
 
 void URLRequestJob::NotifyStartError(const URLRequestStatus &status) {
   DCHECK(!has_handled_response_);
   has_handled_response_ = true;
-  if (request_) {
-    // There may be relevant information in the response info even in the
-    // error case.
-    GetResponseInfo(&request_->response_info_);
+  // There may be relevant information in the response info even in the
+  // error case.
+  GetResponseInfo(&request_->response_info_);
 
-    request_->set_status(status);
-    request_->NotifyResponseStarted();
-    // We may have been deleted.
-  }
+  request_->set_status(status);
+  request_->NotifyResponseStarted();
+  // |this| may have been deleted here.
 }
 
 void URLRequestJob::NotifyDone(const URLRequestStatus &status) {
@@ -597,39 +570,35 @@
   // the response before getting here.
   DCHECK(has_handled_response_ || !status.is_success());
 
-  // As with RawReadCompleted, we need to take care to notice if we were
-  // destroyed during a delegate callback.
-  if (request_) {
-    request_->set_is_pending(false);
-    // With async IO, it's quite possible to have a few outstanding
-    // requests.  We could receive a request to Cancel, followed shortly
-    // by a successful IO.  For tracking the status(), once there is
-    // an error, we do not change the status back to success.  To
-    // enforce this, only set the status if the job is so far
-    // successful.
-    if (request_->status().is_success()) {
-      if (status.status() == URLRequestStatus::FAILED) {
-        request_->net_log().AddEventWithNetErrorCode(NetLog::TYPE_FAILED,
-                                                     status.error());
-      }
-      request_->set_status(status);
+  request_->set_is_pending(false);
+  // With async IO, it's quite possible to have a few outstanding
+  // requests.  We could receive a request to Cancel, followed shortly
+  // by a successful IO.  For tracking the status(), once there is
+  // an error, we do not change the status back to success.  To
+  // enforce this, only set the status if the job is so far
+  // successful.
+  if (request_->status().is_success()) {
+    if (status.status() == URLRequestStatus::FAILED) {
+      request_->net_log().AddEventWithNetErrorCode(NetLog::TYPE_FAILED,
+                                                   status.error());
     }
+    request_->set_status(status);
+  }
 
-    // If the request succeeded (And wasn't cancelled) and the response code was
-    // 4xx or 5xx, record whether or not the main frame was blank.  This is
-    // intended to be a short-lived histogram, used to figure out how important
-    // fixing http://crbug.com/331745 is.
-    if (request_->status().is_success()) {
-      int response_code = GetResponseCode();
-      if (400 <= response_code && response_code <= 599) {
-        bool page_has_content = (postfilter_bytes_read_ != 0);
-        if (request_->load_flags() & net::LOAD_MAIN_FRAME) {
-          UMA_HISTOGRAM_BOOLEAN("Net.ErrorResponseHasContentMainFrame",
-                                page_has_content);
-        } else {
-          UMA_HISTOGRAM_BOOLEAN("Net.ErrorResponseHasContentNonMainFrame",
-                                page_has_content);
-        }
+  // If the request succeeded (And wasn't cancelled) and the response code was
+  // 4xx or 5xx, record whether or not the main frame was blank.  This is
+  // intended to be a short-lived histogram, used to figure out how important
+  // fixing http://crbug.com/331745 is.
+  if (request_->status().is_success()) {
+    int response_code = GetResponseCode();
+    if (400 <= response_code && response_code <= 599) {
+      bool page_has_content = (postfilter_bytes_read_ != 0);
+      if (request_->load_flags() & net::LOAD_MAIN_FRAME) {
+        UMA_HISTOGRAM_BOOLEAN("Net.ErrorResponseHasContentMainFrame",
+                              page_has_content);
+      } else {
+        UMA_HISTOGRAM_BOOLEAN("Net.ErrorResponseHasContentNonMainFrame",
+                              page_has_content);
       }
     }
   }
@@ -645,9 +614,7 @@
 
 void URLRequestJob::CompleteNotifyDone() {
   // Check if we should notify the delegate that we're done because of an error.
-  if (request_ &&
-      !request_->status().is_success() &&
-      request_->has_delegate()) {
+  if (!request_->status().is_success() && request_->has_delegate()) {
     // We report the error differently depending on whether we've called
     // OnResponseStarted yet.
     if (has_handled_response_) {
@@ -773,8 +740,8 @@
         }
         case Filter::FILTER_ERROR: {
           DVLOG(1) << __FUNCTION__ << "() "
-                   << "\"" << (request_ ? request_->url().spec() : "???")
-                   << "\"" << " Filter Error";
+                   << "\"" << request_->url().spec() << "\""
+                   << " Filter Error";
           filter_needs_more_output_space_ = false;
           error = ERR_CONTENT_DECODING_FAILED;
           break;
@@ -788,7 +755,7 @@
       }
 
       // If logging all bytes is enabled, log the filtered bytes read.
-      if (error == OK && request() && filtered_data_len > 0 &&
+      if (error == OK && filtered_data_len > 0 &&
           request()->net_log().IsCapturing()) {
         request()->net_log().AddByteTransferEvent(
             NetLog::TYPE_URL_REQUEST_JOB_FILTERED_BYTES_READ, filtered_data_len,
@@ -815,25 +782,18 @@
 }
 
 const URLRequestStatus URLRequestJob::GetStatus() {
-  if (request_)
-    return request_->status();
-  // If the request is gone, we must be cancelled.
-  return URLRequestStatus(URLRequestStatus::CANCELED,
-                          ERR_ABORTED);
+  return request_->status();
 }
 
 void URLRequestJob::SetStatus(const URLRequestStatus &status) {
-  if (request_) {
-    // An error status should never be replaced by a non-error status by a
-    // URLRequestJob.  URLRequest has some retry paths, but it resets the status
-    // itself, if needed.
-    // TODO(mmenke): Change this to a DCHECK once https://crbug.com/508900 is
-    // resolved.
-    CHECK(request_->status().is_io_pending() ||
-          request_->status().is_success() ||
-          (!status.is_success() && !status.is_io_pending()));
-    request_->set_status(status);
-  }
+  // An error status should never be replaced by a non-error status by a
+  // URLRequestJob.  URLRequest has some retry paths, but it resets the status
+  // itself, if needed.
+  // TODO(mmenke): Change this to a DCHECK once https://crbug.com/508900 is
+  // resolved.
+  CHECK(request_->status().is_io_pending() || request_->status().is_success() ||
+        (!status.is_success() && !status.is_io_pending()));
+  request_->set_status(status);
 }
 
 void URLRequestJob::SetProxyServer(const HostPortPair& proxy_server) {
@@ -893,8 +853,7 @@
   }
   // If |filter_| is non-NULL, bytes will be logged after it is applied
   // instead.
-  if (!filter_.get() && request() && bytes_read > 0 &&
-      request()->net_log().IsCapturing()) {
+  if (!filter_.get() && bytes_read > 0 && request()->net_log().IsCapturing()) {
     request()->net_log().AddByteTransferEvent(
         NetLog::TYPE_URL_REQUEST_JOB_BYTES_READ, bytes_read,
         raw_read_buffer_->data());
@@ -917,7 +876,7 @@
   // If prefilter_bytes_read_ is equal to bytes_read, it indicates this is the
   // first raw read of the response body. This is used as the signal that
   // response headers have been received.
-  if (request_ && request_->context()->network_quality_estimator() &&
+  if (request_->context()->network_quality_estimator() &&
       prefilter_bytes_read_ == bytes_read) {
     request_->context()->network_quality_estimator()->NotifyHeadersReceived(
         *request_);
@@ -926,7 +885,7 @@
   if (!filter_.get())
     postfilter_bytes_read_ += bytes_read;
   DVLOG(2) << __FUNCTION__ << "() "
-           << "\"" << (request_ ? request_->url().spec() : "???") << "\""
+           << "\"" << request_->url().spec() << "\""
            << " pre bytes read = " << bytes_read
            << " pre total = " << prefilter_bytes_read_
            << " post total = " << postfilter_bytes_read_;
@@ -992,7 +951,7 @@
 }
 
 void URLRequestJob::MaybeNotifyNetworkBytes() {
-  if (!request_ || !network_delegate_)
+  if (!network_delegate_)
     return;
 
   // Report any new received bytes.
diff --git a/net/url_request/url_request_job.h b/net/url_request/url_request_job.h
index 79eea582..d53a8493 100644
--- a/net/url_request/url_request_job.h
+++ b/net/url_request/url_request_job.h
@@ -10,7 +10,7 @@
 #include <string>
 #include <vector>
 
-#include "base/memory/ref_counted.h"
+#include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
@@ -45,15 +45,13 @@
 class URLRequestStatus;
 class X509Certificate;
 
-class NET_EXPORT URLRequestJob
-    : public base::RefCounted<URLRequestJob>,
-      public base::PowerObserver {
+class NET_EXPORT URLRequestJob : public base::PowerObserver {
  public:
   explicit URLRequestJob(URLRequest* request,
                          NetworkDelegate* network_delegate);
+  ~URLRequestJob() override;
 
-  // Returns the request that owns this job. THIS POINTER MAY BE NULL if the
-  // request was destroyed.
+  // Returns the request that owns this job.
   URLRequest* request() const {
     return request_;
   }
@@ -97,10 +95,6 @@
   // one notification must be issued.
   virtual void Kill();
 
-  // Called to detach the request from this Job.  Results in the Job being
-  // killed off eventually. The job must not use the request pointer any more.
-  void DetachRequest();
-
   // Called to read post-filtered data from this Job, returning the number of
   // bytes read, 0 when there is no more data, or -1 if there was an error.
   // This is just the backend for URLRequest::Read, see that function for
@@ -258,9 +252,6 @@
                                          const GURL& redirect_destination);
 
  protected:
-  friend class base::RefCounted<URLRequestJob>;
-  ~URLRequestJob() override;
-
   // Notifies the job that a certificate is requested.
   void NotifyCertificateRequested(SSLCertRequestInfo* cert_request_info);
 
@@ -371,8 +362,7 @@
   // bytes read, or < 0 to indicate an error.
   void ReadRawDataComplete(int bytes_read);
 
-  // The request that initiated this job. This value MAY BE NULL if the
-  // request was released by DetachRequest().
+  // The request that initiated this job. This value will never be nullptr.
   URLRequest* request_;
 
  private:
diff --git a/net/url_request/url_request_redirect_job.cc b/net/url_request/url_request_redirect_job.cc
index 1dfb56dc..5d3fbdb9 100644
--- a/net/url_request/url_request_redirect_job.cc
+++ b/net/url_request/url_request_redirect_job.cc
@@ -36,6 +36,8 @@
   DCHECK(!redirect_reason_.empty());
 }
 
+URLRequestRedirectJob::~URLRequestRedirectJob() {}
+
 void URLRequestRedirectJob::GetResponseInfo(HttpResponseInfo* info) {
   // Should only be called after the URLRequest has been notified there's header
   // information.
@@ -83,8 +85,6 @@
   return response_code_;
 }
 
-URLRequestRedirectJob::~URLRequestRedirectJob() {}
-
 void URLRequestRedirectJob::StartAsync() {
   DCHECK(request_);
   DCHECK(request_->status().is_success());
diff --git a/net/url_request/url_request_redirect_job.h b/net/url_request/url_request_redirect_job.h
index c84759fc..a671844 100644
--- a/net/url_request/url_request_redirect_job.h
+++ b/net/url_request/url_request_redirect_job.h
@@ -41,6 +41,8 @@
                         ResponseCode response_code,
                         const std::string& redirect_reason);
 
+  ~URLRequestRedirectJob() override;
+
   // URLRequestJob implementation:
   void GetResponseInfo(HttpResponseInfo* info) override;
   void GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
@@ -50,8 +52,6 @@
   int GetResponseCode() const override;
 
  private:
-  ~URLRequestRedirectJob() override;
-
   void StartAsync();
 
   const GURL redirect_destination_;
diff --git a/net/url_request/url_request_test_job.h b/net/url_request/url_request_test_job.h
index eb1db01..4a6cab2 100644
--- a/net/url_request/url_request_test_job.h
+++ b/net/url_request/url_request_test_job.h
@@ -58,6 +58,8 @@
                     const std::string& response_data,
                     bool auto_advance);
 
+  ~URLRequestTestJob() override;
+
   // The canned URLs this handler will respond to without having been
   // explicitly initialized with response headers and data.
   // FIXME(brettw): we should probably also have a redirect one
@@ -130,8 +132,6 @@
   // When the stage is DONE, this job will not be put on the queue.
   enum Stage { WAITING, DATA_AVAILABLE, ALL_DATA, DONE };
 
-  ~URLRequestTestJob() override;
-
   // Call to process the next opeation, usually sending a notification, and
   // advancing the stage if necessary. THIS MAY DELETE THE OBJECT.
   void ProcessNextOperation();
diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc
index 3bd6ece3..317ee749 100644
--- a/net/url_request/url_request_test_util.cc
+++ b/net/url_request/url_request_test_util.cc
@@ -22,6 +22,7 @@
 #include "net/ssl/channel_id_service.h"
 #include "net/ssl/default_channel_id_store.h"
 #include "net/url_request/static_http_user_agent_settings.h"
+#include "net/url_request/url_request_job.h"
 #include "net/url_request/url_request_job_factory_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -637,19 +638,18 @@
   return cancel_request_with_policy_violating_referrer_;
 }
 
-TestJobInterceptor::TestJobInterceptor() : main_intercept_job_(NULL) {
-}
+TestJobInterceptor::TestJobInterceptor() {}
+
+TestJobInterceptor::~TestJobInterceptor() {}
 
 URLRequestJob* TestJobInterceptor::MaybeCreateJob(
     URLRequest* request,
     NetworkDelegate* network_delegate) const {
-  URLRequestJob* job = main_intercept_job_;
-  main_intercept_job_ = NULL;
-  return job;
+  return main_intercept_job_.release();
 }
 
-void TestJobInterceptor::set_main_intercept_job(URLRequestJob* job) {
-  main_intercept_job_ = job;
+void TestJobInterceptor::set_main_intercept_job(scoped_ptr<URLRequestJob> job) {
+  main_intercept_job_ = std::move(job);
 }
 
 }  // namespace net
diff --git a/net/url_request/url_request_test_util.h b/net/url_request/url_request_test_util.h
index 3369c881..819421dad 100644
--- a/net/url_request/url_request_test_util.h
+++ b/net/url_request/url_request_test_util.h
@@ -398,14 +398,15 @@
 class TestJobInterceptor : public URLRequestJobFactory::ProtocolHandler {
  public:
   TestJobInterceptor();
+  ~TestJobInterceptor() override;
 
   URLRequestJob* MaybeCreateJob(
       URLRequest* request,
       NetworkDelegate* network_delegate) const override;
-  void set_main_intercept_job(URLRequestJob* job);
+  void set_main_intercept_job(scoped_ptr<URLRequestJob> job);
 
  private:
-  mutable URLRequestJob* main_intercept_job_;
+  mutable scoped_ptr<URLRequestJob> main_intercept_job_;
 };
 
 }  // namespace net
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 6567c6d..b9e1ecac6 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -12,8 +12,8 @@
 #include <stdint.h>
 
 #include <algorithm>
+#include <limits>
 
-#include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/compiler_specific.h"
 #include "base/files/file_path.h"
@@ -282,6 +282,27 @@
   DISALLOW_COPY_AND_ASSIGN(TestPowerMonitorSource);
 };
 
+// Job that allows monitoring of its priority.
+class PriorityMonitoringURLRequestJob : public URLRequestTestJob {
+ public:
+  // The latest priority of the job is always written to |request_priority_|.
+  PriorityMonitoringURLRequestJob(URLRequest* request,
+                                  NetworkDelegate* network_delegate,
+                                  RequestPriority* request_priority)
+      : URLRequestTestJob(request, network_delegate),
+        request_priority_(request_priority) {
+    *request_priority_ = DEFAULT_PRIORITY;
+  }
+
+  void SetPriority(RequestPriority priority) override {
+    *request_priority_ = priority;
+    URLRequestTestJob::SetPriority(priority);
+  }
+
+ private:
+  RequestPriority* const request_priority_;
+};
+
 // Do a case-insensitive search through |haystack| for |needle|.
 bool ContainsString(const std::string& haystack, const char* needle) {
   std::string::const_iterator it = std::search(
@@ -302,8 +323,8 @@
   EXPECT_GT(ssl_info.security_bits, 0);
 
   // The cipher suite TLS_NULL_WITH_NULL_NULL (0) must not be negotiated.
-  uint16 cipher_suite = SSLConnectionStatusToCipherSuite(
-      ssl_info.connection_status);
+  uint16_t cipher_suite =
+      SSLConnectionStatusToCipherSuite(ssl_info.connection_status);
   EXPECT_NE(0U, cipher_suite);
 }
 
@@ -814,7 +835,7 @@
 
     base::RunLoop().Run();
 
-    int64 file_size = -1;
+    int64_t file_size = -1;
     EXPECT_TRUE(base::GetFileSize(app_path, &file_size));
 
     EXPECT_TRUE(!r->is_pending());
@@ -858,7 +879,7 @@
   GURL temp_url = FilePathToFileURL(temp_path);
   EXPECT_TRUE(base::WriteFile(temp_path, buffer.get(), buffer_size));
 
-  int64 file_size;
+  int64_t file_size;
   EXPECT_TRUE(base::GetFileSize(temp_path, &file_size));
 
   const size_t first_byte_position = 500;
@@ -903,7 +924,7 @@
   GURL temp_url = FilePathToFileURL(temp_path);
   EXPECT_TRUE(base::WriteFile(temp_path, buffer.get(), buffer_size));
 
-  int64 file_size;
+  int64_t file_size;
   EXPECT_TRUE(base::GetFileSize(temp_path, &file_size));
 
   const size_t first_byte_position = 500;
@@ -947,7 +968,7 @@
   GURL temp_url = FilePathToFileURL(temp_path);
   EXPECT_TRUE(base::WriteFile(temp_path, buffer.get(), buffer_size));
 
-  int64 file_size;
+  int64_t file_size;
   EXPECT_TRUE(base::GetFileSize(temp_path, &file_size));
 
   TestDelegate d;
@@ -2141,15 +2162,16 @@
       GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d));
   EXPECT_EQ(DEFAULT_PRIORITY, req->priority());
 
-  scoped_refptr<URLRequestTestJob> job =
-      new URLRequestTestJob(req.get(), &default_network_delegate_);
-  AddTestInterceptor()->set_main_intercept_job(job.get());
-  EXPECT_EQ(DEFAULT_PRIORITY, job->priority());
+  RequestPriority job_priority;
+  scoped_ptr<URLRequestJob> job(new PriorityMonitoringURLRequestJob(
+      req.get(), &default_network_delegate_, &job_priority));
+  AddTestInterceptor()->set_main_intercept_job(std::move(job));
+  EXPECT_EQ(DEFAULT_PRIORITY, job_priority);
 
   req->SetPriority(LOW);
 
   req->Start();
-  EXPECT_EQ(LOW, job->priority());
+  EXPECT_EQ(LOW, job_priority);
 }
 
 // Make sure that URLRequest passes on its priority updates to its
@@ -2159,17 +2181,18 @@
   scoped_ptr<URLRequest> req(default_context_.CreateRequest(
       GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d));
 
-  scoped_refptr<URLRequestTestJob> job =
-      new URLRequestTestJob(req.get(), &default_network_delegate_);
-  AddTestInterceptor()->set_main_intercept_job(job.get());
+  RequestPriority job_priority;
+  scoped_ptr<URLRequestJob> job(new PriorityMonitoringURLRequestJob(
+      req.get(), &default_network_delegate_, &job_priority));
+  AddTestInterceptor()->set_main_intercept_job(std::move(job));
 
   req->SetPriority(LOW);
   req->Start();
-  EXPECT_EQ(LOW, job->priority());
+  EXPECT_EQ(LOW, job_priority);
 
   req->SetPriority(MEDIUM);
   EXPECT_EQ(MEDIUM, req->priority());
-  EXPECT_EQ(MEDIUM, job->priority());
+  EXPECT_EQ(MEDIUM, job_priority);
 }
 
 // Setting the IGNORE_LIMITS load flag should be okay if the priority
@@ -2180,9 +2203,10 @@
       GURL("http://test_intercept/foo"), MAXIMUM_PRIORITY, &d));
   EXPECT_EQ(MAXIMUM_PRIORITY, req->priority());
 
-  scoped_refptr<URLRequestTestJob> job =
-      new URLRequestTestJob(req.get(), &default_network_delegate_);
-  AddTestInterceptor()->set_main_intercept_job(job.get());
+  RequestPriority job_priority;
+  scoped_ptr<URLRequestJob> job(new PriorityMonitoringURLRequestJob(
+      req.get(), &default_network_delegate_, &job_priority));
+  AddTestInterceptor()->set_main_intercept_job(std::move(job));
 
   req->SetLoadFlags(LOAD_IGNORE_LIMITS);
   EXPECT_EQ(MAXIMUM_PRIORITY, req->priority());
@@ -2192,7 +2216,7 @@
 
   req->Start();
   EXPECT_EQ(MAXIMUM_PRIORITY, req->priority());
-  EXPECT_EQ(MAXIMUM_PRIORITY, job->priority());
+  EXPECT_EQ(MAXIMUM_PRIORITY, job_priority);
 }
 
 namespace {
@@ -5554,9 +5578,9 @@
     PathService::Get(base::DIR_SOURCE_ROOT, &path);
     path = path.Append(kTestFilePath);
     path = path.Append(FILE_PATH_LITERAL("with-headers.html"));
-    element_readers.push_back(make_scoped_ptr(
-        new UploadFileElementReader(base::ThreadTaskRunnerHandle::Get().get(),
-                                    path, 0, kuint64max, base::Time())));
+    element_readers.push_back(make_scoped_ptr(new UploadFileElementReader(
+        base::ThreadTaskRunnerHandle::Get().get(), path, 0,
+        std::numeric_limits<uint64_t>::max(), base::Time())));
     r->set_upload(make_scoped_ptr<UploadDataStream>(
         new ElementsUploadDataStream(std::move(element_readers), 0)));
 
@@ -5565,7 +5589,7 @@
 
     base::RunLoop().Run();
 
-    int64 size64 = 0;
+    int64_t size64 = 0;
     ASSERT_EQ(true, base::GetFileSize(path, &size64));
     ASSERT_LE(size64, std::numeric_limits<int>::max());
     int size = static_cast<int>(size64);
@@ -5599,7 +5623,7 @@
         base::ThreadTaskRunnerHandle::Get().get(),
         base::FilePath(FILE_PATH_LITERAL(
             "c:\\path\\to\\non\\existant\\file.randomness.12345")),
-        0, kuint64max, base::Time())));
+        0, std::numeric_limits<uint64_t>::max(), base::Time())));
     r->set_upload(make_scoped_ptr<UploadDataStream>(
         new ElementsUploadDataStream(std::move(element_readers), 0)));
 
@@ -6442,10 +6466,10 @@
   scoped_ptr<URLRequest> r(
       default_context_.CreateRequest(original_url, DEFAULT_PRIORITY, &d));
 
-  URLRequestRedirectJob* job = new URLRequestRedirectJob(
+  scoped_ptr<URLRequestRedirectJob> job(new URLRequestRedirectJob(
       r.get(), &default_network_delegate_, redirect_url,
-      URLRequestRedirectJob::REDIRECT_302_FOUND, "Very Good Reason");
-  AddTestInterceptor()->set_main_intercept_job(job);
+      URLRequestRedirectJob::REDIRECT_302_FOUND, "Very Good Reason"));
+  AddTestInterceptor()->set_main_intercept_job(std::move(job));
 
   r->Start();
   base::RunLoop().Run();
@@ -7169,11 +7193,11 @@
                     base::SizeTToString(arraysize(kData) - 1));
   req->SetExtraRequestHeaders(headers);
 
-  URLRequestRedirectJob* job = new URLRequestRedirectJob(
+  scoped_ptr<URLRequestRedirectJob> job(new URLRequestRedirectJob(
       req.get(), &default_network_delegate_,
       http_test_server()->GetURL("/echo"),
-      URLRequestRedirectJob::REDIRECT_302_FOUND, "Very Good Reason");
-  AddTestInterceptor()->set_main_intercept_job(job);
+      URLRequestRedirectJob::REDIRECT_302_FOUND, "Very Good Reason"));
+  AddTestInterceptor()->set_main_intercept_job(std::move(job));
 
   req->Start();
   base::RunLoop().Run();
@@ -7195,12 +7219,12 @@
                     base::SizeTToString(arraysize(kData) - 1));
   req->SetExtraRequestHeaders(headers);
 
-  URLRequestRedirectJob* job = new URLRequestRedirectJob(
+  scoped_ptr<URLRequestRedirectJob> job(new URLRequestRedirectJob(
       req.get(), &default_network_delegate_,
       http_test_server()->GetURL("/echo"),
       URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT,
-      "Very Good Reason");
-  AddTestInterceptor()->set_main_intercept_job(job);
+      "Very Good Reason"));
+  AddTestInterceptor()->set_main_intercept_job(std::move(job));
 
   req->Start();
   base::RunLoop().Run();
@@ -7396,23 +7420,24 @@
       http_test_server()->GetURL("/defaultresponse"), DEFAULT_PRIORITY, &d));
   EXPECT_EQ(DEFAULT_PRIORITY, req->priority());
 
-  scoped_refptr<URLRequestRedirectJob> redirect_job = new URLRequestRedirectJob(
+  scoped_ptr<URLRequestRedirectJob> redirect_job(new URLRequestRedirectJob(
       req.get(), &default_network_delegate_,
       http_test_server()->GetURL("/echo"),
-      URLRequestRedirectJob::REDIRECT_302_FOUND, "Very Good Reason");
-  AddTestInterceptor()->set_main_intercept_job(redirect_job.get());
+      URLRequestRedirectJob::REDIRECT_302_FOUND, "Very Good Reason"));
+  AddTestInterceptor()->set_main_intercept_job(std::move(redirect_job));
 
   req->SetPriority(LOW);
   req->Start();
   EXPECT_TRUE(req->is_pending());
 
-  scoped_refptr<URLRequestTestJob> job =
-      new URLRequestTestJob(req.get(), &default_network_delegate_);
-  AddTestInterceptor()->set_main_intercept_job(job.get());
+  RequestPriority job_priority;
+  scoped_ptr<URLRequestJob> job(new PriorityMonitoringURLRequestJob(
+      req.get(), &default_network_delegate_, &job_priority));
+  AddTestInterceptor()->set_main_intercept_job(std::move(job));
 
   // Should trigger |job| to be started.
   base::RunLoop().Run();
-  EXPECT_EQ(LOW, job->priority());
+  EXPECT_EQ(LOW, job_priority);
 }
 
 // Check that creating a network request while entering/exiting suspend mode
@@ -8536,11 +8561,9 @@
         min_version_(kDefaultSSLVersionMin),
         fallback_min_version_(kDefaultSSLVersionFallbackMin) {}
 
-  void set_min_version(uint16 version) {
-    min_version_ = version;
-  }
+  void set_min_version(uint16_t version) { min_version_ = version; }
 
-  void set_fallback_min_version(uint16 version) {
+  void set_fallback_min_version(uint16_t version) {
     fallback_min_version_ = version;
   }
 
@@ -8566,8 +8589,8 @@
   const bool ev_enabled_;
   const bool online_rev_checking_;
   const bool rev_checking_required_local_anchors_;
-  uint16 min_version_;
-  uint16 fallback_min_version_;
+  uint16_t min_version_;
+  uint16_t fallback_min_version_;
 };
 
 class FallbackTestURLRequestContext : public TestURLRequestContext {
@@ -8575,7 +8598,7 @@
   explicit FallbackTestURLRequestContext(bool delay_initialization)
       : TestURLRequestContext(delay_initialization) {}
 
-  void set_fallback_min_version(uint16 version) {
+  void set_fallback_min_version(uint16_t version) {
     TestSSLConfigService *ssl_config_service =
         new TestSSLConfigService(true /* check for EV */,
                                  false /* online revocation checking */,
@@ -8610,7 +8633,7 @@
     base::RunLoop().Run();
   }
 
-  void set_fallback_min_version(uint16 version) {
+  void set_fallback_min_version(uint16_t version) {
     context_.set_fallback_min_version(version);
   }
 
@@ -9783,23 +9806,21 @@
   EXPECT_TRUE(req->response_info().network_accessed);
 }
 
-// Test that URLRequest is canceled correctly and with detached request
-// URLRequestRedirectJob does not crash in StartAsync.
+// Test that URLRequest is canceled correctly.
 // See http://crbug.com/508900
-TEST_F(URLRequestTest, URLRequestRedirectJobDetachRequestNoCrash) {
+TEST_F(URLRequestTest, URLRequestRedirectJobCancelRequest) {
   TestDelegate d;
   scoped_ptr<URLRequest> req(default_context_.CreateRequest(
       GURL("http://not-a-real-domain/"), DEFAULT_PRIORITY, &d));
 
-  URLRequestRedirectJob* job = new URLRequestRedirectJob(
+  scoped_ptr<URLRequestRedirectJob> job(new URLRequestRedirectJob(
       req.get(), &default_network_delegate_,
       GURL("http://this-should-never-be-navigated-to/"),
-      URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT, "Jumbo shrimp");
-  AddTestInterceptor()->set_main_intercept_job(job);
+      URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT, "Jumbo shrimp"));
+  AddTestInterceptor()->set_main_intercept_job(std::move(job));
 
   req->Start();
   req->Cancel();
-  job->DetachRequest();
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
   EXPECT_EQ(0, d.received_redirect_count());
diff --git a/pdf/chunk_stream.cc b/pdf/chunk_stream.cc
index 7ac8f974..e580151 100644
--- a/pdf/chunk_stream.cc
+++ b/pdf/chunk_stream.cc
@@ -17,7 +17,7 @@
 
 namespace chrome_pdf {
 
-ChunkStream::ChunkStream() {
+ChunkStream::ChunkStream() : stream_size_(0) {
 }
 
 ChunkStream::~ChunkStream() {
@@ -26,10 +26,12 @@
 void ChunkStream::Clear() {
   chunks_.clear();
   data_.clear();
+  stream_size_ = 0;
 }
 
 void ChunkStream::Preallocate(size_t stream_size) {
   data_.reserve(stream_size);
+  stream_size_ = stream_size;
 }
 
 size_t ChunkStream::GetSize() {
@@ -150,7 +152,7 @@
   return begin->first > 0 ? 0 : begin->second;
 }
 
-size_t ChunkStream::GetLastByteBefore(size_t offset) const {
+size_t ChunkStream::GetFirstMissingByteInInterval(size_t offset) const {
   if (chunks_.empty())
     return 0;
   std::map<size_t, size_t>::const_iterator it = chunks_.upper_bound(offset);
@@ -160,13 +162,13 @@
   return it->first + it->second;
 }
 
-size_t ChunkStream::GetFirstByteAfter(size_t offset) const {
+size_t ChunkStream::GetLastMissingByteInInterval(size_t offset) const {
   if (chunks_.empty())
-    return 0;
+    return stream_size_ - 1;
   std::map<size_t, size_t>::const_iterator it = chunks_.upper_bound(offset);
   if (it == chunks_.end())
-    return data_.size();
-  return it->first;
+    return stream_size_ - 1;
+  return it->first - 1;
 }
 
 }  // namespace chrome_pdf
diff --git a/pdf/chunk_stream.h b/pdf/chunk_stream.h
index fac1ec64..048f958 100644
--- a/pdf/chunk_stream.h
+++ b/pdf/chunk_stream.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 
 #include <map>
+#include <utility>
 #include <vector>
 
 namespace chrome_pdf {
@@ -33,16 +34,20 @@
   bool IsRangeAvailable(size_t offset, size_t size) const;
   size_t GetFirstMissingByte() const;
 
-  size_t GetLastByteBefore(size_t offset) const;
-  size_t GetFirstByteAfter(size_t offset) const;
+  // Finds the first byte of the missing byte interval that offset belongs to.
+  size_t GetFirstMissingByteInInterval(size_t offset) const;
+  // Returns the last byte of the missing byte interval that offset belongs to.
+  size_t GetLastMissingByteInInterval(size_t offset) const;
 
  private:
   std::vector<unsigned char> data_;
 
   // Pair, first - begining of the chunk, second - size of the chunk.
   std::map<size_t, size_t> chunks_;
+
+  size_t stream_size_;
 };
 
 };  // namespace chrome_pdf
 
-#endif
+#endif  // PDF_CHUNK_STREAM_H_
diff --git a/pdf/document_loader.cc b/pdf/document_loader.cc
index 5bbed1a0..89e74676 100644
--- a/pdf/document_loader.cc
+++ b/pdf/document_loader.cc
@@ -16,9 +16,6 @@
 
 namespace {
 
-// Document below size will be downloaded in one chunk.
-const uint32_t kMinFileSize = 64 * 1024;
-
 // If the headers have a byte-range response, writes the start and end
 // positions and returns true if at least the start position was parsed.
 // The end position will be set to 0 if it was not found or parsed from the
@@ -176,14 +173,18 @@
 }
 
 void DocumentLoader::LoadPartialDocument() {
+  // The current request is a full request (not a range request) so it starts at
+  // 0 and ends at |document_size_|.
+  current_chunk_size_ = document_size_;
+  current_pos_ = 0;
+  current_request_offset_ = 0;
+  current_request_size_ = 0;
+  current_request_extended_size_ = document_size_;
+  request_pending_ = true;
+
   partial_document_ = true;
-  // Force the main request to be cancelled, since if we're a full-frame plugin
-  // there could be other references to the loader.
-  loader_.Close();
-  loader_ = pp::URLLoader();
-  // Download file header.
   header_request_ = true;
-  RequestData(0, std::min(GetRequestSize(), document_size_));
+  ReadMore();
 }
 
 void DocumentLoader::LoadFullDocument() {
@@ -212,12 +213,8 @@
 }
 
 void DocumentLoader::ClearPendingRequests() {
-  // The first item in the queue is pending (need to keep it in the queue).
-  if (pending_requests_.size() > 1) {
-    // Remove all elements except the first one.
-    pending_requests_.erase(++pending_requests_.begin(),
-                            pending_requests_.end());
-  }
+  pending_requests_.erase(pending_requests_.begin(),
+                          pending_requests_.end());
 }
 
 bool DocumentLoader::GetBlock(uint32_t position,
@@ -247,86 +244,74 @@
   DownloadPendingRequests();
 }
 
-void DocumentLoader::DownloadPendingRequests() {
-  if (request_pending_ || pending_requests_.empty())
-    return;
-
-  // Remove already completed requests.
-  // By design DownloadPendingRequests() should have at least 1 request in the
-  // queue. ReadComplete() will remove the last pending comment from the queue.
-  while (pending_requests_.size() > 1) {
-    if (IsDataAvailable(pending_requests_.front().first,
-                        pending_requests_.front().second)) {
-      pending_requests_.pop_front();
-    } else {
-      break;
-    }
-  }
-
-  uint32_t pos = pending_requests_.front().first;
-  uint32_t size = pending_requests_.front().second;
-  if (IsDataAvailable(pos, size)) {
-    ReadComplete();
-    return;
-  }
-
-  // If current request has been partially downloaded already, split it into
-  // a few smaller requests.
+void DocumentLoader::RemoveCompletedRanges() {
+  // Split every request that has been partially downloaded already into smaller
+  // requests.
   std::vector<std::pair<size_t, size_t> > ranges;
-  chunk_stream_.GetMissedRanges(pos, size, &ranges);
-  if (!ranges.empty()) {
-    pending_requests_.pop_front();
-    pending_requests_.insert(pending_requests_.begin(),
-                             ranges.begin(), ranges.end());
+  auto it = pending_requests_.begin();
+  while (it != pending_requests_.end()) {
+    chunk_stream_.GetMissedRanges(it->first, it->second, &ranges);
+    pending_requests_.insert(it, ranges.begin(), ranges.end());
+    ranges.clear();
+    pending_requests_.erase(it++);
+  }
+}
+
+void DocumentLoader::DownloadPendingRequests() {
+  if (request_pending_)
+    return;
+
+  uint32_t pos;
+  uint32_t size;
+  if (pending_requests_.empty()) {
+    // If the document is not complete and we have no outstanding requests,
+    // download what's left for as long as no other request gets added to
+    // |pending_requests_|.
+    pos = chunk_stream_.GetFirstMissingByte();
+    if (pos >= document_size_) {
+      // We're done downloading the document.
+      return;
+    }
+    // Start with size 0, we'll set |current_request_extended_size_| to > 0.
+    // This way this request will get cancelled as soon as the renderer wants
+    // another portion of the document.
+    size = 0;
+  } else {
+    RemoveCompletedRanges();
+
     pos = pending_requests_.front().first;
     size = pending_requests_.front().second;
+    if (IsDataAvailable(pos, size)) {
+      ReadComplete();
+      return;
+    }
   }
 
-  uint32_t cur_request_size = GetRequestSize();
-  // If size is less than default request, try to expand download range for
-  // more optimal download.
-  if (size < cur_request_size && partial_document_) {
-    // First, try to expand block towards the end of the file.
-    uint32_t new_pos = pos;
-    uint32_t new_size = cur_request_size;
-    if (pos + new_size > document_size_)
-      new_size = document_size_ - pos;
-
-    std::vector<std::pair<size_t, size_t> > ranges;
-    if (chunk_stream_.GetMissedRanges(new_pos, new_size, &ranges)) {
-      new_pos = ranges[0].first;
-      new_size = ranges[0].second;
+  size_t last_byte_before = chunk_stream_.GetFirstMissingByteInInterval(pos);
+  if (size < kDefaultRequestSize) {
+    // Try to extend before pos, up to size |kDefaultRequestSize|.
+    if (pos + size - last_byte_before > kDefaultRequestSize) {
+      pos += size - kDefaultRequestSize;
+      size = kDefaultRequestSize;
+    } else {
+      size += pos - last_byte_before;
+      pos = last_byte_before;
     }
-
-    // Second, try to expand block towards the beginning of the file.
-    if (new_size < cur_request_size) {
-      uint32_t block_end = new_pos + new_size;
-      if (block_end > cur_request_size) {
-        new_pos = block_end - cur_request_size;
-      } else {
-        new_pos = 0;
-      }
-      new_size = block_end - new_pos;
-
-      if (chunk_stream_.GetMissedRanges(new_pos, new_size, &ranges)) {
-        new_pos = ranges.back().first;
-        new_size = ranges.back().second;
-      }
-    }
-    pos = new_pos;
-    size = new_size;
   }
-
-  size_t last_byte_before = chunk_stream_.GetLastByteBefore(pos);
-  size_t first_byte_after = chunk_stream_.GetFirstByteAfter(pos + size - 1);
-  if (pos - last_byte_before < cur_request_size) {
-    size = pos + size - last_byte_before;
+  if (pos - last_byte_before < kDefaultRequestSize) {
+    // Don't leave a gap smaller than |kDefaultRequestSize|.
+    size += pos - last_byte_before;
     pos = last_byte_before;
   }
 
-  if ((pos + size < first_byte_after) &&
-      (pos + size + cur_request_size >= first_byte_after))
-    size = first_byte_after - pos;
+  current_request_offset_ = pos;
+  current_request_size_ = size;
+
+  // Extend the request until the next downloaded byte or the end of the
+  // document.
+  size_t last_missing_byte =
+      chunk_stream_.GetLastMissingByteInInterval(pos + size - 1);
+  current_request_extended_size_ = last_missing_byte - pos + 1;
 
   request_pending_ = true;
 
@@ -335,7 +320,7 @@
   loader_ = client_->CreateURLLoader();
   pp::CompletionCallback callback =
       loader_factory_.NewCallback(&DocumentLoader::DidOpen);
-  pp::URLRequestInfo request = GetRequest(pos, size);
+  pp::URLRequestInfo request = GetRequest(pos, current_request_extended_size_);
   requests_count_++;
   int rv = loader_.Open(request, callback);
   if (rv != PP_OK_COMPLETIONPENDING)
@@ -469,14 +454,51 @@
       current_chunk_read_ += length;
       client_->OnNewDataAvailable();
     }
+
+    // Only call the renderer if we allow partial loading.
+    if (!partial_document_) {
+      ReadMore();
+      return;
+    }
+
+    UpdateRendering();
+    RemoveCompletedRanges();
+
+    if (!pending_requests_.empty()) {
+      // If there are pending requests and the current content we're downloading
+      // doesn't satisfy any of these requests, cancel the current request to
+      // fullfill those more important requests.
+      bool satisfying_pending_request =
+            SatisfyingRequest(current_request_offset_, current_request_size_);
+      for (const auto& pending_request : pending_requests_) {
+        if (SatisfyingRequest(pending_request.first, pending_request.second)) {
+          satisfying_pending_request = true;
+          break;
+        }
+      }
+      // Cancel the request as it's not satisfying any request from the
+      // renderer, unless the current request is finished in which case we let
+      // it finish cleanly.
+      if (!satisfying_pending_request &&
+          current_pos_ < current_request_offset_ +
+          current_request_extended_size_) {
+        loader_.Close();
+      }
+    }
+
     ReadMore();
-  } else if (result == PP_OK) {
+  } else if (result == PP_OK || result == PP_ERROR_ABORTED) {
     ReadComplete();
   } else {
     NOTREACHED();
   }
 }
 
+bool DocumentLoader::SatisfyingRequest(size_t offset, size_t size) const {
+  return offset <= current_pos_ + kDefaultRequestSize &&
+      current_pos_ < offset + size;
+}
+
 void DocumentLoader::ReadComplete() {
   if (!partial_document_) {
     if (document_size_ == 0) {
@@ -497,46 +519,22 @@
   }
 
   request_pending_ = false;
-  pending_requests_.pop_front();
-
-  // If there are more pending request - continue downloading.
-  if (!pending_requests_.empty()) {
-    DownloadPendingRequests();
-    return;
-  }
 
   if (IsDocumentComplete()) {
     client_->OnDocumentComplete();
     return;
   }
 
+  UpdateRendering();
+  DownloadPendingRequests();
+}
+
+void DocumentLoader::UpdateRendering() {
   if (header_request_)
     client_->OnPartialDocumentLoaded();
   else
     client_->OnPendingRequestComplete();
   header_request_ = false;
-
-  // The OnPendingRequestComplete could have added more requests.
-  if (!pending_requests_.empty()) {
-    DownloadPendingRequests();
-  } else {
-    // Document is not complete and we have no outstanding requests.
-    // Let's keep downloading PDF file in small chunks.
-    uint32_t pos = chunk_stream_.GetFirstMissingByte();
-    std::vector<std::pair<size_t, size_t> > ranges;
-    chunk_stream_.GetMissedRanges(pos, GetRequestSize(), &ranges);
-    DCHECK(!ranges.empty());
-    RequestData(ranges[0].first, ranges[0].second);
-  }
-}
-
-uint32_t DocumentLoader::GetRequestSize() const {
-  // Document loading strategy:
-  // For first 10 requests, we use 32k chunk sizes, for the next 10 requests we
-  // double the size (64k), and so on, until we cap max request size at 2M for
-  // 71 or more requests.
-  uint32_t limited_count = std::min(std::max(requests_count_, 10u), 70u);
-  return 32 * 1024 * (1 << ((limited_count - 1) / 10u));
 }
 
 }  // namespace chrome_pdf
diff --git a/pdf/document_loader.h b/pdf/document_loader.h
index 4e734a0..7e175de 100644
--- a/pdf/document_loader.h
+++ b/pdf/document_loader.h
@@ -7,6 +7,7 @@
 
 #include <list>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/basictypes.h"
@@ -14,8 +15,6 @@
 #include "ppapi/cpp/url_loader.h"
 #include "ppapi/utility/completion_callback_factory.h"
 
-#define kDefaultRequestSize 32768u
-
 namespace chrome_pdf {
 
 class DocumentLoader {
@@ -81,12 +80,24 @@
   void LoadFullDocument();
   // Download pending requests.
   void DownloadPendingRequests();
+  // Remove completed ranges.
+  void RemoveCompletedRanges();
+  // Returns true if we are already in progress satisfying the request, or just
+  // about ready to start. This helps us avoid expensive jumping around, and
+  // even worse leaving tiny gaps in the byte stream that might have to be
+  // filled later.
+  bool SatisfyingRequest(size_t pos, size_t size) const;
   // Called when we complete server request and read all data from it.
   void ReadComplete();
   // Creates request to download size byte of data data starting from position.
   pp::URLRequestInfo GetRequest(uint32_t position, uint32_t size) const;
-  // Returns current request size in bytes.
-  uint32_t GetRequestSize() const;
+  // Updates the rendering by the Client.
+  void UpdateRendering();
+
+  // Document below size will be downloaded in one chunk.
+  static const uint32_t kMinFileSize = 64 * 1024;
+  // Number was chosen in crbug.com/78264#c8
+  enum { kDefaultRequestSize = 65536 };
 
   Client* client_;
   std::string url_;
@@ -97,6 +108,15 @@
   bool request_pending_;
   typedef std::list<std::pair<size_t, size_t> > PendingRequests;
   PendingRequests pending_requests_;
+  // The starting position of the HTTP request currently being processed.
+  size_t current_request_offset_;
+  // The size of the byte range the current HTTP request must download before
+  // being cancelled.
+  size_t current_request_size_;
+  // The actual byte range size of the current HTTP request. This may be larger
+  // than |current_request_size_| and the request may be cancelled before
+  // reaching |current_request_offset_| + |current_request_extended_size_|.
+  size_t current_request_extended_size_;
   char buffer_[kDefaultRequestSize];
   uint32_t current_pos_;
   uint32_t current_chunk_size_;
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 20e84d9..5287a29 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -206,7 +206,11 @@
     // MS Mincho in Shift_JIS encoding.
     {"\x82\x6C\x82\x72\x96\xBE\x92\xA9",
      "MS Mincho", false, false},
-};
+  };
+
+  // Similar logic exists in PDFium's CFX_FolderFontInfo::FindFont().
+  if (charset == FXFONT_ANSI_CHARSET && (pitch_family & FXFONT_FF_FIXEDPITCH))
+    face = "Courier New";
 
   // Map from the standard PDF fonts to TrueType font names.
   size_t i;
diff --git a/ppapi/proxy/file_io_resource.cc b/ppapi/proxy/file_io_resource.cc
index e119dd5c..1d31ef4 100644
--- a/ppapi/proxy/file_io_resource.cc
+++ b/ppapi/proxy/file_io_resource.cc
@@ -4,6 +4,8 @@
 
 #include "ppapi/proxy/file_io_resource.h"
 
+#include <limits>
+
 #include "base/bind.h"
 #include "base/task_runner_util.h"
 #include "ipc/ipc_message.h"
@@ -289,8 +291,10 @@
       increase = bytes_to_write;
     } else {
       uint64_t max_offset = offset + bytes_to_write;
-      if (max_offset > static_cast<uint64_t>(kint64max))
+      if (max_offset >
+          static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
         return PP_ERROR_FAILED;  // amount calculation would overflow.
+      }
       increase = static_cast<int64_t>(max_offset) - max_written_offset_;
     }
 
diff --git a/ppapi/proxy/ppapi_command_buffer_proxy.cc b/ppapi/proxy/ppapi_command_buffer_proxy.cc
index a77433d40..9fe1899 100644
--- a/ppapi/proxy/ppapi_command_buffer_proxy.cc
+++ b/ppapi/proxy/ppapi_command_buffer_proxy.cc
@@ -213,6 +213,10 @@
   return false;
 }
 
+int32_t PpapiCommandBufferProxy::GetExtraCommandBufferData() const {
+  return 0;
+}
+
 uint32 PpapiCommandBufferProxy::InsertSyncPoint() {
   uint32 sync_point = 0;
   if (last_state_.error == gpu::error::kNoError) {
diff --git a/ppapi/proxy/ppapi_command_buffer_proxy.h b/ppapi/proxy/ppapi_command_buffer_proxy.h
index fedb36215..0242d4c 100644
--- a/ppapi/proxy/ppapi_command_buffer_proxy.h
+++ b/ppapi/proxy/ppapi_command_buffer_proxy.h
@@ -75,6 +75,7 @@
   void SignalSyncToken(const gpu::SyncToken& sync_token,
                        const base::Closure& callback) override;
   bool CanWaitUnverifiedSyncToken(const gpu::SyncToken* sync_token) override;
+  int32_t GetExtraCommandBufferData() const override;
 
  private:
   bool Send(IPC::Message* msg);
diff --git a/ppapi/proxy/websocket_resource.cc b/ppapi/proxy/websocket_resource.cc
index bc4e85355..b374ef3 100644
--- a/ppapi/proxy/websocket_resource.cc
+++ b/ppapi/proxy/websocket_resource.cc
@@ -4,6 +4,7 @@
 
 #include "ppapi/proxy/websocket_resource.h"
 
+#include <limits>
 #include <set>
 #include <string>
 #include <vector>
@@ -26,8 +27,8 @@
 const size_t kMinimumPayloadSizeWithEightByteExtendedPayloadLength = 0x10000;
 
 uint64_t SaturateAdd(uint64_t a, uint64_t b) {
-  if (kuint64max - a < b)
-    return kuint64max;
+  if (std::numeric_limits<uint64_t>::max() - a < b)
+    return std::numeric_limits<uint64_t>::max();
   return a + b;
 }
 
diff --git a/remoting/BUILD.gn b/remoting/BUILD.gn
index 815f8b6..2dbbecf 100644
--- a/remoting/BUILD.gn
+++ b/remoting/BUILD.gn
@@ -41,10 +41,10 @@
     ]
   }
 
-  if (is_android) {
+  if (is_android && !is_component_build) {
     deps += [
-      #"//remoting:remoting_apk",
-      #"//remoting:remoting_test_apk",
+      "//remoting/android:remoting_apk",
+      "//remoting/android:remoting_test_apk",
     ]
   }
 
diff --git a/remoting/android/BUILD.gn b/remoting/android/BUILD.gn
new file mode 100644
index 0000000..b14baf8
--- /dev/null
+++ b/remoting/android/BUILD.gn
@@ -0,0 +1,134 @@
+# 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/android/config.gni")
+import("//build/config/android/rules.gni")
+import("//remoting/android/client_java_tmpl.gni")
+import("//remoting/android/remoting_apk_tmpl.gni")
+import("//remoting/remoting_options.gni")
+import("//remoting/tools/build/remoting_localize.gni")
+
+assert(!is_component_build, "Remoting requires static library build.")
+
+generate_jni("jni_headers") {
+  sources = [
+    "java/src/org/chromium/chromoting/jni/Client.java",
+    "java/src/org/chromium/chromoting/jni/JniInterface.java",
+    "java/src/org/chromium/chromoting/jni/TouchEventData.java",
+  ]
+  jni_package = "remoting"
+}
+
+shared_library("remoting_client_jni") {
+  deps = [
+    "//google_apis",
+    "//remoting/android:jni_headers",
+    "//remoting/base",
+    "//remoting/client",
+    "//remoting/protocol",
+    "//ui/events:dom_keycode_converter",
+    "//ui/gfx",
+  ]
+  sources = [
+    "//remoting/client/jni/android_keymap.cc",
+    "//remoting/client/jni/android_keymap.h",
+    "//remoting/client/jni/chromoting_jni_instance.cc",
+    "//remoting/client/jni/chromoting_jni_instance.h",
+    "//remoting/client/jni/chromoting_jni_runtime.cc",
+    "//remoting/client/jni/chromoting_jni_runtime.h",
+    "//remoting/client/jni/jni_client.cc",
+    "//remoting/client/jni/jni_client.h",
+    "//remoting/client/jni/jni_frame_consumer.cc",
+    "//remoting/client/jni/jni_frame_consumer.h",
+    "//remoting/client/jni/jni_touch_event_data.cc",
+    "//remoting/client/jni/jni_touch_event_data.h",
+    "//remoting/client/jni/remoting_jni_onload.cc",
+    "//remoting/client/jni/remoting_jni_registrar.cc",
+    "//remoting/client/jni/remoting_jni_registrar.h",
+  ]
+}
+
+_raw_resources_base_dir = "$target_gen_dir/remoting_android_raw_resources/res"
+copy("remoting_android_raw_resources") {
+  _credits_html = get_label_info("//remoting/webapp:credits",
+                                 "target_gen_dir") + "/credits.html"
+  sources = [
+    "//remoting/webapp/base/html/credits_css.css",
+    "//remoting/webapp/base/html/main.css",
+    "//remoting/webapp/base/js/credits_js.js",
+    _credits_html,
+  ]
+  outputs = [
+    "$_raw_resources_base_dir/raw/{{source_file_part}}",
+  ]
+  deps = [
+    "//remoting/webapp:credits",
+  ]
+}
+
+remoting_localize("remoting_apk_manifest") {
+  sources = [
+    "java/AndroidManifest.xml.jinja2",
+  ]
+  locales = [ "en" ]
+  defines = [ "ENABLE_CARDBOARD=$enable_cardboard" ]
+  variables = [ branding_path ]
+  output = "$root_gen_dir/remoting/android/{{source_name_part}}"
+}
+
+android_resources("remoting_android_client_java_resources") {
+  custom_package = "org.chromium.chromoting"
+  resource_dirs = [ "java/res" ]
+  generated_resource_dirs = [ _raw_resources_base_dir ]
+  generated_resource_files =
+      get_target_outputs(":remoting_android_raw_resources")
+
+  deps = [
+    ":remoting_android_raw_resources",
+    "//remoting/resources:strings_java",
+    "//third_party/android_tools:android_support_v7_appcompat_resources",
+  ]
+}
+
+remoting_android_client_java_tmpl("remoting_android_client_java") {
+  remoting_google_play_services_library = google_play_services_library
+}
+
+action("remoting_cardboard_extract_native_lib") {
+  script = "//remoting/tools/extract_android_native_lib.py"
+  sources = [
+    "//third_party/cardboard-java/src/CardboardSample/libs/cardboard.jar",
+  ]
+  outputs = [
+    "$root_out_dir/libvrtoolkit.so",
+  ]
+  args = [ android_app_abi ]
+  args += rebase_path(sources, root_build_dir)
+  args += rebase_path(outputs, root_build_dir)
+}
+
+remoting_apk_tmpl("remoting_apk") {
+  apk_name = "Chromoting"
+
+  DEPRECATED_java_in_dir = "//remoting/android/apk/src"
+
+  deps = [
+    ":remoting_android_client_java",
+    "//base:base_java",
+    "//net/android:net_java",
+    google_play_services_resources,
+  ]
+}
+
+instrumentation_test_apk("remoting_test_apk") {
+  android_manifest = "javatests/AndroidManifest.xml"
+  apk_name = "ChromotingTest"
+  apk_under_test = ":remoting_apk"
+  DEPRECATED_java_in_dir = "javatests/src"
+  deps = [
+    ":remoting_android_client_java",
+    "//base:base_java",
+    "//base:base_java_test_support",
+  ]
+}
diff --git a/remoting/android/client_java_tmpl.gni b/remoting/android/client_java_tmpl.gni
new file mode 100644
index 0000000..91ef26101
--- /dev/null
+++ b/remoting/android/client_java_tmpl.gni
@@ -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("//build/config/android/rules.gni")
+import("//remoting/remoting_options.gni")
+
+template("remoting_android_client_java_tmpl") {
+  android_library(target_name) {
+    DEPRECATED_java_in_dir = "//remoting/android/java/src"
+    java_files = []
+
+    if (enable_cast) {
+      java_files += [ "//remoting/android/cast/src/org/chromium/chromoting/CastExtensionHandler.java" ]
+    }
+
+    deps = [
+      "//base:base_java",
+      "//remoting/android:remoting_android_client_java_resources",
+      "//third_party/android_tools:android_support_v13_java",
+      "//third_party/android_tools:android_support_v7_appcompat_java",
+      "//third_party/android_tools:android_support_v7_mediarouter_java",
+      "//third_party/cardboard-java",
+      "//ui/android:ui_java",
+    ]
+
+    deps += [ invoker.remoting_google_play_services_library ]
+  }
+}
diff --git a/remoting/android/java/src/org/chromium/chromoting/DesktopCanvas.java b/remoting/android/java/src/org/chromium/chromoting/DesktopCanvas.java
index b9edf31..83a0be3 100644
--- a/remoting/android/java/src/org/chromium/chromoting/DesktopCanvas.java
+++ b/remoting/android/java/src/org/chromium/chromoting/DesktopCanvas.java
@@ -20,10 +20,12 @@
     private final RenderData mRenderData;
 
     /**
-     * The current cursor position is stored here as a float so that the desktop image can be
-     * positioned with sub-pixel accuracy to give a smoother panning animation at high zoom levels.
+     * Represents the desired center of the viewport.  This value may not represent the actual
+     * center of the viewport as adjustments are made to ensure as much of the desktop is visible as
+     * possible.  This value needs to be a pair of floats so the desktop image can be positioned
+     * with sub-pixel accuracy for smoother panning animations at high zoom levels.
      */
-    private PointF mCursorPosition = new PointF();
+    private PointF mViewportPosition = new PointF();
 
     /**
      * Represents the amount of vertical space in pixels used by the soft input device and
@@ -37,26 +39,37 @@
      */
     private int mInputMethodOffsetX = 0;
 
-    /** Used to determine whether the view should be locked to the cursor. */
-    private boolean mCenterCursorInView = true;
-
     public DesktopCanvas(DesktopViewInterface viewer, RenderData renderData) {
         mViewer = viewer;
         mRenderData = renderData;
     }
 
-    public void setCenterCursorInView(boolean centerCursor) {
-        mCenterCursorInView = centerCursor;
+    /**
+     * Returns the desired center position of the viewport.  Note that this may not represent the
+     * true center of the viewport as other calculations are done to maximize the viewable area.
+     *
+     * @return A point representing the desired position of the viewport.
+     */
+    public PointF getViewportPosition() {
+        return new PointF(mViewportPosition.x, mViewportPosition.y);
     }
 
-    public PointF getCursorPosition() {
-        return new PointF(mCursorPosition.x, mCursorPosition.y);
+    /**
+     * Sets the desired center position of the viewport.
+     *
+     * @param newX The new x coordinate value for the desired center position.
+     * @param newY The new y coordinate value for the desired center position.
+     */
+    public void setViewportPosition(float newX, float newY) {
+        mViewportPosition.set(newX, newY);
     }
 
-    public void setCursorPosition(float newX, float newY) {
-        mCursorPosition.set(newX, newY);
-    }
-
+    /**
+     * Sets the offset values used to calculate the space used by the current soft input method.
+     *
+     * @param offsetX The space used by the soft input method UI on the right edge of the screen.
+     * @param offsetY The space used by the soft input method UI on the bottom edge of the screen.
+     */
     public void setInputMethodOffsetValues(int offsetX, int offsetY) {
         mInputMethodOffsetX = offsetX;
         mInputMethodOffsetY = offsetY;
@@ -99,27 +112,26 @@
 
     /**
      * Repositions the image by translating it (without affecting the zoom level) to place the
-     * cursor close to the center of the screen.
+     * viewport close to the center of the screen.
      */
     public void repositionImage() {
         synchronized (mRenderData) {
             float adjustedScreenWidth = mRenderData.screenWidth - mInputMethodOffsetX;
             float adjustedScreenHeight = mRenderData.screenHeight - mInputMethodOffsetY;
 
-            if (mCenterCursorInView) {
-                // For indirect input modes such as Trackpad emulation, we want to try to position
-                // the view so the cursor is centered.  We move it here and then make adjustments
-                // below as needed to keep as much of the image on screen as possible.
+            // The goal of the code below is to position the viewport as close to the desired center
+            // position as possible whilst keeping as much of the desktop in view as possible.
+            // To achieve these goals, we first position the desktop image at the desired center
+            // point and then re-position it to maximize the viewable area.
 
-                // Get the current cursor position in screen coordinates.
-                float[] cursorScreen = {mCursorPosition.x, mCursorPosition.y};
-                mRenderData.transform.mapPoints(cursorScreen);
+            // Map the current viewport position to screen coordinates.
+            float[] viewportPosition = {mViewportPosition.x, mViewportPosition.y};
+            mRenderData.transform.mapPoints(viewportPosition);
 
-                // Translate so the cursor is displayed in the middle of the screen.
-                mRenderData.transform.postTranslate(
-                        (float) adjustedScreenWidth / 2 - cursorScreen[0],
-                        (float) adjustedScreenHeight / 2 - cursorScreen[1]);
-            }
+            // Translate so the viewport is displayed in the middle of the screen.
+            mRenderData.transform.postTranslate(
+                    (float) adjustedScreenWidth / 2 - viewportPosition[0],
+                    (float) adjustedScreenHeight / 2 - viewportPosition[1]);
 
             // Get the coordinates of the desktop rectangle (top-left/bottom-right corners) in
             // screen coordinates. Order is: left, top, right, bottom.
diff --git a/remoting/android/java/src/org/chromium/chromoting/DesktopView.java b/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
index d2499be3..5d4e33d 100644
--- a/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
+++ b/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
@@ -62,14 +62,14 @@
         private static final float TOTAL_DURATION_MS = 220;
 
         /** Start time of the animation, from {@link SystemClock#uptimeMillis()}. */
-        private long mStartTime = 0;
+        private long mStartTimeInMs = 0;
 
         private boolean mRunning = false;
 
         /** Contains the size of the feedback animation for the most recent request. */
         private float mFeedbackSizeInPixels;
 
-        /** Lock to allow multithreaded access to {@link #mStartTime} and {@link #mRunning}. */
+        /** Lock to allow multithreaded access to {@link #mStartTimeInMs} and {@link #mRunning}. */
         private final Object mLock = new Object();
 
         private Paint mPaint = new Paint();
@@ -92,7 +92,7 @@
 
             synchronized (mLock) {
                 mRunning = true;
-                mStartTime = SystemClock.uptimeMillis();
+                mStartTimeInMs = SystemClock.uptimeMillis();
                 mFeedbackSizeInPixels = getInputFeedbackSizeInPixels(feedbackType);
             }
         }
@@ -102,7 +102,17 @@
             float progress;
             float size;
             synchronized (mLock) {
-                progress = (SystemClock.uptimeMillis() - mStartTime) / TOTAL_DURATION_MS;
+                // |mStartTimeInMs| is set and accessed on different threads (hence the lock).  It
+                // is possible for |mStartTimeInMs| to be updated when an animation is in progress.
+                // When this occurs, |radius| will eventually be set to 0 and used to initialize
+                // RadialGradient which requires the radius to be > 0.  This will result in a crash.
+                // In order to avoid this problem, we return early if the elapsed time is 0.
+                float elapsedTimeInMs = SystemClock.uptimeMillis() - mStartTimeInMs;
+                if (elapsedTimeInMs < 1) {
+                    return;
+                }
+
+                progress = elapsedTimeInMs / TOTAL_DURATION_MS;
                 if (progress >= 1) {
                     mRunning = false;
                     return;
@@ -222,7 +232,8 @@
         }
 
         Canvas canvas;
-        int x, y;
+        Point cursorPosition;
+        boolean drawCursor;
         synchronized (mRenderData) {
             mRepaintPending = false;
             // Don't try to lock the canvas before it is ready, as the implementation of
@@ -237,26 +248,30 @@
                 return;
             }
             canvas.setMatrix(mRenderData.transform);
-            x = mRenderData.cursorPosition.x;
-            y = mRenderData.cursorPosition.y;
+            drawCursor = mRenderData.drawCursor;
+            cursorPosition = mRenderData.getCursorPosition();
         }
 
         canvas.drawColor(Color.BLACK);
         canvas.drawBitmap(image, 0, 0, new Paint());
 
+        // TODO(joedow): Replace the custom animation code with a standard Android implementation.
         boolean feedbackAnimationRunning = mFeedbackAnimator.isAnimationRunning();
         if (feedbackAnimationRunning) {
             float scaleFactor;
             synchronized (mRenderData) {
                 scaleFactor = mRenderData.transform.mapRadius(1);
             }
-            mFeedbackAnimator.render(canvas, x, y, scaleFactor);
+            mFeedbackAnimator.render(canvas, cursorPosition.x, cursorPosition.y, scaleFactor);
         }
 
-        Bitmap cursorBitmap = JniInterface.getCursorBitmap();
-        if (cursorBitmap != null) {
-            Point hotspot = JniInterface.getCursorHotspot();
-            canvas.drawBitmap(cursorBitmap, x - hotspot.x, y - hotspot.y, new Paint());
+        if (drawCursor) {
+            Bitmap cursorBitmap = JniInterface.getCursorBitmap();
+            if (cursorBitmap != null) {
+                Point hotspot = JniInterface.getCursorHotspot();
+                canvas.drawBitmap(cursorBitmap, cursorPosition.x - hotspot.x,
+                        cursorPosition.y - hotspot.y, new Paint());
+            }
         }
 
         getHolder().unlockCanvasAndPost(canvas);
@@ -401,7 +416,7 @@
 
         switch (inputMode) {
             case TRACKPAD:
-                mInputHandler.setInputStrategy(new TrackpadInputStrategy(this, mRenderData));
+                mInputHandler.setInputStrategy(new TrackpadInputStrategy(mRenderData));
                 break;
 
             case TOUCH:
@@ -416,5 +431,8 @@
                 // Unreachable, but required by Google Java style and findbugs.
                 assert false : "Unreached";
         }
+
+        // Ensure the cursor state is updated appropriately.
+        requestRepaint();
     }
 }
diff --git a/remoting/android/java/src/org/chromium/chromoting/InputStrategyInterface.java b/remoting/android/java/src/org/chromium/chromoting/InputStrategyInterface.java
index 1048f51..4f39962 100644
--- a/remoting/android/java/src/org/chromium/chromoting/InputStrategyInterface.java
+++ b/remoting/android/java/src/org/chromium/chromoting/InputStrategyInterface.java
@@ -4,33 +4,74 @@
 
 package org.chromium.chromoting;
 
+import android.view.MotionEvent;
+
 /**
  * This interface defines the methods used to customize input handling for
  * a particular strategy.  The implementing class is responsible for sending
  * remote input events and defining implementation specific behavior.
  */
 public interface InputStrategyInterface {
-    /** Sends a pointer move event to the remote host. */
-    void injectRemoteMoveEvent(int x, int y);
+    /**
+     * Called when a user tap has been detected.
+     *
+     * @param button The button value for the tap event.
+     * @return A boolean representing whether the event was handled.
+     */
+    boolean onTap(int button);
 
-    /** Sends a pointer button event to the remote host. */
-    void injectRemoteButtonEvent(int button, boolean pressed);
+    /**
+     * Called when the user has put one or more fingers down on the screen for a period of time.
+     *
+     * @param button The button value for the tap event.
+     * @return A boolean representing whether the event was handled.
+     */
+    boolean onPressAndHold(int button);
 
-    /** Sends a scroll/pan event to the remote host. */
-    void injectRemoteScrollEvent(int deltaX, int deltaY);
+    /**
+     * Called when a MotionEvent is received.  This method allows the input strategy to store or
+     * react to specific MotionEvents as needed.
+     *
+     * @param event The original event for the current touch motion.
+     */
+    void onMotionEvent(MotionEvent event);
 
-    /** Returns the feedback animation type to use for a short press. */
+    /**
+     * Called when the user is attempting to scroll/pan the remote UI.
+     *
+     * @param distanceX The distance moved along the x-axis.
+     * @param distanceY The distance moved along the y-axis.
+     */
+    void onScroll(float distanceX, float distanceY);
+
+    /**
+     * Called to update the remote cursor position.
+     *
+     * @param x The new x coordinate of the cursor.
+     * @param y The new y coordinate of the cursor.
+     */
+    void injectCursorMoveEvent(int x, int y);
+
+    /**
+     * Returns the feedback animation type to use for a short press.
+     *
+     * @return The feedback to display when a short press occurs.
+     */
     DesktopView.InputFeedbackType getShortPressFeedbackType();
 
-    /** Returns the feedback animation type to use for a long press. */
+    /**
+     * Returns the feedback animation type to use for a long press.
+     *
+     * @return The feedback to display when a long press occurs.
+     */
     DesktopView.InputFeedbackType getLongPressFeedbackType();
 
     /**
-     * Indicates whether the view should be manipulated to keep the cursor in the center or if the
-     * view and cursor are not linked.
+     * Indicates whether this input mode is an indirect input mode.  Indirect input modes manipulate
+     * the cursor in a detached fashion (such as a trackpad) and direct input modes will update the
+     * cursor/screen position to match the location of the touch point.
+     *
+     * @return A boolean representing whether this input mode is indirect (true) or direct (false).
      */
-    boolean centerCursorInView();
-
-    /** Indicates whether to invert cursor movement for panning/scrolling. */
-    boolean invertCursorMovement();
+    boolean isIndirectInputMode();
 }
diff --git a/remoting/android/java/src/org/chromium/chromoting/RenderData.java b/remoting/android/java/src/org/chromium/chromoting/RenderData.java
index f161c9f..8e21488 100644
--- a/remoting/android/java/src/org/chromium/chromoting/RenderData.java
+++ b/remoting/android/java/src/org/chromium/chromoting/RenderData.java
@@ -20,9 +20,42 @@
     public int imageWidth = 0;
     public int imageHeight = 0;
 
+    /** Determines whether the local cursor should be drawn. */
+    public boolean drawCursor = false;
+
     /**
      * Specifies the position, in image coordinates, at which the cursor image will be drawn.
      * This will normally be at the location of the most recently injected motion event.
      */
-    public Point cursorPosition = new Point();
+    private Point mCursorPosition = new Point();
+
+    /**
+     * Returns the position of the rendered cursor.
+     *
+     * @return A point representing the current position.
+     */
+    public Point getCursorPosition() {
+        return new Point(mCursorPosition);
+    }
+
+    /**
+     * Sets the position of the cursor which is used for rendering.
+     *
+     * @param newX The new value of the x coordinate.
+     * @param newY The new value of the y coordinate
+     * @return True if the cursor position has changed.
+     */
+    public boolean setCursorPosition(int newX, int newY) {
+        boolean cursorMoved = false;
+        if (newX != mCursorPosition.x) {
+            mCursorPosition.x = newX;
+            cursorMoved = true;
+        }
+        if (newY != mCursorPosition.y) {
+            mCursorPosition.y = newY;
+            cursorMoved = true;
+        }
+
+        return cursorMoved;
+    }
 }
diff --git a/remoting/android/java/src/org/chromium/chromoting/TapGestureDetector.java b/remoting/android/java/src/org/chromium/chromoting/TapGestureDetector.java
index 14cf558f..45dab79 100644
--- a/remoting/android/java/src/org/chromium/chromoting/TapGestureDetector.java
+++ b/remoting/android/java/src/org/chromium/chromoting/TapGestureDetector.java
@@ -25,16 +25,20 @@
          * Notified when a tap event occurs.
          *
          * @param pointerCount The number of fingers that were tapped.
+         * @param x The x coordinate of the initial finger tapped.
+         * @param y The y coordinate of the initial finger tapped.
          * @return True if the event is consumed.
          */
-        boolean onTap(int pointerCount);
+        boolean onTap(int pointerCount, float x, float y);
 
         /**
          * Notified when a long-touch event occurs.
          *
          * @param pointerCount The number of fingers held down.
+         * @param x The x coordinate of the initial finger tapped.
+         * @param y The y coordinate of the initial finger tapped.
          */
-        void onLongPress(int pointerCount);
+        void onLongPress(int pointerCount, float x, float y);
     }
 
     /** The listener to which notifications are sent. */
@@ -46,6 +50,9 @@
     /** The maximum number of fingers seen in the gesture. */
     private int mPointerCount = 0;
 
+    /** The coordinates of the first finger down seen in the gesture. */
+    private PointF mInitialPoint;
+
     /**
      * Stores the location of each down MotionEvent (by pointer ID), for detecting motion of any
      * pointer beyond the TouchSlop region.
@@ -74,7 +81,8 @@
         public void handleMessage(Message message) {
             TapGestureDetector detector = mDetector.get();
             if (detector != null) {
-                detector.mListener.onLongPress(detector.mPointerCount);
+                detector.mListener.onLongPress(
+                        detector.mPointerCount, detector.mInitialPoint.x, detector.mInitialPoint.y);
                 detector.mTapCancelled = true;
             }
         }
@@ -117,8 +125,9 @@
             case MotionEvent.ACTION_UP:
                 cancelLongTouchNotification();
                 if (!mTapCancelled) {
-                    handled = mListener.onTap(mPointerCount);
+                    handled = mListener.onTap(mPointerCount, mInitialPoint.x, mInitialPoint.y);
                 }
+                mInitialPoint = null;
                 break;
 
             case MotionEvent.ACTION_POINTER_UP:
@@ -143,8 +152,12 @@
             pointerIndex = event.getActionIndex();
         }
         int pointerId = event.getPointerId(pointerIndex);
-        mInitialPositions.put(pointerId,
-                new PointF(event.getX(pointerIndex), event.getY(pointerIndex)));
+        PointF eventPosition = new PointF(event.getX(pointerIndex), event.getY(pointerIndex));
+        mInitialPositions.put(pointerId, eventPosition);
+
+        if (mInitialPoint == null) {
+            mInitialPoint = eventPosition;
+        }
     }
 
     /** Removes the ACTION_UP or ACTION_POINTER_UP event from the stored list. */
diff --git a/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java b/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java
index d7520f7..7f95555 100644
--- a/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java
+++ b/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java
@@ -34,7 +34,7 @@
     private ScaleGestureDetector mZoomer;
     private TapGestureDetector mTapDetector;
 
-    /** Used to calculate the physics for flinging the cursor. */
+    /** Used to calculate the physics for flinging the viewport across the desktop image. */
     private Scroller mFlingScroller;
 
     /** Used to disambiguate a 2-finger gesture as a swipe or a pinch. */
@@ -52,9 +52,6 @@
      */
     private float mSwipeThreshold;
 
-    /** Mouse-button currently held down, or BUTTON_UNDEFINED otherwise. */
-    private int mHeldButton = BUTTON_UNDEFINED;
-
     /**
      * Set to true to prevent any further movement of the cursor, for example, when showing the
      * keyboard to prevent the cursor wandering from the area where keystrokes should be sent.
@@ -73,6 +70,12 @@
      */
     private boolean mSwipeCompleted = false;
 
+    /**
+     * Set to true when a 1 finger pan gesture originates with a longpress.  This means the user
+     * is performing a drag operation.
+     */
+    private boolean mIsDragging = false;
+
     public TouchInputHandler(DesktopViewInterface viewer, Context context, RenderData renderData) {
         mViewer = viewer;
         mRenderData = renderData;
@@ -101,6 +104,11 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
+        // Give the underlying input strategy a chance to observe the current motion event before
+        // passing it to the gesture detectors.  This allows the input strategy to react to the
+        // event or save the payload for use in recreating the gesture remotely.
+        mInputStrategy.onMotionEvent(event);
+
         // Avoid short-circuit logic evaluation - ensure all gesture detectors see all events so
         // that they generate correct notifications.
         boolean handled = mScroller.onTouchEvent(event);
@@ -114,16 +122,13 @@
                 mSuppressCursorMovement = false;
                 mSuppressFling = false;
                 mSwipeCompleted = false;
+                mIsDragging = false;
                 break;
 
             case MotionEvent.ACTION_POINTER_DOWN:
                 mTotalMotionY = 0;
                 break;
 
-            case MotionEvent.ACTION_UP:
-                releaseAnyHeldButton();
-                break;
-
             default:
                 break;
         }
@@ -137,7 +142,7 @@
 
     @Override
     public void onHostSizeChanged(int width, int height) {
-        moveCursor((float) width / 2, (float) height / 2);
+        moveViewport((float) width / 2, (float) height / 2);
         mDesktopCanvas.resizeImageToFitScreen();
     }
 
@@ -172,30 +177,29 @@
             canvasToImage.mapVectors(delta);
         }
 
-        moveCursorRelative(-delta[0], -delta[1]);
+        moveViewportWithOffset(-delta[0], -delta[1]);
     }
 
     @Override
     public void setInputStrategy(InputStrategyInterface inputStrategy) {
         mInputStrategy = inputStrategy;
-        mDesktopCanvas.setCenterCursorInView(mInputStrategy.centerCursorInView());
     }
 
-    /** Moves the mouse-cursor relative to the current position. */
-    private void moveCursorRelative(float deltaX, float deltaY) {
-        if (mInputStrategy.invertCursorMovement()) {
+    /** Moves the desired center of the viewport using the specified deltas. */
+    private void moveViewportWithOffset(float deltaX, float deltaY) {
+        // If we are in an indirect mode or are in the middle of a drag operation, then we want to
+        // invert the direction of the operation (i.e. follow the motion of the finger).
+        if (mInputStrategy.isIndirectInputMode() || mIsDragging) {
             deltaX = -deltaX;
             deltaY = -deltaY;
         }
 
-        PointF cursorPosition = mDesktopCanvas.getCursorPosition();
-        moveCursor(cursorPosition.x + deltaX, cursorPosition.y + deltaY);
-    }
-
-    /** Moves the mouse-cursor, injects a mouse-move event and repositions the image. */
-    private void moveCursor(float newX, float newY) {
+        // Constrain the coordinates to the image area.
+        PointF viewportPosition = mDesktopCanvas.getViewportPosition();
+        float newX = viewportPosition.x + deltaX;
+        float newY = viewportPosition.y + deltaY;
         synchronized (mRenderData) {
-            // Constrain cursor to the image area.
+            // Constrain viewport position to the image area.
             if (newX < 0) {
                 newX = 0;
             } else if (newX > mRenderData.imageWidth) {
@@ -207,13 +211,43 @@
             } else if (newY > mRenderData.imageHeight) {
                 newY = mRenderData.imageHeight;
             }
+        }
 
-            mDesktopCanvas.setCursorPosition(newX, newY);
+        moveViewport(newX, newY);
+    }
+
+    /** Moves the desired center of the viewport to the specified position. */
+    private void moveViewport(float newX, float newY) {
+        mDesktopCanvas.setViewportPosition(newX, newY);
+
+        // If we are in an indirect mode or are in the middle of a drag operation, then we want to
+        // keep the cursor centered, if possible, as the viewport moves.
+        if (mInputStrategy.isIndirectInputMode() || mIsDragging) {
+            moveCursor((int) newX, (int) newY);
         }
 
         mDesktopCanvas.repositionImage();
+    }
 
-        mInputStrategy.injectRemoteMoveEvent((int) newX, (int) newY);
+    /** Moves the cursor to the specified position on the screen. */
+    private void moveCursorToScreenPoint(float screenX, float screenY) {
+        float[] mappedValues = {screenX, screenY};
+        synchronized (mRenderData) {
+            Matrix canvasToImage = new Matrix();
+            mRenderData.transform.invert(canvasToImage);
+            canvasToImage.mapPoints(mappedValues);
+        }
+        moveCursor((int) mappedValues[0], (int) mappedValues[1]);
+    }
+
+    /** Moves the cursor to the specified position on the remote host. */
+    private void moveCursor(int newX, int newY) {
+        synchronized (mRenderData) {
+            boolean cursorMoved = mRenderData.setCursorPosition(newX, newY);
+            if (cursorMoved) {
+                mInputStrategy.injectCursorMoveEvent(newX, newY);
+            }
+        }
     }
 
     /** Processes a (multi-finger) swipe gesture. */
@@ -234,14 +268,6 @@
         return true;
     }
 
-    /** Injects a button-up event if the button is currently held down (during a drag event). */
-    private void releaseAnyHeldButton() {
-        if (mHeldButton != BUTTON_UNDEFINED) {
-            mInputStrategy.injectRemoteButtonEvent(mHeldButton, false);
-            mHeldButton = BUTTON_UNDEFINED;
-        }
-    }
-
     /** Responds to touch events filtered by the gesture detectors. */
     private class GestureListener extends GestureDetector.SimpleOnGestureListener
             implements ScaleGestureDetector.OnScaleGestureListener,
@@ -261,7 +287,7 @@
             }
 
             if (pointerCount == 2 && mSwipePinchDetector.isSwiping()) {
-                mInputStrategy.injectRemoteScrollEvent(-(int) distanceX, -(int) distanceY);
+                mInputStrategy.onScroll(distanceX, distanceY);
 
                 // Prevent the cursor being moved or flung by the gesture.
                 mSuppressCursorMovement = true;
@@ -279,7 +305,7 @@
                 canvasToImage.mapVectors(delta);
             }
 
-            moveCursorRelative(delta[0], delta[1]);
+            moveViewportWithOffset(delta[0], delta[1]);
             return true;
         }
 
@@ -356,26 +382,38 @@
 
         /** Called when the user taps the screen with one or more fingers. */
         @Override
-        public boolean onTap(int pointerCount) {
+        public boolean onTap(int pointerCount, float x, float y) {
             int button = mouseButtonFromPointerCount(pointerCount);
             if (button == BUTTON_UNDEFINED) {
                 return false;
-            } else {
-                mInputStrategy.injectRemoteButtonEvent(button, true);
-                mInputStrategy.injectRemoteButtonEvent(button, false);
-                mViewer.showInputFeedback(mInputStrategy.getShortPressFeedbackType());
-                return true;
             }
+
+            if (!mInputStrategy.isIndirectInputMode()) {
+                moveCursorToScreenPoint(x, y);
+            }
+
+            if (mInputStrategy.onTap(button)) {
+                mViewer.showInputFeedback(mInputStrategy.getShortPressFeedbackType());
+            }
+            return true;
         }
 
         /** Called when a long-press is triggered for one or more fingers. */
         @Override
-        public void onLongPress(int pointerCount) {
-            mHeldButton = mouseButtonFromPointerCount(pointerCount);
-            if (mHeldButton != BUTTON_UNDEFINED) {
-                mInputStrategy.injectRemoteButtonEvent(mHeldButton, true);
+        public void onLongPress(int pointerCount, float x, float y) {
+            int button = mouseButtonFromPointerCount(pointerCount);
+            if (button == BUTTON_UNDEFINED) {
+                return;
+            }
+
+            if (!mInputStrategy.isIndirectInputMode()) {
+                moveCursorToScreenPoint(x, y);
+            }
+
+            if (mInputStrategy.onPressAndHold(button)) {
                 mViewer.showInputFeedback(mInputStrategy.getLongPressFeedbackType());
                 mSuppressFling = true;
+                mIsDragging = true;
             }
         }
 
diff --git a/remoting/android/java/src/org/chromium/chromoting/TrackpadInputStrategy.java b/remoting/android/java/src/org/chromium/chromoting/TrackpadInputStrategy.java
index edc9baf..326eff97 100644
--- a/remoting/android/java/src/org/chromium/chromoting/TrackpadInputStrategy.java
+++ b/remoting/android/java/src/org/chromium/chromoting/TrackpadInputStrategy.java
@@ -4,6 +4,9 @@
 
 package org.chromium.chromoting;
 
+import android.graphics.Point;
+import android.view.MotionEvent;
+
 import org.chromium.chromoting.jni.JniInterface;
 
 /**
@@ -13,33 +16,49 @@
  */
 public class TrackpadInputStrategy implements InputStrategyInterface {
     private final RenderData mRenderData;
-    private final DesktopViewInterface mViewer;
 
-    public TrackpadInputStrategy(DesktopViewInterface viewer, RenderData renderData) {
-        mViewer = viewer;
+    /** Mouse-button currently held down, or BUTTON_UNDEFINED otherwise. */
+    private int mHeldButton = TouchInputHandlerInterface.BUTTON_UNDEFINED;
+
+    public TrackpadInputStrategy(RenderData renderData) {
         mRenderData = renderData;
-    }
 
-    @Override
-    public void injectRemoteMoveEvent(int x, int y) {
-        injectRemoteButtonEvent(x, y, TouchInputHandlerInterface.BUTTON_UNDEFINED, false);
-    }
-
-    @Override
-    public void injectRemoteButtonEvent(int button, boolean pressed) {
-        int x;
-        int y;
         synchronized (mRenderData) {
-            x = mRenderData.cursorPosition.x;
-            y = mRenderData.cursorPosition.y;
+            mRenderData.drawCursor = true;
         }
-
-        injectRemoteButtonEvent(x, y, button, pressed);
     }
 
     @Override
-    public void injectRemoteScrollEvent(int deltaX, int deltaY) {
-        JniInterface.sendMouseWheelEvent(deltaX, deltaY);
+    public boolean onTap(int button) {
+        injectMouseButtonEvent(button, true);
+        injectMouseButtonEvent(button, false);
+        return true;
+    }
+
+    @Override
+    public boolean onPressAndHold(int button) {
+        injectMouseButtonEvent(button, true);
+        mHeldButton = button;
+        return true;
+    }
+
+    @Override
+    public void onScroll(float distanceX, float distanceY) {
+        JniInterface.sendMouseWheelEvent((int) -distanceX, (int) -distanceY);
+    }
+
+    @Override
+    public void onMotionEvent(MotionEvent event) {
+        if (event.getActionMasked() == MotionEvent.ACTION_UP
+                && mHeldButton != TouchInputHandlerInterface.BUTTON_UNDEFINED) {
+            injectMouseButtonEvent(mHeldButton, false);
+            mHeldButton = TouchInputHandlerInterface.BUTTON_UNDEFINED;
+        }
+    }
+
+    @Override
+    public void injectCursorMoveEvent(int x, int y) {
+        JniInterface.sendMouseEvent(x, y, TouchInputHandlerInterface.BUTTON_UNDEFINED, false);
     }
 
     @Override
@@ -53,38 +72,15 @@
     }
 
     @Override
-    public boolean centerCursorInView() {
+    public boolean isIndirectInputMode() {
         return true;
     }
 
-    @Override
-    public boolean invertCursorMovement() {
-        return true;
-    }
-
-    private void injectRemoteButtonEvent(int x, int y, int button, boolean pressed) {
-        boolean cursorMoved = false;
+    private void injectMouseButtonEvent(int button, boolean pressed) {
+        Point cursorPosition;
         synchronized (mRenderData) {
-            // Test if the cursor actually moved, which requires repainting the cursor. This
-            // requires that |mRenderData.cursorPosition| was not assigned to beforehand.
-            if (x != mRenderData.cursorPosition.x) {
-                mRenderData.cursorPosition.x = x;
-                cursorMoved = true;
-            }
-            if (y != mRenderData.cursorPosition.y) {
-                mRenderData.cursorPosition.y = y;
-                cursorMoved = true;
-            }
+            cursorPosition = mRenderData.getCursorPosition();
         }
-
-        if (button == TouchInputHandlerInterface.BUTTON_UNDEFINED && !cursorMoved) {
-            // No need to inject anything or repaint.
-            return;
-        }
-
-        JniInterface.sendMouseEvent(x, y, button, pressed);
-        if (cursorMoved) {
-            mViewer.transformationChanged();
-        }
+        JniInterface.sendMouseEvent(cursorPosition.x, cursorPosition.y, button, pressed);
     }
 }
diff --git a/remoting/android/javatests/src/org/chromium/chromoting/TapGestureDetectorTest.java b/remoting/android/javatests/src/org/chromium/chromoting/TapGestureDetectorTest.java
index ab66faa4..3dd4b52 100644
--- a/remoting/android/javatests/src/org/chromium/chromoting/TapGestureDetectorTest.java
+++ b/remoting/android/javatests/src/org/chromium/chromoting/TapGestureDetectorTest.java
@@ -15,35 +15,52 @@
 /** Tests for {@link TapGestureDetector}. */
 public class TapGestureDetectorTest extends InstrumentationTestCase {
     private static class MockListener implements TapGestureDetector.OnTapListener {
+        private static final float COMPARISON_DELTA = 0.01f;
         int mTapCount = -1;
         int mLongPressCount = -1;
+        float mTapX = -1;
+        float mTapY = -1;
 
         @Override
-        public boolean onTap(int pointerCount) {
+        public boolean onTap(int pointerCount, float x, float y) {
             assertEquals(-1, mTapCount);
+            assertEquals(-1, mTapX, COMPARISON_DELTA);
+            assertEquals(-1, mTapY, COMPARISON_DELTA);
             mTapCount = pointerCount;
+            mTapX = x;
+            mTapY = y;
             return true;
         }
 
         @Override
-        public void onLongPress(int pointerCount) {
+        public void onLongPress(int pointerCount, float x, float y) {
             assertEquals(-1, mLongPressCount);
+            assertEquals(-1, mTapX, COMPARISON_DELTA);
+            assertEquals(-1, mTapY, COMPARISON_DELTA);
             mLongPressCount = pointerCount;
+            mTapX = x;
+            mTapY = y;
         }
 
-        public void assertTapDetected(int expectedCount) {
+        public void assertTapDetected(int expectedCount, float expectedX, float expectedY) {
             assertEquals(expectedCount, mTapCount);
+            assertEquals(expectedX, mTapX, COMPARISON_DELTA);
+            assertEquals(expectedY, mTapY, COMPARISON_DELTA);
             assertEquals(-1, mLongPressCount);
         }
 
-        public void assertLongPressDetected(int expectedCount) {
+        public void assertLongPressDetected(int expectedCount, float expectedX, float expectedY) {
             assertEquals(expectedCount, mLongPressCount);
+            assertEquals(expectedX, mTapX, COMPARISON_DELTA);
+            assertEquals(expectedY, mTapY, COMPARISON_DELTA);
             assertEquals(-1, mTapCount);
         }
 
         public void assertNothingDetected() {
             assertEquals(-1, mTapCount);
             assertEquals(-1, mLongPressCount);
+            assertEquals(-1, mTapX, COMPARISON_DELTA);
+            assertEquals(-1, mTapY, COMPARISON_DELTA);
         }
     }
 
@@ -85,7 +102,7 @@
     public void testOneFingerDownUp() throws Exception {
         injectDownEvent(0, 0, 0);
         injectUpEvent(0);
-        mListener.assertTapDetected(1);
+        mListener.assertTapDetected(1, 0, 0);
     }
 
     /** Verifies that a simple multi-finger down/up is detected as a tap. */
@@ -98,7 +115,7 @@
         injectUpEvent(0);
         injectUpEvent(1);
         injectUpEvent(2);
-        mListener.assertTapDetected(3);
+        mListener.assertTapDetected(3, 0, 0);
     }
 
     /** Verifies that a multi-finger tap is detected when lifting the fingers in reverse order. */
@@ -111,7 +128,7 @@
         injectUpEvent(2);
         injectUpEvent(1);
         injectUpEvent(0);
-        mListener.assertTapDetected(3);
+        mListener.assertTapDetected(3, 0, 0);
     }
 
     /** Verifies that small movement of multiple fingers is still detected as a tap. */
@@ -127,7 +144,7 @@
         injectUpEvent(0);
         injectUpEvent(1);
         injectUpEvent(2);
-        mListener.assertTapDetected(3);
+        mListener.assertTapDetected(3, 0, 0);
     }
 
     /** Verifies that large motion of a finger prevents a tap being detected. */
@@ -169,6 +186,6 @@
             }
         });
 
-        mListener.assertLongPressDetected(1);
+        mListener.assertLongPressDetected(1, 0, 0);
     }
 }
diff --git a/remoting/android/remoting_apk_tmpl.gni b/remoting/android/remoting_apk_tmpl.gni
new file mode 100644
index 0000000..57d5e57
--- /dev/null
+++ b/remoting/android/remoting_apk_tmpl.gni
@@ -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("//build/config/android/rules.gni")
+import("//chrome/android/chrome_apk_version.gni")
+
+if (!is_component_build) {
+  template("remoting_apk_tmpl") {
+    android_apk(target_name) {
+      forward_variables_from(invoker, "*")
+
+      version_name = chrome_apk_version_name
+      version_code = chrome_apk_version_code
+      android_manifest = "$root_gen_dir/remoting/android/AndroidManifest.xml"
+      native_libs = [ "libremoting_client_jni.so" ]
+
+      deps += [
+        "//remoting/android:remoting_apk_manifest",
+        "//remoting/android:remoting_client_jni",
+      ]
+
+      if (target_cpu == "arm") {
+        deps += [ "//remoting/android:remoting_cardboard_extract_native_lib" ]
+        native_libs += [ "libvrtoolkit.so" ]
+      }
+    }
+  }
+}
diff --git a/remoting/host/desktop_session_agent.cc b/remoting/host/desktop_session_agent.cc
index 2e486c5b..dd5a3fb 100644
--- a/remoting/host/desktop_session_agent.cc
+++ b/remoting/host/desktop_session_agent.cc
@@ -89,23 +89,16 @@
 
   ~SharedBuffer() override { agent_->OnSharedBufferDeleted(id()); }
 
+  base::SharedMemory* shared_memory() { return shared_memory_.get(); }
+
  private:
   SharedBuffer(DesktopSessionAgent* agent,
                scoped_ptr<base::SharedMemory> memory,
                size_t size,
                int id)
-      : SharedMemory(memory->memory(),
-                     size,
-#if defined(OS_WIN)
-                     memory->handle().GetHandle(),
-#else
-                     base::SharedMemory::GetFdFromSharedMemoryHandle(
-                         memory->handle()),
-#endif
-                     id),
+      : SharedMemory(memory->memory(), size, 0, id),
         agent_(agent),
-        shared_memory_(memory.Pass()) {
-  }
+        shared_memory_(memory.Pass()) {}
 
   DesktopSessionAgent* agent_;
   scoped_ptr<base::SharedMemory> shared_memory_;
@@ -208,9 +201,11 @@
 
     IPC::PlatformFileForTransit handle;
 #if defined(OS_WIN)
-    handle = buffer->handle();
+    handle = buffer->shared_memory()->handle().GetHandle(),
 #else
-    handle = base::FileDescriptor(buffer->handle(), false);
+    handle =
+        base::FileDescriptor(base::SharedMemory::GetFdFromSharedMemoryHandle(
+            buffer->shared_memory()->handle()), false);
 #endif
     SendToNetwork(new ChromotingDesktopNetworkMsg_CreateSharedBuffer(
         buffer->id(), handle, buffer->size()));
diff --git a/remoting/host/desktop_session_proxy.cc b/remoting/host/desktop_session_proxy.cc
index 4536500..6166d20a 100644
--- a/remoting/host/desktop_session_proxy.cc
+++ b/remoting/host/desktop_session_proxy.cc
@@ -67,14 +67,6 @@
   int id() { return id_; }
   size_t size() { return size_; }
   void* memory() { return shared_memory_.memory(); }
-  webrtc::SharedMemory::Handle handle() {
-#if defined(OS_WIN)
-    return shared_memory_.handle().GetHandle();
-#else
-    return base::SharedMemory::GetFdFromSharedMemoryHandle(
-        shared_memory_.handle());
-#endif
-  }
 
  private:
   virtual ~IpcSharedBufferCore() {}
@@ -90,10 +82,8 @@
 class DesktopSessionProxy::IpcSharedBuffer : public webrtc::SharedMemory {
  public:
   IpcSharedBuffer(scoped_refptr<IpcSharedBufferCore> core)
-      : SharedMemory(core->memory(), core->size(),
-                     core->handle(), core->id()),
-        core_(core) {
-  }
+      : SharedMemory(core->memory(), core->size(), 0, core->id()),
+        core_(core) {}
 
  private:
   scoped_refptr<IpcSharedBufferCore> core_;
diff --git a/remoting/host/installer/mac/Keystone/GoogleSoftwareUpdate.pkg b/remoting/host/installer/mac/Keystone/GoogleSoftwareUpdate.pkg
index 35abb80..d4e4bd2 100644
--- a/remoting/host/installer/mac/Keystone/GoogleSoftwareUpdate.pkg
+++ b/remoting/host/installer/mac/Keystone/GoogleSoftwareUpdate.pkg
Binary files differ
diff --git a/remoting/protocol/jingle_session.cc b/remoting/protocol/jingle_session.cc
index 4903fc45..92b56c8 100644
--- a/remoting/protocol/jingle_session.cc
+++ b/remoting/protocol/jingle_session.cc
@@ -4,6 +4,10 @@
 
 #include "remoting/protocol/jingle_session.h"
 
+#include <stdint.h>
+
+#include <limits>
+
 #include "base/bind.h"
 #include "base/rand_util.h"
 #include "base/single_thread_task_runner.h"
@@ -98,7 +102,8 @@
   // concurrent session per host, so a random 64-bit integer provides
   // enough entropy. In the worst case connection will fail when two
   // clients generate the same session ID concurrently.
-  session_id_ = base::Uint64ToString(base::RandGenerator(kuint64max));
+  session_id_ = base::Uint64ToString(
+      base::RandGenerator(std::numeric_limits<uint64_t>::max()));
 
   transport_ = session_manager_->transport_factory_->CreateTransport();
 
diff --git a/remoting/protocol/webrtc_data_stream_adapter.cc b/remoting/protocol/webrtc_data_stream_adapter.cc
index 9c1dac1a..b53800f 100644
--- a/remoting/protocol/webrtc_data_stream_adapter.cc
+++ b/remoting/protocol/webrtc_data_stream_adapter.cc
@@ -209,11 +209,11 @@
 
 void WebrtcDataStreamAdapter::Initialize(
     rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection,
-    bool is_server) {
+    bool outgoing) {
   peer_connection_ = peer_connection;
-  is_server_ = is_server;
+  outgoing_ = outgoing;
 
- if (!is_server_) {
+ if (outgoing_) {
     for (auto& channel : pending_channels_) {
       webrtc::DataChannelInit config;
       config.reliable = true;
@@ -226,7 +226,7 @@
 void WebrtcDataStreamAdapter::OnIncomingDataChannel(
     webrtc::DataChannelInterface* data_channel) {
   auto it = pending_channels_.find(data_channel->label());
-  if (!is_server_ || it == pending_channels_.end()) {
+  if (outgoing_ || it == pending_channels_.end()) {
     LOG(ERROR) << "Received unexpected data channel " << data_channel->label();
     return;
   }
@@ -243,7 +243,7 @@
                              base::Unretained(this), callback));
   pending_channels_[name] = channel;
 
-  if (peer_connection_ && !is_server_) {
+  if (peer_connection_ && outgoing_) {
     webrtc::DataChannelInit config;
     config.reliable = true;
     channel->Start(peer_connection_->CreateDataChannel(name, &config));
diff --git a/remoting/protocol/webrtc_data_stream_adapter.h b/remoting/protocol/webrtc_data_stream_adapter.h
index 1200db6..fc7e42f 100644
--- a/remoting/protocol/webrtc_data_stream_adapter.h
+++ b/remoting/protocol/webrtc_data_stream_adapter.h
@@ -20,15 +20,21 @@
 namespace remoting {
 namespace protocol {
 
+// WebrtcDataStreamAdapter is a StreamChannelFactory that creates channels that
+// send and receive data over PeerConnection data channels.
 class WebrtcDataStreamAdapter : public StreamChannelFactory {
  public:
   WebrtcDataStreamAdapter();
   ~WebrtcDataStreamAdapter() override;
 
+  // Initializes the adapter for |peer_connection|. If |outgoing| is set to true
+  // all channels will be created as outgoing. Otherwise CreateChannel() will
+  // wait for the other end to create connection.
   void Initialize(
       rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection,
-      bool is_server);
+      bool outgoing);
 
+  // Called by WebrtcTransport.
   void OnIncomingDataChannel(webrtc::DataChannelInterface* data_channel);
 
   // StreamChannelFactory interface.
@@ -44,7 +50,7 @@
                           bool connected);
 
   rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
-  bool is_server_ = false;
+  bool outgoing_ = false;
 
   std::map<std::string, Channel*> pending_channels_;
 
diff --git a/remoting/protocol/webrtc_transport.cc b/remoting/protocol/webrtc_transport.cc
index 3a6ad6f..6dcbb972 100644
--- a/remoting/protocol/webrtc_transport.cc
+++ b/remoting/protocol/webrtc_transport.cc
@@ -8,6 +8,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task_runner_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "jingle/glue/thread_wrapper.h"
 #include "third_party/libjingle/source/talk/app/webrtc/test/fakeconstraints.h"
 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
@@ -29,15 +30,6 @@
 // XML namespace for the transport elements.
 const char kTransportNamespace[] = "google:remoting:webrtc";
 
-rtc::Thread* InitAndGetRtcThread() {
-  jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
-
-  // TODO(sergeyu): Investigate if it's possible to avoid Send().
-  jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true);
-
-  return jingle_glue::JingleThreadWrapper::current();
-}
-
 // A webrtc::CreateSessionDescriptionObserver implementation used to receive the
 // results of creating descriptions for this end of the PeerConnection.
 class CreateSessionDescriptionObserver
@@ -108,13 +100,13 @@
 }  // namespace
 
 WebrtcTransport::WebrtcTransport(
+    rtc::Thread* worker_thread,
     rtc::scoped_refptr<webrtc::PortAllocatorFactoryInterface>
         port_allocator_factory,
-    TransportRole role,
-    scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner)
+    TransportRole role)
     : port_allocator_factory_(port_allocator_factory),
       role_(role),
-      worker_task_runner_(worker_task_runner),
+      worker_thread_(worker_thread),
       weak_factory_(this) {}
 
 WebrtcTransport::~WebrtcTransport() {}
@@ -126,10 +118,34 @@
   event_handler_ = event_handler;
 
   // TODO(sergeyu): Use the |authenticator| to authenticate PeerConnection.
+  jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
 
-  base::PostTaskAndReplyWithResult(
-      worker_task_runner_.get(), FROM_HERE, base::Bind(&InitAndGetRtcThread),
-      base::Bind(&WebrtcTransport::DoStart, weak_factory_.GetWeakPtr()));
+  // TODO(sergeyu): Investigate if it's possible to avoid Send().
+  jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true);
+
+  fake_audio_device_module_.reset(new webrtc::FakeAudioDeviceModule());
+
+  peer_connection_factory_ = webrtc::CreatePeerConnectionFactory(
+      worker_thread_, rtc::Thread::Current(),
+      fake_audio_device_module_.get(), nullptr, nullptr);
+
+  webrtc::PeerConnectionInterface::IceServer stun_server;
+  stun_server.urls.push_back("stun:stun.l.google.com:19302");
+  webrtc::PeerConnectionInterface::RTCConfiguration rtc_config;
+  rtc_config.servers.push_back(stun_server);
+
+  webrtc::FakeConstraints constraints;
+  constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
+                           webrtc::MediaConstraintsInterface::kValueTrue);
+
+  peer_connection_ = peer_connection_factory_->CreatePeerConnection(
+      rtc_config, &constraints, port_allocator_factory_, nullptr, this);
+
+  data_stream_adapter_.Initialize(peer_connection_,
+                                  role_ == TransportRole::SERVER);
+
+  if (role_ == TransportRole::SERVER)
+    RequestNegotiation();
 }
 
 bool WebrtcTransport::ProcessTransportInfo(XmlElement* transport_info) {
@@ -145,7 +161,7 @@
       QName(kTransportNamespace, "session-description"));
   if (session_description) {
     webrtc::PeerConnectionInterface::SignalingState expected_state =
-        role_ == TransportRole::SERVER
+        role_ == TransportRole::CLIENT
             ? webrtc::PeerConnectionInterface::kStable
             : webrtc::PeerConnectionInterface::kHaveLocalOffer;
     if (peer_connection_->signaling_state() != expected_state) {
@@ -156,7 +172,7 @@
     std::string type = session_description->Attr(QName(std::string(), "type"));
     std::string sdp = session_description->BodyText();
     if (type.empty() || sdp.empty()) {
-      LOG(ERROR) << "Incorrect session_description format.";
+      LOG(ERROR) << "Incorrect session description format.";
       return false;
     }
 
@@ -164,15 +180,16 @@
     scoped_ptr<webrtc::SessionDescriptionInterface> session_description(
         webrtc::CreateSessionDescription(type, sdp, &error));
     if (!session_description) {
-      LOG(ERROR) << "Failed to parse the offer: " << error.description
-                 << " line: " << error.line;
+      LOG(ERROR) << "Failed to parse the session description: "
+                 << error.description << " line: " << error.line;
       return false;
     }
 
     peer_connection_->SetRemoteDescription(
         SetSessionDescriptionObserver::Create(
             base::Bind(&WebrtcTransport::OnRemoteDescriptionSet,
-                       weak_factory_.GetWeakPtr())),
+                       weak_factory_.GetWeakPtr(),
+                       type == webrtc::SessionDescriptionInterface::kOffer)),
         session_description.release());
   }
 
@@ -227,54 +244,6 @@
   return GetStreamChannelFactory();
 }
 
-void WebrtcTransport::DoStart(rtc::Thread* worker_thread) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
-
-  // TODO(sergeyu): Investigate if it's possible to avoid Send().
-  jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true);
-
-  fake_audio_device_module_.reset(new webrtc::FakeAudioDeviceModule());
-
-  peer_connection_factory_ = webrtc::CreatePeerConnectionFactory(
-      worker_thread, rtc::Thread::Current(),
-      fake_audio_device_module_.get(), nullptr, nullptr);
-
-  webrtc::PeerConnectionInterface::IceServer stun_server;
-  stun_server.urls.push_back("stun:stun.l.google.com:19302");
-  webrtc::PeerConnectionInterface::RTCConfiguration rtc_config;
-  rtc_config.servers.push_back(stun_server);
-
-  webrtc::FakeConstraints constraints;
-  constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
-                           webrtc::MediaConstraintsInterface::kValueTrue);
-
-  peer_connection_ = peer_connection_factory_->CreatePeerConnection(
-      rtc_config, &constraints, port_allocator_factory_, nullptr, this);
-
-  data_stream_adapter_.Initialize(peer_connection_,
-                                  role_ == TransportRole::SERVER);
-
-  if (role_ == TransportRole::CLIENT) {
-    webrtc::FakeConstraints offer_config;
-    offer_config.AddMandatory(
-        webrtc::MediaConstraintsInterface::kOfferToReceiveVideo,
-        webrtc::MediaConstraintsInterface::kValueTrue);
-    offer_config.AddMandatory(
-        webrtc::MediaConstraintsInterface::kOfferToReceiveAudio,
-        webrtc::MediaConstraintsInterface::kValueFalse);
-    offer_config.AddMandatory(
-        webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
-        webrtc::MediaConstraintsInterface::kValueTrue);
-    peer_connection_->CreateOffer(
-        CreateSessionDescriptionObserver::Create(
-            base::Bind(&WebrtcTransport::OnLocalSessionDescriptionCreated,
-                       weak_factory_.GetWeakPtr())),
-        &offer_config);
-  }
-}
-
 void WebrtcTransport::OnLocalSessionDescriptionCreated(
     scoped_ptr<webrtc::SessionDescriptionInterface> description,
     const std::string& error) {
@@ -329,7 +298,8 @@
   AddPendingCandidatesIfPossible();
 }
 
-void WebrtcTransport::OnRemoteDescriptionSet(bool success,
+void WebrtcTransport::OnRemoteDescriptionSet(bool send_answer,
+                                             bool success,
                                              const std::string& error) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
@@ -343,7 +313,7 @@
   }
 
   // Create and send answer on the server.
-  if (role_ == TransportRole::SERVER) {
+  if (send_answer) {
     peer_connection_->CreateAnswer(
         CreateSessionDescriptionObserver::Create(
             base::Bind(&WebrtcTransport::OnLocalSessionDescriptionCreated,
@@ -389,7 +359,25 @@
 
 void WebrtcTransport::OnRenegotiationNeeded() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  // TODO(sergeyu): Figure out what needs to happen here.
+
+  if (role_ == TransportRole::SERVER) {
+    RequestNegotiation();
+  } else {
+    // TODO(sergeyu): Is it necessary to support renegotiation initiated by the
+    // client?
+    NOTIMPLEMENTED();
+  }
+}
+
+void WebrtcTransport::RequestNegotiation() {
+  DCHECK(role_ == TransportRole::SERVER);
+
+  if (!negotiation_pending_) {
+    negotiation_pending_ = true;
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(&WebrtcTransport::SendOffer, weak_factory_.GetWeakPtr()));
+  }
 }
 
 void WebrtcTransport::OnIceConnectionChange(
@@ -446,6 +434,28 @@
   }
 }
 
+void WebrtcTransport::SendOffer() {
+  DCHECK(role_ == TransportRole::SERVER);
+
+  DCHECK(negotiation_pending_);
+  negotiation_pending_ = false;
+
+  webrtc::FakeConstraints offer_config;
+  offer_config.AddMandatory(
+      webrtc::MediaConstraintsInterface::kOfferToReceiveVideo,
+      webrtc::MediaConstraintsInterface::kValueTrue);
+  offer_config.AddMandatory(
+      webrtc::MediaConstraintsInterface::kOfferToReceiveAudio,
+      webrtc::MediaConstraintsInterface::kValueFalse);
+  offer_config.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
+                            webrtc::MediaConstraintsInterface::kValueTrue);
+  peer_connection_->CreateOffer(
+      CreateSessionDescriptionObserver::Create(
+          base::Bind(&WebrtcTransport::OnLocalSessionDescriptionCreated,
+                     weak_factory_.GetWeakPtr())),
+      &offer_config);
+}
+
 void WebrtcTransport::SendTransportInfo() {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(pending_transport_info_message_);
@@ -472,23 +482,21 @@
 }
 
 WebrtcTransportFactory::WebrtcTransportFactory(
+    rtc::Thread* worker_thread,
     SignalStrategy* signal_strategy,
     rtc::scoped_refptr<webrtc::PortAllocatorFactoryInterface>
         port_allocator_factory,
     TransportRole role)
-    : signal_strategy_(signal_strategy),
+    : worker_thread_(worker_thread),
+      signal_strategy_(signal_strategy),
       port_allocator_factory_(port_allocator_factory),
-      role_(role),
-      worker_thread_("ChromotingWebrtcWorkerThread") {
-  worker_thread_.StartWithOptions(
-      base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
-}
+      role_(role) {}
 
 WebrtcTransportFactory::~WebrtcTransportFactory() {}
 
 scoped_ptr<Transport> WebrtcTransportFactory::CreateTransport() {
-  return make_scoped_ptr(new WebrtcTransport(port_allocator_factory_, role_,
-                                             worker_thread_.task_runner()));
+  return make_scoped_ptr(
+      new WebrtcTransport(worker_thread_, port_allocator_factory_, role_));
 }
 
 }  // namespace protocol
diff --git a/remoting/protocol/webrtc_transport.h b/remoting/protocol/webrtc_transport.h
index 74ec30c..ae792f2 100644
--- a/remoting/protocol/webrtc_transport.h
+++ b/remoting/protocol/webrtc_transport.h
@@ -9,7 +9,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
-#include "base/threading/thread.h"
 #include "base/threading/thread_checker.h"
 #include "base/timer/timer.h"
 #include "remoting/protocol/transport.h"
@@ -27,13 +26,19 @@
 class WebrtcTransport : public Transport,
                         public webrtc::PeerConnectionObserver {
  public:
-  WebrtcTransport(
-      rtc::scoped_refptr<webrtc::PortAllocatorFactoryInterface>
-          port_allocator_factory,
-      TransportRole role,
-      scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner);
+  WebrtcTransport(rtc::Thread* worker_thread,
+                  rtc::scoped_refptr<webrtc::PortAllocatorFactoryInterface>
+                      port_allocator_factory,
+                  TransportRole role);
   ~WebrtcTransport() override;
 
+  webrtc::PeerConnectionInterface* peer_connection() {
+    return peer_connection_;
+  }
+  webrtc::PeerConnectionFactoryInterface* peer_connection_factory() {
+    return peer_connection_factory_;
+  }
+
   // Transport interface.
   void Start(EventHandler* event_handler,
              Authenticator* authenticator) override;
@@ -42,12 +47,13 @@
   StreamChannelFactory* GetMultiplexedChannelFactory() override;
 
  private:
-  void DoStart(rtc::Thread* worker_thread);
   void OnLocalSessionDescriptionCreated(
       scoped_ptr<webrtc::SessionDescriptionInterface> description,
       const std::string& error);
   void OnLocalDescriptionSet(bool success, const std::string& error);
-  void OnRemoteDescriptionSet(bool success, const std::string& error);
+  void OnRemoteDescriptionSet(bool send_answer,
+                              bool success,
+                              const std::string& error);
 
   // webrtc::PeerConnectionObserver interface.
   void OnSignalingChange(
@@ -62,6 +68,8 @@
       webrtc::PeerConnectionInterface::IceGatheringState new_state) override;
   void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override;
 
+  void RequestNegotiation();
+  void SendOffer();
   void EnsurePendingTransportInfoMessage();
   void SendTransportInfo();
   void AddPendingCandidatesIfPossible();
@@ -74,7 +82,7 @@
       port_allocator_factory_;
   TransportRole role_;
   EventHandler* event_handler_ = nullptr;
-  scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner_;
+  rtc::Thread* worker_thread_;
 
   scoped_ptr<webrtc::FakeAudioDeviceModule> fake_audio_device_module_;
 
@@ -82,6 +90,8 @@
       peer_connection_factory_;
   rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
 
+  bool negotiation_pending_ = false;
+
   scoped_ptr<buzz::XmlElement> pending_transport_info_message_;
   base::OneShotTimer transport_info_timer_;
 
@@ -100,6 +110,7 @@
 class WebrtcTransportFactory : public TransportFactory {
  public:
   WebrtcTransportFactory(
+      rtc::Thread* worker_thread,
       SignalStrategy* signal_strategy,
       rtc::scoped_refptr<webrtc::PortAllocatorFactoryInterface>
           port_allocator_factory,
@@ -110,13 +121,12 @@
   scoped_ptr<Transport> CreateTransport() override;
 
  private:
+  rtc::Thread* worker_thread_;
   SignalStrategy* signal_strategy_;
   rtc::scoped_refptr<webrtc::PortAllocatorFactoryInterface>
       port_allocator_factory_;
   TransportRole role_;
 
-  base::Thread worker_thread_;
-
   DISALLOW_COPY_AND_ASSIGN(WebrtcTransportFactory);
 };
 
diff --git a/remoting/protocol/webrtc_transport_unittest.cc b/remoting/protocol/webrtc_transport_unittest.cc
index d327085..1797a7e 100644
--- a/remoting/protocol/webrtc_transport_unittest.cc
+++ b/remoting/protocol/webrtc_transport_unittest.cc
@@ -90,7 +90,7 @@
     signal_strategy_.reset(new FakeSignalStrategy(kTestJid));
 
     host_transport_factory_.reset(new WebrtcTransportFactory(
-        signal_strategy_.get(),
+        jingle_glue::JingleThreadWrapper::current(), signal_strategy_.get(),
         ChromiumPortAllocatorFactory::Create(network_settings_, nullptr),
         TransportRole::SERVER));
     host_transport_ = host_transport_factory_->CreateTransport();
@@ -98,7 +98,7 @@
         FakeAuthenticator::HOST, 0, FakeAuthenticator::ACCEPT, false));
 
     client_transport_factory_.reset(new WebrtcTransportFactory(
-        signal_strategy_.get(),
+        jingle_glue::JingleThreadWrapper::current(), signal_strategy_.get(),
         ChromiumPortAllocatorFactory::Create(network_settings_, nullptr),
         TransportRole::CLIENT));
     client_transport_ = client_transport_factory_->CreateTransport();
diff --git a/remoting/remoting_locales.gni b/remoting/remoting_locales.gni
index b37d177b..a9702de6 100644
--- a/remoting/remoting_locales.gni
+++ b/remoting/remoting_locales.gni
@@ -105,6 +105,52 @@
   messages_locales += [ "en_US" ]
 }
 
+remoting_android_locales = [
+  "am",
+  "ar",
+  "bg",
+  "ca",
+  "cs",
+  "da",
+  "de",
+  "el",
+  "en-rGB",
+  "es",
+  "es-rUS",
+  "fa",
+  "fi",
+  "fr",
+  "hi",
+  "hr",
+  "hu",
+  "in",
+  "it",
+  "iw",
+  "ja",
+  "ko",
+  "lt",
+  "lv",
+  "nb",
+  "nl",
+  "pl",
+  "pt-rBR",
+  "pt-rPT",
+  "ro",
+  "ru",
+  "sk",
+  "sl",
+  "sr",
+  "sv",
+  "sw",
+  "th",
+  "tl",
+  "tr",
+  "uk",
+  "vi",
+  "zh-rCN",
+  "zh-rTW",
+]
+
 # The list of .json files generated by remoting_strings.grd.
 remoting_webapp_locale_files =
     process_file_template(
diff --git a/remoting/remoting_options.gni b/remoting/remoting_options.gni
index 5f3d5b95..0cf8f29 100644
--- a/remoting/remoting_options.gni
+++ b/remoting/remoting_options.gni
@@ -14,11 +14,14 @@
 }
 
 # Set this to enable cast mode on the android client.
-enable_cast = 0
+enable_cast = false
 
 # Set this to use GCD instead of the remoting directory service.
 remoting_use_gcd = 0
 
+# Set this to enable Android Chromoting Cardboard Activity.
+enable_cardboard = false
+
 # Enable the multi-process host on Windows by default.
 if (is_win) {
   remoting_multi_process = 1
diff --git a/remoting/resources/BUILD.gn b/remoting/resources/BUILD.gn
index 2f2fcbfa..ddc1b0b 100644
--- a/remoting/resources/BUILD.gn
+++ b/remoting/resources/BUILD.gn
@@ -5,6 +5,10 @@
 import("//remoting/remoting_locales.gni")
 import("//tools/grit/grit_rule.gni")
 
+if (is_android) {
+  import("//build/config/android/rules.gni")
+}
+
 group("resources") {
   public_deps = [
     ":copy_locales",
@@ -64,6 +68,14 @@
   }
 }  # if false
 
+if (is_android) {
+  android_string_outputs =
+      [ "remoting/android/res/values/remoting_strings.xml" ]
+  android_string_outputs += process_file_template(
+          remoting_android_locales,
+          [ "remoting/android/res/values-{{source_name_part}}/remoting_strings.xml" ])
+}
+
 grit("strings") {
   source = "remoting_strings.grd"
   output_name = "remoting_strings"
@@ -83,6 +95,21 @@
                             [ "remoting/resources/{{source_name_part}}.pak" ])
 
   outputs += remoting_webapp_locale_files
+
+  if (is_android) {
+    outputs += android_string_outputs
+  }
+}
+
+if (is_android) {
+  java_strings_grd_prebuilt("strings_java") {
+    grit_output_dir = "$root_gen_dir/remoting/android/res"
+    generated_files =
+        rebase_path(android_string_outputs, "remoting/android/res", ".")
+    deps = [
+      ":strings",
+    ]
+  }
 }
 
 action("copy_locales") {
diff --git a/sandbox/linux/integration_tests/namespace_unix_domain_socket_unittest.cc b/sandbox/linux/integration_tests/namespace_unix_domain_socket_unittest.cc
index 9d79bff1..5e8a239 100644
--- a/sandbox/linux/integration_tests/namespace_unix_domain_socket_unittest.cc
+++ b/sandbox/linux/integration_tests/namespace_unix_domain_socket_unittest.cc
@@ -10,11 +10,11 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <utility>
 #include <vector>
 
 #include "base/files/scoped_file.h"
 #include "base/logging.h"
-#include "base/memory/scoped_vector.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/posix/unix_domain_socket_linux.h"
 #include "base/process/process.h"
@@ -95,14 +95,14 @@
   // Extra receiving buffer space to make sure we really received only
   // sizeof(kHello) bytes and it wasn't just truncated to fit the buffer.
   char buf[sizeof(kHello) + 1];
-  ScopedVector<base::ScopedFD> message_fds;
+  std::vector<base::ScopedFD> message_fds;
   ssize_t n = base::UnixDomainSocket::RecvMsgWithPid(
       fd, buf, sizeof(buf), &message_fds, sender_pid);
   CHECK_EQ(sizeof(kHello), static_cast<size_t>(n));
   CHECK_EQ(0, memcmp(buf, kHello, sizeof(kHello)));
   CHECK_EQ(1U, message_fds.size());
   if (write_pipe)
-    write_pipe->swap(*message_fds[0]);
+    std::swap(*write_pipe, message_fds[0]);
 }
 
 // Check that receiving PIDs works across a fork().
diff --git a/sandbox/linux/seccomp-bpf/trap.cc b/sandbox/linux/seccomp-bpf/trap.cc
index 8f559e5..01cbbaca 100644
--- a/sandbox/linux/seccomp-bpf/trap.cc
+++ b/sandbox/linux/seccomp-bpf/trap.cc
@@ -11,6 +11,7 @@
 
 #include <algorithm>
 #include <limits>
+#include <tuple>
 
 #include "base/compiler_specific.h"
 #include "base/logging.h"
@@ -251,13 +252,7 @@
 }
 
 bool Trap::TrapKey::operator<(const TrapKey& o) const {
-  if (fnc != o.fnc) {
-    return fnc < o.fnc;
-  } else if (aux != o.aux) {
-    return aux < o.aux;
-  } else {
-    return safe < o.safe;
-  }
+  return std::tie(fnc, aux, safe) < std::tie(o.fnc, o.aux, o.safe);
 }
 
 uint16_t Trap::Add(TrapFnc fnc, const void* aux, bool safe) {
diff --git a/sandbox/linux/syscall_broker/broker_host.cc b/sandbox/linux/syscall_broker/broker_host.cc
index 1a0568f..a81a30e 100644
--- a/sandbox/linux/syscall_broker/broker_host.cc
+++ b/sandbox/linux/syscall_broker/broker_host.cc
@@ -174,7 +174,7 @@
 // that we will then close.
 // A request should start with an int that will be used as the command type.
 BrokerHost::RequestStatus BrokerHost::HandleRequest() const {
-  ScopedVector<base::ScopedFD> fds;
+  std::vector<base::ScopedFD> fds;
   char buf[kMaxMessageLength];
   errno = 0;
   const ssize_t msg_len = base::UnixDomainSocket::RecvMsg(
@@ -187,13 +187,12 @@
 
   // The client should send exactly one file descriptor, on which we
   // will write the reply.
-  // TODO(mdempsky): ScopedVector doesn't have 'at()', only 'operator[]'.
-  if (msg_len < 0 || fds.size() != 1 || fds[0]->get() < 0) {
+  if (msg_len < 0 || fds.size() != 1 || fds[0].get() < 0) {
     PLOG(ERROR) << "Error reading message from the client";
     return RequestStatus::FAILURE;
   }
 
-  base::ScopedFD temporary_ipc(std::move(*fds[0]));
+  base::ScopedFD temporary_ipc(std::move(fds[0]));
 
   base::Pickle pickle(buf, msg_len);
   base::PickleIterator iter(pickle);
diff --git a/sandbox/win/src/crosscall_params.h b/sandbox/win/src/crosscall_params.h
index a601fc7..c060c607 100644
--- a/sandbox/win/src/crosscall_params.h
+++ b/sandbox/win/src/crosscall_params.h
@@ -114,7 +114,7 @@
   }
 
   // Returns how many parameter this IPC call should have.
-  const uint32_t GetParamsCount() const { return params_count_; }
+  uint32_t GetParamsCount() const { return params_count_; }
 
   // Returns a pointer to the CrossCallReturn structure.
   CrossCallReturn* GetCallReturn() {
@@ -122,9 +122,7 @@
   }
 
   // Returns TRUE if this call contains InOut parameters.
-  const bool IsInOut() const {
-    return (1 == is_in_out_);
-  }
+  bool IsInOut() const { return (1 == is_in_out_); }
 
   // Tells the CrossCall object if it contains InOut parameters.
   void SetIsInOut(bool value) {
diff --git a/sandbox/win/src/handle_closer_test.cc b/sandbox/win/src/handle_closer_test.cc
index 1cb2bb5..10ebe3b 100644
--- a/sandbox/win/src/handle_closer_test.cc
+++ b/sandbox/win/src/handle_closer_test.cc
@@ -86,8 +86,8 @@
     case BEFORE_INIT:
       // Create a unique marker file that is open while the test is running.
       // The handles leak, but it will be closed by the test or on exit.
-      for (int i = 0; i < arraysize(kFileExtensions); ++i)
-        CHECK_NE(GetMarkerFile(kFileExtensions[i]), INVALID_HANDLE_VALUE);
+      for (const wchar_t* kExtension : kFileExtensions)
+        CHECK_NE(GetMarkerFile(kExtension), INVALID_HANDLE_VALUE);
       return SBOX_TEST_SUCCEEDED;
 
     case AFTER_REVERT: {
@@ -134,8 +134,8 @@
   switch (state++) {
     case BEFORE_INIT:
       // Create a unique marker file that is open while the test is running.
-      for (int i = 0; i < arraysize(kFileExtensions); ++i) {
-        HANDLE handle = GetMarkerFile(kFileExtensions[i]);
+      for (const wchar_t* kExtension : kFileExtensions) {
+        HANDLE handle = GetMarkerFile(kExtension);
         CHECK_NE(handle, INVALID_HANDLE_VALUE);
         to_check.push_back(handle);
       }
@@ -195,9 +195,9 @@
   runner.SetTestState(EVERY_STATE);
 
   base::string16 command = base::string16(L"CheckForFileHandles Y");
-  for (int i = 0; i < arraysize(kFileExtensions); ++i) {
+  for (const wchar_t* kExtension : kFileExtensions) {
     base::string16 handle_name;
-    base::win::ScopedHandle marker(GetMarkerFile(kFileExtensions[i]));
+    base::win::ScopedHandle marker(GetMarkerFile(kExtension));
     CHECK(marker.IsValid());
     CHECK(sandbox::GetHandleName(marker.Get(), &handle_name));
     command += (L" ");
@@ -215,9 +215,9 @@
   sandbox::TargetPolicy* policy = runner.GetPolicy();
 
   base::string16 command = base::string16(L"CheckForFileHandles N");
-  for (int i = 0; i < arraysize(kFileExtensions); ++i) {
+  for (const wchar_t* kExtension : kFileExtensions) {
     base::string16 handle_name;
-    base::win::ScopedHandle marker(GetMarkerFile(kFileExtensions[i]));
+    base::win::ScopedHandle marker(GetMarkerFile(kExtension));
     CHECK(marker.IsValid());
     CHECK(sandbox::GetHandleName(marker.Get(), &handle_name));
     CHECK_EQ(policy->AddKernelObjectToClose(L"File", handle_name.c_str()),
@@ -236,9 +236,9 @@
   runner.SetTestState(EVERY_STATE);
   sandbox::TargetPolicy* policy = runner.GetPolicy();
 
-  for (int i = 0; i < arraysize(kFileExtensions); ++i) {
+  for (const wchar_t* kExtension : kFileExtensions) {
     base::string16 handle_name;
-    base::win::ScopedHandle marker(GetMarkerFile(kFileExtensions[i]));
+    base::win::ScopedHandle marker(GetMarkerFile(kExtension));
     CHECK(marker.IsValid());
     CHECK(sandbox::GetHandleName(marker.Get(), &handle_name));
     CHECK_EQ(policy->AddKernelObjectToClose(L"File", handle_name.c_str()),
diff --git a/sandbox/win/src/interception_unittest.cc b/sandbox/win/src/interception_unittest.cc
index 7ce5724b..9b282df7 100644
--- a/sandbox/win/src/interception_unittest.cc
+++ b/sandbox/win/src/interception_unittest.cc
@@ -93,7 +93,7 @@
   // ciel(log2(544)) = 10.
   // Alignment must be 2^10 = 1024.
   const size_t kAlignmentBits = base::bits::Log2Ceiling(kThunkBytes);
-  const size_t kAlignment = 1 << kAlignmentBits;
+  const size_t kAlignment = static_cast<size_t>(1) << kAlignmentBits;
 
   const size_t kAllocGranularity = 65536;
 
@@ -118,7 +118,7 @@
     max_val = std::max(val, max_val);
   }
   ASSERT_EQ(max_val, kAllocGranularity - kAlignment);
-  ASSERT_EQ(min_val, 0);
+  ASSERT_EQ(0u, min_val);
   ASSERT_EQ(min_nonzero_val, kAlignment);
 }
 
@@ -179,7 +179,7 @@
                                       INTERCEPTION_EAT, function, OPEN_KEY_ID);
 
   // Verify that all interceptions were added
-  ASSERT_EQ(18, interceptions.interceptions_.size());
+  ASSERT_EQ(18u, interceptions.interceptions_.size());
 
   size_t buffer_size = interceptions.GetBufferSize();
   scoped_ptr<BYTE[]> local_buffer(new BYTE[buffer_size]);
@@ -195,7 +195,7 @@
   // first group remains on the list of interceptions (inside the object
   // "interceptions"). There are 3 local interceptions (of ntdll); the
   // other 15 have to be sent to the child to be performed "hot".
-  EXPECT_EQ(3, interceptions.interceptions_.size());
+  EXPECT_EQ(3u, interceptions.interceptions_.size());
 
   int num_dlls, num_functions, num_names;
   WalkBuffer(local_buffer.get(), buffer_size, &num_dlls, &num_functions,
@@ -232,7 +232,7 @@
                                       INTERCEPTION_SMART_SIDESTEP, function,
                                       OPEN_FILE_ID);
   // Verify that all interceptions were added
-  ASSERT_EQ(5, interceptions.interceptions_.size());
+  ASSERT_EQ(5u, interceptions.interceptions_.size());
 
   size_t buffer_size = interceptions.GetBufferSize();
   scoped_ptr<BYTE[]> local_buffer(new BYTE[buffer_size]);
@@ -245,7 +245,7 @@
   // group with the interceptions belonging to dlls that will be "hot"
   // patched on the client. The second group lives on local_buffer, and the
   // first group remains on the list of interceptions, in this case just one.
-  EXPECT_EQ(1, interceptions.interceptions_.size());
+  EXPECT_EQ(1u, interceptions.interceptions_.size());
 
   int num_dlls, num_functions, num_names;
   WalkBuffer(local_buffer.get(), buffer_size, &num_dlls, &num_functions,
diff --git a/sandbox/win/src/ipc_unittest.cc b/sandbox/win/src/ipc_unittest.cc
index e8b0b810..9b61a43 100644
--- a/sandbox/win/src/ipc_unittest.cc
+++ b/sandbox/win/src/ipc_unittest.cc
@@ -68,11 +68,11 @@
   size_t channel_start = 0;
   IPCControl* client_control = MakeChannels(12 * 64, 4096, &channel_start);
   ASSERT_TRUE(NULL != client_control);
-  EXPECT_EQ(5, client_control->channels_count);
+  EXPECT_EQ(5u, client_control->channels_count);
 #if defined(_WIN64)
-  EXPECT_EQ(216, channel_start);
+  EXPECT_EQ(216u, channel_start);
 #else
-  EXPECT_EQ(108, channel_start);
+  EXPECT_EQ(108u, channel_start);
 #endif
   delete[] reinterpret_cast<char*>(client_control);
 }
@@ -166,7 +166,7 @@
 
   CrossCall(client, tag1, text, &answer);
   actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
-  EXPECT_EQ(1, actual_params->GetParamsCount());
+  EXPECT_EQ(1u, actual_params->GetParamsCount());
   EXPECT_EQ(tag1, actual_params->GetTag());
   EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text));
   EXPECT_STREQ(text, copied_text.c_str());
@@ -176,13 +176,13 @@
   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(1u, actual_params->GetParamsCount());
   EXPECT_EQ(tag2, actual_params->GetTag());
   uint32_t param_size = 1;
   ArgType type = INVALID_TYPE;
   void* param_addr = actual_params->GetRawParameter(0, &param_size, &type);
   EXPECT_TRUE(NULL != param_addr);
-  EXPECT_EQ(0, param_size);
+  EXPECT_EQ(0u, param_size);
   EXPECT_EQ(WCHAR_TYPE, type);
   EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text));
 
@@ -193,12 +193,12 @@
   // Check with an empty string and a non-empty string.
   CrossCall(client, tag3, null_text, text, &answer);
   actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
-  EXPECT_EQ(2, actual_params->GetParamsCount());
+  EXPECT_EQ(2u, actual_params->GetParamsCount());
   EXPECT_EQ(tag3, actual_params->GetTag());
   type = INVALID_TYPE;
   param_addr = actual_params->GetRawParameter(0, &param_size, &type);
   EXPECT_TRUE(NULL != param_addr);
-  EXPECT_EQ(0, param_size);
+  EXPECT_EQ(0u, param_size);
   EXPECT_EQ(WCHAR_TYPE, type);
   EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text));
   EXPECT_TRUE(actual_params->GetParameterStr(1, &copied_text));
@@ -210,7 +210,7 @@
   const wchar_t *text2 = L"AeFG";
   CrossCall(client, tag1, text2, null_text, text, &answer);
   actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
-  EXPECT_EQ(3, actual_params->GetParamsCount());
+  EXPECT_EQ(3u, actual_params->GetParamsCount());
   EXPECT_EQ(tag1, actual_params->GetTag());
   EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text_p0));
   EXPECT_STREQ(text2, copied_text_p0.c_str());
@@ -219,7 +219,7 @@
   type = INVALID_TYPE;
   param_addr = actual_params->GetRawParameter(1, &param_size, &type);
   EXPECT_TRUE(NULL != param_addr);
-  EXPECT_EQ(0, param_size);
+  EXPECT_EQ(0u, param_size);
   EXPECT_EQ(WCHAR_TYPE, type);
 
   CloseChannelEvents(client_control);
@@ -246,7 +246,7 @@
   DWORD dw = 0xE6578;
   CrossCall(client, tag2, dw, &answer);
   actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
-  EXPECT_EQ(1, actual_params->GetParamsCount());
+  EXPECT_EQ(1u, actual_params->GetParamsCount());
   EXPECT_EQ(tag2, actual_params->GetTag());
   ArgType type = INVALID_TYPE;
   uint32_t param_size = 1;
@@ -260,7 +260,7 @@
   HANDLE h = HANDLE(0x70000500);
   CrossCall(client, tag1, text, h, &answer);
   actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
-  EXPECT_EQ(2, actual_params->GetParamsCount());
+  EXPECT_EQ(2u, actual_params->GetParamsCount());
   EXPECT_EQ(tag1, actual_params->GetTag());
   type = INVALID_TYPE;
   param_addr = actual_params->GetRawParameter(1, &param_size, &type);
@@ -272,7 +272,7 @@
   // Check combination of 32 and 64 bits.
   CrossCall(client, tag2, h, dw, h, &answer);
   actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
-  EXPECT_EQ(3, actual_params->GetParamsCount());
+  EXPECT_EQ(3u, actual_params->GetParamsCount());
   EXPECT_EQ(tag2, actual_params->GetTag());
   type = INVALID_TYPE;
   param_addr = actual_params->GetRawParameter(0, &param_size, &type);
@@ -313,7 +313,7 @@
   ASSERT_TRUE(NULL != ccp);
   EXPECT_TRUE(ccp->GetBuffer() != buffer);
   EXPECT_EQ(kTag, ccp->GetTag());
-  EXPECT_EQ(1, ccp->GetParamsCount());
+  EXPECT_EQ(1u, ccp->GetParamsCount());
   delete[] (reinterpret_cast<char*>(ccp));
 
   // Test that we handle integer overflow on the number of params
@@ -434,7 +434,7 @@
   EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
   EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
 
-  EXPECT_EQ(0, client_control->channels[1].ipc_tag);
+  EXPECT_EQ(0u, client_control->channels[1].ipc_tag);
 
   uint32_t tag = 7654;
   CrossCallReturn answer;
diff --git a/sandbox/win/src/job_unittest.cc b/sandbox/win/src/job_unittest.cc
index d176367..7ed9cf0 100644
--- a/sandbox/win/src/job_unittest.cc
+++ b/sandbox/win/src/job_unittest.cc
@@ -16,7 +16,8 @@
   {
     // Create the job.
     Job job;
-    ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
+    ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+              job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
 
     // check if the job exists.
     HANDLE job_handle = ::OpenJobObjectW(GENERIC_ALL, FALSE,
@@ -30,7 +31,7 @@
   // Check if the job is destroyed when the object goes out of scope.
   HANDLE job_handle = ::OpenJobObjectW(GENERIC_ALL, FALSE, L"my_test_job_name");
   ASSERT_TRUE(job_handle == NULL);
-  ASSERT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
+  ASSERT_EQ(static_cast<DWORD>(ERROR_FILE_NOT_FOUND), ::GetLastError());
 }
 
 // Tests the method "Take".
@@ -40,7 +41,8 @@
   {
     // Create the job.
     Job job;
-    ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
+    ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+              job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
 
     job_handle = job.Take();
     ASSERT_TRUE(job_handle.IsValid());
@@ -61,7 +63,7 @@
   // Check if the jbo is really dead.
   job_handle_dup = ::OpenJobObjectW(GENERIC_ALL, FALSE, L"my_test_job_name");
   ASSERT_TRUE(job_handle_dup == NULL);
-  ASSERT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
+  ASSERT_EQ(static_cast<DWORD>(ERROR_FILE_NOT_FOUND), ::GetLastError());
 }
 
 // Tests the ui exceptions
@@ -71,8 +73,9 @@
   {
     // Create the job.
     Job job;
-    ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name",
-                                      JOB_OBJECT_UILIMIT_READCLIPBOARD, 0));
+    ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+              job.Init(JOB_LOCKDOWN, L"my_test_job_name",
+                       JOB_OBJECT_UILIMIT_READCLIPBOARD, 0));
 
     job_handle = job.Take();
     ASSERT_TRUE(job_handle.IsValid());
@@ -84,7 +87,7 @@
                                               &jbur, size, &size);
     ASSERT_TRUE(result);
 
-    ASSERT_EQ(jbur.UIRestrictionsClass & JOB_OBJECT_UILIMIT_READCLIPBOARD, 0);
+    ASSERT_EQ(0u, jbur.UIRestrictionsClass & JOB_OBJECT_UILIMIT_READCLIPBOARD);
     job_handle.Close();
   }
 
@@ -92,7 +95,8 @@
   {
     // Create the job.
     Job job;
-    ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
+    ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+              job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
 
     job_handle = job.Take();
     ASSERT_TRUE(job_handle.IsValid());
@@ -104,8 +108,8 @@
                                               &jbur, size, &size);
     ASSERT_TRUE(result);
 
-    ASSERT_EQ(jbur.UIRestrictionsClass & JOB_OBJECT_UILIMIT_READCLIPBOARD,
-              JOB_OBJECT_UILIMIT_READCLIPBOARD);
+    ASSERT_EQ(static_cast<DWORD>(JOB_OBJECT_UILIMIT_READCLIPBOARD),
+              jbur.UIRestrictionsClass & JOB_OBJECT_UILIMIT_READCLIPBOARD);
   }
 }
 
@@ -113,51 +117,59 @@
 TEST(JobTest, DoubleInit) {
   // Create the job.
   Job job;
-  ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
-  ASSERT_EQ(ERROR_ALREADY_INITIALIZED, job.Init(JOB_LOCKDOWN, L"test", 0, 0));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_ALREADY_INITIALIZED),
+            job.Init(JOB_LOCKDOWN, L"test", 0, 0));
 }
 
 // Tests the error case when we use a method and the object is not yet
 // initialized.
 TEST(JobTest, NoInit) {
   Job job;
-  ASSERT_EQ(ERROR_NO_DATA, job.UserHandleGrantAccess(NULL));
-  ASSERT_EQ(ERROR_NO_DATA, job.AssignProcessToJob(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_NO_DATA), job.UserHandleGrantAccess(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_NO_DATA), job.AssignProcessToJob(NULL));
   ASSERT_FALSE(job.Take().IsValid());
 }
 
 // Tests the initialization of the job with different security level.
 TEST(JobTest, SecurityLevel) {
   Job job1;
-  ASSERT_EQ(ERROR_SUCCESS, job1.Init(JOB_LOCKDOWN, L"job1", 0, 0));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            job1.Init(JOB_LOCKDOWN, L"job1", 0, 0));
 
   Job job2;
-  ASSERT_EQ(ERROR_SUCCESS, job2.Init(JOB_RESTRICTED, L"job2", 0, 0));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            job2.Init(JOB_RESTRICTED, L"job2", 0, 0));
 
   Job job3;
-  ASSERT_EQ(ERROR_SUCCESS, job3.Init(JOB_LIMITED_USER, L"job3", 0, 0));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            job3.Init(JOB_LIMITED_USER, L"job3", 0, 0));
 
   Job job4;
-  ASSERT_EQ(ERROR_SUCCESS, job4.Init(JOB_INTERACTIVE, L"job4", 0, 0));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            job4.Init(JOB_INTERACTIVE, L"job4", 0, 0));
 
   Job job5;
-  ASSERT_EQ(ERROR_SUCCESS, job5.Init(JOB_UNPROTECTED, L"job5", 0, 0));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            job5.Init(JOB_UNPROTECTED, L"job5", 0, 0));
 
   // JOB_NONE means we run without a job object so Init should fail.
   Job job6;
-  ASSERT_EQ(ERROR_BAD_ARGUMENTS, job6.Init(JOB_NONE, L"job6", 0, 0));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_BAD_ARGUMENTS),
+            job6.Init(JOB_NONE, L"job6", 0, 0));
 
   Job job7;
-  ASSERT_EQ(ERROR_BAD_ARGUMENTS, job7.Init(
-      static_cast<JobLevel>(JOB_NONE+1), L"job7", 0, 0));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_BAD_ARGUMENTS),
+            job7.Init(static_cast<JobLevel>(JOB_NONE + 1), L"job7", 0, 0));
 }
 
 // Tests the method "AssignProcessToJob".
 TEST(JobTest, ProcessInJob) {
   // Create the job.
   Job job;
-  ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_UNPROTECTED, L"job_test_process", 0,
-                                    0));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            job.Init(JOB_UNPROTECTED, L"job_test_process", 0, 0));
 
   BOOL result = FALSE;
 
@@ -168,7 +180,8 @@
                            &temp_process_info);
   ASSERT_TRUE(result);
   base::win::ScopedProcessInformation pi(temp_process_info);
-  ASSERT_EQ(ERROR_SUCCESS, job.AssignProcessToJob(pi.process_handle()));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            job.AssignProcessToJob(pi.process_handle()));
 
   // Get the job handle.
   base::win::ScopedHandle job_handle = job.Take();
@@ -181,8 +194,8 @@
                                        &jbpidl, size, &size);
   EXPECT_TRUE(result);
 
-  EXPECT_EQ(1, jbpidl.NumberOfAssignedProcesses);
-  EXPECT_EQ(1, jbpidl.NumberOfProcessIdsInList);
+  EXPECT_EQ(1u, jbpidl.NumberOfAssignedProcesses);
+  EXPECT_EQ(1u, jbpidl.NumberOfProcessIdsInList);
   EXPECT_EQ(pi.process_id(), jbpidl.ProcessIdList[0]);
 
   EXPECT_TRUE(::TerminateProcess(pi.process_handle(), 0));
diff --git a/sandbox/win/src/policy_low_level_unittest.cc b/sandbox/win/src/policy_low_level_unittest.cc
index 4081a58..88b9c439 100644
--- a/sandbox/win/src/policy_low_level_unittest.cc
+++ b/sandbox/win/src/policy_low_level_unittest.cc
@@ -392,7 +392,7 @@
   EXPECT_TRUE(pr_pipe.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_NORMAL, EQUAL));
 
   size_t opc1 = pr_pipe.GetOpcodeCount();
-  EXPECT_EQ(3, opc1);
+  EXPECT_EQ(3u, opc1);
 
   PolicyRule pr_dump(ASK_BROKER);
   EXPECT_TRUE(pr_dump.AddStringMatch(IF, 0, L"\\\\/?/?\\*\\Crash Reports\\*",
@@ -401,7 +401,7 @@
   EXPECT_TRUE(pr_dump.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_NORMAL, EQUAL));
 
   size_t opc2 = pr_dump.GetOpcodeCount();
-  EXPECT_EQ(4, opc2);
+  EXPECT_EQ(4u, opc2);
 
   PolicyRule pr_winexe(SIGNAL_ALARM);
   EXPECT_TRUE(pr_winexe.AddStringMatch(IF, 0, L"\\\\/?/?\\C:\\Windows\\*.exe",
@@ -409,7 +409,7 @@
   EXPECT_TRUE(pr_winexe.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_NORMAL, EQUAL));
 
   size_t opc3 = pr_winexe.GetOpcodeCount();
-  EXPECT_EQ(3, opc3);
+  EXPECT_EQ(3u, opc3);
 
   PolicyRule pr_adobe(GIVE_CACHED);
   EXPECT_TRUE(pr_adobe.AddStringMatch(IF, 0, L"c:\\adobe\\ver?.?\\",
@@ -417,14 +417,14 @@
   EXPECT_TRUE(pr_adobe.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_NORMAL, EQUAL));
 
   size_t opc4 = pr_adobe.GetOpcodeCount();
-  EXPECT_EQ(4, opc4);
+  EXPECT_EQ(4u, opc4);
 
   PolicyRule pr_none(GIVE_FIRST);
   EXPECT_TRUE(pr_none.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_READONLY, AND));
   EXPECT_TRUE(pr_none.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_SYSTEM, AND));
 
   size_t opc5 = pr_none.GetOpcodeCount();
-  EXPECT_EQ(2, opc5);
+  EXPECT_EQ(2u, opc5);
 
   PolicyGlobal* policy = MakePolicyMemory();
 
diff --git a/sandbox/win/src/policy_opcodes_unittest.cc b/sandbox/win/src/policy_opcodes_unittest.cc
index c999348..954aa445 100644
--- a/sandbox/win/src/policy_opcodes_unittest.cc
+++ b/sandbox/win/src/policy_opcodes_unittest.cc
@@ -122,7 +122,7 @@
   context.position = 1;
   context.options = kPolUseOREval;
   EXPECT_EQ(EVAL_TRUE, op5->Evaluate(&ppb1, 1, &context));
-  EXPECT_EQ(0, context.position);
+  EXPECT_EQ(0u, context.position);
   MatchContext context2;
   EXPECT_EQ(context2.options, context.options);
 }
@@ -280,7 +280,7 @@
                                                       kPolClearContext);
   ASSERT_NE(nullptr, op4);
   EXPECT_EQ(EVAL_TRUE, op4->Evaluate(&pp_tc1, 1, &mc1));
-  EXPECT_EQ(0, mc1.position);
+  EXPECT_EQ(0u, mc1.position);
 
   // Test that we can properly match the last part of the string
   PolicyOpcode* op4b = opcode_maker.MakeOpWStringMatch(0, txt4, kSeekToEnd,
@@ -288,7 +288,7 @@
                                                        kPolClearContext);
   ASSERT_NE(nullptr, op4b);
   EXPECT_EQ(EVAL_TRUE, op4b->Evaluate(&pp_tc1, 1, &mc1));
-  EXPECT_EQ(0, mc1.position);
+  EXPECT_EQ(0u, mc1.position);
 
   // Test matching 'jumps over' over the entire string. This is the
   // primitive we build '*' from.
@@ -296,7 +296,7 @@
                                                       CASE_SENSITIVE, kPolNone);
   ASSERT_NE(nullptr, op5);
   EXPECT_EQ(EVAL_TRUE, op5->Evaluate(&pp_tc1, 1, &mc1));
-  EXPECT_EQ(24, mc1.position);
+  EXPECT_EQ(24u, mc1.position);
 
   // Test that we don't match because it is not at the end of the string
   PolicyOpcode* op5b = opcode_maker.MakeOpWStringMatch(0, txt5, kSeekToEnd,
@@ -304,7 +304,7 @@
                                                        kPolNone);
   ASSERT_NE(nullptr, op5b);
   EXPECT_EQ(EVAL_FALSE, op5b->Evaluate(&pp_tc1, 1, &mc1));
-  EXPECT_EQ(24, mc1.position);
+  EXPECT_EQ(24u, mc1.position);
 
   // Test that we function if the string does not fit. In this case we
   // try to match 'the lazy dog' against 'he lazy dog'.
@@ -319,12 +319,12 @@
                                                       CASE_SENSITIVE, kPolNone);
   ASSERT_NE(nullptr, op7);
   EXPECT_EQ(EVAL_TRUE, op7->Evaluate(&pp_tc1, 1, &mc2));
-  EXPECT_EQ(37, mc2.position);
+  EXPECT_EQ(37u, mc2.position);
 
   // Trying to match again should fail since we are in the last char.
   // This also covers a couple of boundary conditions.
   EXPECT_EQ(EVAL_FALSE, op7->Evaluate(&pp_tc1, 1, &mc2));
-  EXPECT_EQ(37, mc2.position);
+  EXPECT_EQ(37u, mc2.position);
 }
 
 TEST(PolicyEngineTest, WCharOpcodes2) {
@@ -350,7 +350,7 @@
   ASSERT_NE(nullptr, op1i);
   EXPECT_EQ(EVAL_FALSE, op1s->Evaluate(&pp_tc1, 1, &mc1));
   EXPECT_EQ(EVAL_TRUE, op1i->Evaluate(&pp_tc1, 1, &mc1));
-  EXPECT_EQ(35, mc1.position);
+  EXPECT_EQ(35u, mc1.position);
 }
 
 TEST(PolicyEngineTest, ActionOpcodes) {
diff --git a/sandbox/win/src/policy_target_test.cc b/sandbox/win/src/policy_target_test.cc
index bb1f0b2b..d1a82e54 100644
--- a/sandbox/win/src/policy_target_test.cc
+++ b/sandbox/win/src/policy_target_test.cc
@@ -14,6 +14,10 @@
 #include "sandbox/win/tests/common/controller.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if defined(OS_WIN)
+#include "base/win/win_util.h"
+#endif
+
 namespace sandbox {
 
 #define BINDNTDLL(name) \
@@ -256,9 +260,10 @@
   if (result == SBOX_ALL_OK)
     target.Set(temp_process_info);
 
-  EXPECT_EQ(1, ::ResumeThread(target.thread_handle()));
+  EXPECT_EQ(1u, ::ResumeThread(target.thread_handle()));
 
-  EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(target.process_handle(), 2000));
+  EXPECT_EQ(static_cast<DWORD>(WAIT_TIMEOUT),
+            ::WaitForSingleObject(target.process_handle(), 2000));
 
   EXPECT_NE(::GetThreadDesktop(target.thread_id()),
             ::GetThreadDesktop(::GetCurrentThreadId()));
@@ -319,9 +324,10 @@
   if (result == SBOX_ALL_OK)
     target.Set(temp_process_info);
 
-  EXPECT_EQ(1, ::ResumeThread(target.thread_handle()));
+  EXPECT_EQ(1u, ::ResumeThread(target.thread_handle()));
 
-  EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(target.process_handle(), 2000));
+  EXPECT_EQ(static_cast<DWORD>(WAIT_TIMEOUT),
+            ::WaitForSingleObject(target.process_handle(), 2000));
 
   EXPECT_NE(::GetThreadDesktop(target.thread_id()),
             ::GetThreadDesktop(::GetCurrentThreadId()));
@@ -382,8 +388,7 @@
   base::string16 arguments(L"\"");
   arguments += prog_name;
   arguments += L"\" -child 0 shared_memory_handle ";
-  arguments += base::UintToString16(
-      reinterpret_cast<unsigned int>(shared_handle));
+  arguments += base::UintToString16(base::win::HandleToUint32(shared_handle));
 
   // Launch the app.
   ResultCode result = SBOX_ALL_OK;
@@ -399,9 +404,9 @@
   if (result == SBOX_ALL_OK)
     target.Set(temp_process_info);
 
-  EXPECT_EQ(1, ::ResumeThread(target.thread_handle()));
+  EXPECT_EQ(1u, ::ResumeThread(target.thread_handle()));
 
-  EXPECT_EQ(WAIT_TIMEOUT,
+  EXPECT_EQ(static_cast<DWORD>(WAIT_TIMEOUT),
             ::WaitForSingleObject(target.process_handle(), 2000));
 
   EXPECT_TRUE(::TerminateProcess(target.process_handle(), 0));
diff --git a/sandbox/win/src/resolver_64.cc b/sandbox/win/src/resolver_64.cc
index 8b2cc53c..f1f135ea 100644
--- a/sandbox/win/src/resolver_64.cc
+++ b/sandbox/win/src/resolver_64.cc
@@ -12,34 +12,25 @@
 
 namespace {
 
-const BYTE kPushRax = 0x50;
 const USHORT kMovRax = 0xB848;
-const ULONG kMovRspRax = 0x24048948;
-const BYTE kRetNp = 0xC3;
+const USHORT kJmpRax = 0xe0ff;
 
 #pragma pack(push, 1)
 struct InternalThunk {
   // This struct contains roughly the following code:
-  // 00 50                    push  rax
   // 01 48b8f0debc9a78563412  mov   rax,123456789ABCDEF0h
-  // 0b 48890424              mov   qword ptr [rsp],rax
-  // 0f c3                    ret
+  // ff e0                    jmp   rax
   //
-  // The code modifies rax, but that should not be an issue for the common
-  // calling conventions.
+  // The code modifies rax, but that's fine for x64 ABI.
 
   InternalThunk() {
-    push_rax = kPushRax;
     mov_rax = kMovRax;
+    jmp_rax = kJmpRax;
     interceptor_function = 0;
-    mov_rsp_rax = kMovRspRax;
-    ret = kRetNp;
   };
-  BYTE push_rax;        // = 50
   USHORT mov_rax;       // = 48 B8
   ULONG_PTR interceptor_function;
-  ULONG mov_rsp_rax;    // = 48 89 04 24
-  BYTE ret;             // = C3
+  USHORT jmp_rax;  // = ff e0
 };
 #pragma pack(pop)
 
diff --git a/sandbox/win/src/restricted_token_unittest.cc b/sandbox/win/src/restricted_token_unittest.cc
index fca1a07..b11948e 100644
--- a/sandbox/win/src/restricted_token_unittest.cc
+++ b/sandbox/win/src/restricted_token_unittest.cc
@@ -19,7 +19,8 @@
 // Tests the initializatioin with an invalid token handle.
 TEST(RestrictedTokenTest, InvalidHandle) {
   RestrictedToken token;
-  ASSERT_EQ(ERROR_INVALID_HANDLE, token.Init(reinterpret_cast<HANDLE>(0x5555)));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_INVALID_HANDLE),
+            token.Init(reinterpret_cast<HANDLE>(0x5555)));
 }
 
 // Tests the initialization with NULL as parameter.
@@ -36,13 +37,13 @@
 
   // Create the token using the current token.
   RestrictedToken token_default;
-  ASSERT_EQ(ERROR_SUCCESS, token_default.Init(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token_default.Init(NULL));
 
   // Get the handle to the restricted token.
 
   base::win::ScopedHandle restricted_token_handle;
-  ASSERT_EQ(ERROR_SUCCESS,
-      token_default.GetRestrictedToken(&restricted_token_handle));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token_default.GetRestrictedToken(&restricted_token_handle));
 
   ATL::CAccessToken restricted_token;
   restricted_token.Attach(restricted_token_handle.Take());
@@ -78,13 +79,14 @@
 
   // Create the token using the current token.
   RestrictedToken token;
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(access_token.GetHandle()));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.Init(access_token.GetHandle()));
 
   // Get the handle to the restricted token.
 
   base::win::ScopedHandle restricted_token_handle;
-  ASSERT_EQ(ERROR_SUCCESS,
-      token.GetRestrictedToken(&restricted_token_handle));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedToken(&restricted_token_handle));
 
   ATL::CAccessToken restricted_token;
   restricted_token.Attach(restricted_token_handle.Take());
@@ -101,13 +103,14 @@
 // Verifies that the token created by the object are valid.
 TEST(RestrictedTokenTest, ResultToken) {
   RestrictedToken token;
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(NULL));
 
-  ASSERT_EQ(ERROR_SUCCESS,
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
             token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
 
   base::win::ScopedHandle restricted_token;
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&restricted_token));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedToken(&restricted_token));
 
   ASSERT_TRUE(::IsTokenRestricted(restricted_token.Get()));
 
@@ -122,8 +125,8 @@
   ASSERT_EQ(type, TokenPrimary);
 
   base::win::ScopedHandle impersonation_token;
-  ASSERT_EQ(ERROR_SUCCESS,
-      token.GetRestrictedTokenForImpersonation(&impersonation_token));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedTokenForImpersonation(&impersonation_token));
 
   ASSERT_TRUE(::IsTokenRestricted(impersonation_token.Get()));
 
@@ -139,13 +142,14 @@
 // Verifies that the token created has "Restricted" in its default dacl.
 TEST(RestrictedTokenTest, DefaultDacl) {
   RestrictedToken token;
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(NULL));
 
-  ASSERT_EQ(ERROR_SUCCESS,
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
             token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
 
   base::win::ScopedHandle handle;
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&handle));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedToken(&handle));
 
   ATL::CAccessToken restricted_token;
   restricted_token.Attach(handle.Take());
@@ -174,9 +178,11 @@
   RestrictedToken token;
   base::win::ScopedHandle token_handle;
 
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
-  ASSERT_EQ(ERROR_SUCCESS, token.AddSidForDenyOnly(Sid(WinWorldSid)));
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.AddSidForDenyOnly(Sid(WinWorldSid)));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
   restricted_token.Attach(token_handle.Take());
@@ -190,7 +196,7 @@
 
   for (unsigned int i = 0; i < sids.GetCount(); i++) {
     if (ATL::Sids::World() == sids[i]) {
-      ASSERT_EQ(SE_GROUP_USE_FOR_DENY_ONLY,
+      ASSERT_EQ(static_cast<DWORD>(SE_GROUP_USE_FOR_DENY_ONLY),
                 attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
     }
   }
@@ -201,9 +207,11 @@
   RestrictedToken token;
   base::win::ScopedHandle token_handle;
 
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
-  ASSERT_EQ(ERROR_SUCCESS, token.AddAllSidsForDenyOnly(NULL));
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.AddAllSidsForDenyOnly(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
   restricted_token.Attach(token_handle.Take());
@@ -219,7 +227,7 @@
   for (unsigned int i = 0; i < sids.GetCount(); i++) {
     if ((attributes[i] & SE_GROUP_LOGON_ID) == 0 &&
         (attributes[i] & SE_GROUP_INTEGRITY) == 0) {
-      ASSERT_EQ(SE_GROUP_USE_FOR_DENY_ONLY,
+      ASSERT_EQ(static_cast<DWORD>(SE_GROUP_USE_FOR_DENY_ONLY),
                 attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
     }
   }
@@ -233,9 +241,11 @@
   std::vector<Sid> sids_exception;
   sids_exception.push_back(Sid(WinWorldSid));
 
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
-  ASSERT_EQ(ERROR_SUCCESS, token.AddAllSidsForDenyOnly(&sids_exception));
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.AddAllSidsForDenyOnly(&sids_exception));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
   restricted_token.Attach(token_handle.Take());
@@ -252,9 +262,9 @@
     if ((attributes[i] & SE_GROUP_LOGON_ID) == 0 &&
         (attributes[i] & SE_GROUP_INTEGRITY) == 0) {
       if (ATL::Sids::World() == sids[i]) {
-        ASSERT_EQ(NULL, attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
+        ASSERT_EQ(0u, attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
       } else {
-        ASSERT_EQ(SE_GROUP_USE_FOR_DENY_ONLY,
+        ASSERT_EQ(static_cast<DWORD>(SE_GROUP_USE_FOR_DENY_ONLY),
                   attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
       }
     }
@@ -266,9 +276,10 @@
   RestrictedToken token;
   base::win::ScopedHandle token_handle;
 
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
-  ASSERT_EQ(ERROR_SUCCESS, token.AddUserSidForDenyOnly());
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.AddUserSidForDenyOnly());
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
   restricted_token.Attach(token_handle.Take());
@@ -285,7 +296,7 @@
 
   for (unsigned int i = 0; i < sids.GetCount(); ++i) {
     if (user_sid == sids[i]) {
-      ASSERT_EQ(SE_GROUP_USE_FOR_DENY_ONLY,
+      ASSERT_EQ(static_cast<DWORD>(SE_GROUP_USE_FOR_DENY_ONLY),
                 attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
     }
   }
@@ -305,9 +316,11 @@
 
   RestrictedToken token;
   base::win::ScopedHandle token_handle;
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(access_token.GetHandle()));
-  ASSERT_EQ(ERROR_SUCCESS, token.AddUserSidForDenyOnly());
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.Init(access_token.GetHandle()));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.AddUserSidForDenyOnly());
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
   restricted_token.Attach(token_handle.Take());
@@ -324,7 +337,7 @@
 
   for (unsigned int i = 0; i < sids.GetCount(); ++i) {
     if (user_sid == sids[i]) {
-      ASSERT_EQ(SE_GROUP_USE_FOR_DENY_ONLY,
+      ASSERT_EQ(static_cast<DWORD>(SE_GROUP_USE_FOR_DENY_ONLY),
                 attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
     }
   }
@@ -335,9 +348,10 @@
   RestrictedToken token;
   base::win::ScopedHandle token_handle;
 
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
-  ASSERT_EQ(ERROR_SUCCESS, token.DeleteAllPrivileges(NULL));
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.DeleteAllPrivileges(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
   restricted_token.Attach(token_handle.Take());
@@ -345,7 +359,7 @@
   ATL::CTokenPrivileges privileges;
   ASSERT_TRUE(restricted_token.GetPrivileges(&privileges));
 
-  ASSERT_EQ(0, privileges.GetCount());
+  ASSERT_EQ(0u, privileges.GetCount());
 }
 
 // Tests the method DeleteAllPrivileges with an exception list.
@@ -356,9 +370,11 @@
   std::vector<base::string16> exceptions;
   exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
 
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
-  ASSERT_EQ(ERROR_SUCCESS, token.DeleteAllPrivileges(&exceptions));
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.DeleteAllPrivileges(&exceptions));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
   restricted_token.Attach(token_handle.Take());
@@ -371,7 +387,7 @@
   privileges.GetNamesAndAttributes(&privilege_names,
                                    &privilege_name_attributes);
 
-  ASSERT_EQ(1, privileges.GetCount());
+  ASSERT_EQ(1u, privileges.GetCount());
 
   for (unsigned int i = 0; i < privileges.GetCount(); ++i) {
     ASSERT_EQ(privilege_names[i], SE_CHANGE_NOTIFY_NAME);
@@ -383,9 +399,11 @@
   RestrictedToken token;
   base::win::ScopedHandle token_handle;
 
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
-  ASSERT_EQ(ERROR_SUCCESS, token.DeletePrivilege(SE_CHANGE_NOTIFY_NAME));
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.DeletePrivilege(SE_CHANGE_NOTIFY_NAME));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
   restricted_token.Attach(token_handle.Take());
@@ -421,7 +439,7 @@
   delete[] memory;
 
   if (count >= 0)
-    ASSERT_EQ(count, atl_groups.GetCount());
+    ASSERT_EQ(static_cast<unsigned>(count), atl_groups.GetCount());
 
   ATL::CSid::CSidArray sids;
   ATL::CAtlArray<DWORD> attributes;
@@ -443,10 +461,11 @@
   RestrictedToken token;
   base::win::ScopedHandle token_handle;
 
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
-  ASSERT_EQ(ERROR_SUCCESS,
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
             token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
   restricted_token.Attach(token_handle.Take());
@@ -459,9 +478,11 @@
   RestrictedToken token;
   base::win::ScopedHandle token_handle;
 
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
-  ASSERT_EQ(ERROR_SUCCESS, token.AddRestrictingSidCurrentUser());
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.AddRestrictingSidCurrentUser());
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
   restricted_token.Attach(token_handle.Take());
@@ -485,9 +506,12 @@
 
   RestrictedToken token;
   base::win::ScopedHandle token_handle;
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(access_token.GetHandle()));
-  ASSERT_EQ(ERROR_SUCCESS, token.AddRestrictingSidCurrentUser());
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.Init(access_token.GetHandle()));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.AddRestrictingSidCurrentUser());
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
   restricted_token.Attach(token_handle.Take());
@@ -502,9 +526,11 @@
   RestrictedToken token;
   base::win::ScopedHandle token_handle;
 
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
-  ASSERT_EQ(ERROR_SUCCESS, token.AddRestrictingSidLogonSession());
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.AddRestrictingSidLogonSession());
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
   restricted_token.Attach(token_handle.Take());
@@ -519,12 +545,15 @@
   RestrictedToken token;
   base::win::ScopedHandle token_handle;
 
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
-  ASSERT_EQ(ERROR_SUCCESS, token.AddRestrictingSidCurrentUser());
-  ASSERT_EQ(ERROR_SUCCESS, token.AddRestrictingSidLogonSession());
-  ASSERT_EQ(ERROR_SUCCESS,
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.AddRestrictingSidCurrentUser());
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.AddRestrictingSidLogonSession());
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
             token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
   restricted_token.Attach(token_handle.Take());
@@ -543,7 +572,7 @@
   ATL::CTokenGroups atl_groups(*groups);
   delete[] memory;
 
-  ASSERT_EQ(3, atl_groups.GetCount());
+  ASSERT_EQ(3u, atl_groups.GetCount());
 }
 
 // Tests the method "AddRestrictingSidAllSids".
@@ -551,9 +580,11 @@
   RestrictedToken token;
   base::win::ScopedHandle token_handle;
 
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
-  ASSERT_EQ(ERROR_SUCCESS, token.AddRestrictingSidAllSids());
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.AddRestrictingSidAllSids());
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+            token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
   restricted_token.Attach(token_handle.Take());
@@ -581,9 +612,9 @@
 // Checks the error code when the object is initialized twice.
 TEST(RestrictedTokenTest, DoubleInit) {
   RestrictedToken token;
-  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(NULL));
 
-  ASSERT_EQ(ERROR_ALREADY_INITIALIZED, token.Init(NULL));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_ALREADY_INITIALIZED), token.Init(NULL));
 }
 
 }  // namespace sandbox
diff --git a/sandbox/win/src/sandbox_policy_base.cc b/sandbox/win/src/sandbox_policy_base.cc
index 17f52c5..2b82f106 100644
--- a/sandbox/win/src/sandbox_policy_base.cc
+++ b/sandbox/win/src/sandbox_policy_base.cc
@@ -635,7 +635,7 @@
   return appcontainer_list_.get();
 }
 
-const PSID PolicyBase::GetLowBoxSid() const {
+PSID PolicyBase::GetLowBoxSid() const {
   return lowbox_sid_;
 }
 
diff --git a/sandbox/win/src/sandbox_policy_base.h b/sandbox/win/src/sandbox_policy_base.h
index a461bd71..0068553 100644
--- a/sandbox/win/src/sandbox_policy_base.h
+++ b/sandbox/win/src/sandbox_policy_base.h
@@ -90,7 +90,7 @@
 
   const AppContainerAttributes* GetAppContainer() const;
 
-  const PSID GetLowBoxSid() const;
+  PSID GetLowBoxSid() const;
 
   // Adds a target process to the internal list of targets. Internally a
   // call to TargetProcess::Init() is issued.
diff --git a/sandbox/win/src/service_resolver_64.cc b/sandbox/win/src/service_resolver_64.cc
index c0e684c..8dcea7d 100644
--- a/sandbox/win/src/service_resolver_64.cc
+++ b/sandbox/win/src/service_resolver_64.cc
@@ -139,9 +139,9 @@
                                      void* thunk_storage,
                                      size_t storage_bytes,
                                      size_t* storage_used) {
-  NTSTATUS ret = Init(target_module, interceptor_module, target_name,
-                      interceptor_name, interceptor_entry_point,
-                      thunk_storage, storage_bytes);
+  NTSTATUS ret =
+      Init(target_module, interceptor_module, target_name, interceptor_name,
+           interceptor_entry_point, thunk_storage, storage_bytes);
   if (!NT_SUCCESS(ret))
     return ret;
 
@@ -213,7 +213,7 @@
                                             void* remote_thunk) {
   // Patch the original code.
   ServiceEntry local_service;
-  DCHECK_NT(GetInternalThunkSize() >= sizeof(local_service));
+  DCHECK_NT(GetInternalThunkSize() <= sizeof(local_service));
   if (!SetInternalThunk(&local_service, sizeof(local_service), NULL,
                         interceptor_))
     return STATUS_UNSUCCESSFUL;
diff --git a/sandbox/win/src/threadpool_unittest.cc b/sandbox/win/src/threadpool_unittest.cc
index f4398108..4f3b0df 100644
--- a/sandbox/win/src/threadpool_unittest.cc
+++ b/sandbox/win/src/threadpool_unittest.cc
@@ -19,22 +19,22 @@
 TEST(IPCTest, ThreadPoolRegisterTest1) {
   Win2kThreadPool thread_pool;
 
-  EXPECT_EQ(0, thread_pool.OutstandingWaits());
+  EXPECT_EQ(0u, thread_pool.OutstandingWaits());
 
   HANDLE event1 = ::CreateEventW(NULL, FALSE, FALSE, NULL);
   HANDLE event2 = ::CreateEventW(NULL, FALSE, FALSE, NULL);
 
   uint32 context = 0;
   EXPECT_FALSE(thread_pool.RegisterWait(0, event1, EmptyCallBack, &context));
-  EXPECT_EQ(0, thread_pool.OutstandingWaits());
+  EXPECT_EQ(0u, thread_pool.OutstandingWaits());
 
   EXPECT_TRUE(thread_pool.RegisterWait(this, event1, EmptyCallBack, &context));
-  EXPECT_EQ(1, thread_pool.OutstandingWaits());
+  EXPECT_EQ(1u, thread_pool.OutstandingWaits());
   EXPECT_TRUE(thread_pool.RegisterWait(this, event2, EmptyCallBack, &context));
-  EXPECT_EQ(2, thread_pool.OutstandingWaits());
+  EXPECT_EQ(2u, thread_pool.OutstandingWaits());
 
   EXPECT_TRUE(thread_pool.UnRegisterWaits(this));
-  EXPECT_EQ(0, thread_pool.OutstandingWaits());
+  EXPECT_EQ(0u, thread_pool.OutstandingWaits());
 
   EXPECT_EQ(TRUE, ::CloseHandle(event1));
   EXPECT_EQ(TRUE, ::CloseHandle(event2));
@@ -52,17 +52,17 @@
   uint32 c2 = 0;
 
   EXPECT_TRUE(thread_pool.RegisterWait(&c1, event1, EmptyCallBack, &context));
-  EXPECT_EQ(1, thread_pool.OutstandingWaits());
+  EXPECT_EQ(1u, thread_pool.OutstandingWaits());
   EXPECT_TRUE(thread_pool.RegisterWait(&c2, event2, EmptyCallBack, &context));
-  EXPECT_EQ(2, thread_pool.OutstandingWaits());
+  EXPECT_EQ(2u, thread_pool.OutstandingWaits());
 
   EXPECT_TRUE(thread_pool.UnRegisterWaits(&c2));
-  EXPECT_EQ(1, thread_pool.OutstandingWaits());
+  EXPECT_EQ(1u, thread_pool.OutstandingWaits());
   EXPECT_TRUE(thread_pool.UnRegisterWaits(&c2));
-  EXPECT_EQ(1, thread_pool.OutstandingWaits());
+  EXPECT_EQ(1u, thread_pool.OutstandingWaits());
 
   EXPECT_TRUE(thread_pool.UnRegisterWaits(&c1));
-  EXPECT_EQ(0, thread_pool.OutstandingWaits());
+  EXPECT_EQ(0u, thread_pool.OutstandingWaits());
 
   EXPECT_EQ(TRUE, ::CloseHandle(event1));
   EXPECT_EQ(TRUE, ::CloseHandle(event2));
@@ -83,9 +83,10 @@
   EXPECT_EQ(WAIT_OBJECT_0, ::SignalObjectAndWait(event1, event2, 5000, FALSE));
 
   EXPECT_TRUE(thread_pool.UnRegisterWaits(this));
-  EXPECT_EQ(0, thread_pool.OutstandingWaits());
+  EXPECT_EQ(0u, thread_pool.OutstandingWaits());
 
-  EXPECT_EQ(WAIT_TIMEOUT, ::SignalObjectAndWait(event1, event2, 1000, FALSE));
+  EXPECT_EQ(static_cast<DWORD>(WAIT_TIMEOUT),
+            ::SignalObjectAndWait(event1, event2, 1000, FALSE));
 
   EXPECT_EQ(TRUE, ::CloseHandle(event1));
   EXPECT_EQ(TRUE, ::CloseHandle(event2));
diff --git a/sandbox/win/src/win_utils_unittest.cc b/sandbox/win/src/win_utils_unittest.cc
index 15da51b..fb72eb33 100644
--- a/sandbox/win/src/win_utils_unittest.cc
+++ b/sandbox/win/src/win_utils_unittest.cc
@@ -22,13 +22,16 @@
   ASSERT_TRUE(::DeleteFile(my_folder));
   ASSERT_TRUE(::CreateDirectory(my_folder, NULL));
 
-  EXPECT_EQ(ERROR_NOT_A_REPARSE_POINT, IsReparsePoint(my_folder));
+  EXPECT_EQ(static_cast<DWORD>(ERROR_NOT_A_REPARSE_POINT),
+            IsReparsePoint(my_folder));
 
   base::string16 not_found = base::string16(my_folder) + L"\\foo\\bar";
-  EXPECT_EQ(ERROR_NOT_A_REPARSE_POINT, IsReparsePoint(not_found));
+  EXPECT_EQ(static_cast<DWORD>(ERROR_NOT_A_REPARSE_POINT),
+            IsReparsePoint(not_found));
 
   base::string16 new_file = base::string16(my_folder) + L"\\foo";
-  EXPECT_EQ(ERROR_NOT_A_REPARSE_POINT, IsReparsePoint(new_file));
+  EXPECT_EQ(static_cast<DWORD>(ERROR_NOT_A_REPARSE_POINT),
+            IsReparsePoint(new_file));
 
   // Replace the directory with a reparse point to %temp%.
   HANDLE dir = ::CreateFile(my_folder, FILE_ALL_ACCESS,
@@ -39,7 +42,7 @@
   base::string16 temp_dir_nt = base::string16(L"\\??\\") + temp_directory;
   EXPECT_TRUE(SetReparsePoint(dir, temp_dir_nt.c_str()));
 
-  EXPECT_EQ(ERROR_SUCCESS, IsReparsePoint(new_file));
+  EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), IsReparsePoint(new_file));
 
   EXPECT_TRUE(DeleteReparsePoint(dir));
   EXPECT_TRUE(::CloseHandle(dir));
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 1e688f58..796f4e7 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -225,6 +225,14 @@
 #ifndef    SK_IGNORE_GPU_DITHER
 #   define SK_IGNORE_GPU_DITHER
 #endif
+
+#ifndef    SK_SUPPORT_LEGACY_HQ_DOWNSAMPLING
+#   define SK_SUPPORT_LEGACY_HQ_DOWNSAMPLING
+#endif
+
+#ifndef    SK_SUPPORT_LEGACY_HAIR_IGNORES_CAPS
+#   define SK_SUPPORT_LEGACY_HAIR_IGNORES_CAPS
+#endif
 ///////////////////////// Imported from BUILD.gn and skia_common.gypi
 
 /* In some places Skia can use static initializers for global initialization,
@@ -237,6 +245,10 @@
  */
 #define SK_DISABLE_OFFSETIMAGEFILTER_OPTIMIZATION
 
+/* Disable tight bounds for saveLayer offscreens in Skia until rebaselining is done.
+ */
+#define SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
+
 /* This flag forces Skia not to use typographic metrics with GDI.
  */
 #define SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
diff --git a/storage/browser/fileapi/file_system_dir_url_request_job.cc b/storage/browser/fileapi/file_system_dir_url_request_job.cc
index c0537735..c99454d 100644
--- a/storage/browser/fileapi/file_system_dir_url_request_job.cc
+++ b/storage/browser/fileapi/file_system_dir_url_request_job.cc
@@ -100,8 +100,8 @@
     return;
   }
   file_system_context_->operation_runner()->ReadDirectory(
-      url_,
-      base::Bind(&FileSystemDirURLRequestJob::DidReadDirectory, this));
+      url_, base::Bind(&FileSystemDirURLRequestJob::DidReadDirectory,
+                       weak_factory_.GetWeakPtr()));
 }
 
 void FileSystemDirURLRequestJob::DidAttemptAutoMount(base::File::Error result) {
@@ -159,7 +159,8 @@
   file_system_context_->operation_runner()->GetMetadata(
       url, FileSystemOperation::GET_METADATA_FIELD_SIZE |
                FileSystemOperation::GET_METADATA_FIELD_LAST_MODIFIED,
-      base::Bind(&FileSystemDirURLRequestJob::DidGetMetadata, this, index));
+      base::Bind(&FileSystemDirURLRequestJob::DidGetMetadata,
+                 weak_factory_.GetWeakPtr(), index));
 }
 
 void FileSystemDirURLRequestJob::DidGetMetadata(
diff --git a/storage/browser/fileapi/file_system_dir_url_request_job.h b/storage/browser/fileapi/file_system_dir_url_request_job.h
index 93fdd1fe..57b6904e 100644
--- a/storage/browser/fileapi/file_system_dir_url_request_job.h
+++ b/storage/browser/fileapi/file_system_dir_url_request_job.h
@@ -29,6 +29,8 @@
       const std::string& storage_domain,
       FileSystemContext* file_system_context);
 
+  ~FileSystemDirURLRequestJob() override;
+
   // URLRequestJob methods:
   void Start() override;
   void Kill() override;
@@ -43,8 +45,6 @@
  private:
   class CallbackDispatcher;
 
-  ~FileSystemDirURLRequestJob() override;
-
   void StartAsync();
   void DidAttemptAutoMount(base::File::Error result);
   void DidReadDirectory(base::File::Error result,
diff --git a/storage/browser/fileapi/file_system_operation_impl.cc b/storage/browser/fileapi/file_system_operation_impl.cc
index b6a6997..7cc26c0 100644
--- a/storage/browser/fileapi/file_system_operation_impl.cc
+++ b/storage/browser/fileapi/file_system_operation_impl.cc
@@ -4,6 +4,8 @@
 
 #include "storage/browser/fileapi/file_system_operation_impl.h"
 
+#include <limits>
+
 #include "base/bind.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
@@ -198,7 +200,8 @@
                  weak_factory_.GetWeakPtr(), url, callback));
 }
 
-void FileSystemOperationImpl::Truncate(const FileSystemURL& url, int64 length,
+void FileSystemOperationImpl::Truncate(const FileSystemURL& url,
+                                       int64_t length,
                                        const StatusCallback& callback) {
   DCHECK(SetPendingOperationType(kOperationTruncate));
 
@@ -393,7 +396,8 @@
       !file_system_context()->GetQuotaUtil(url.type())) {
     // If we don't have the quota manager or the requested filesystem type
     // does not support quota, we should be able to let it go.
-    operation_context_->set_allowed_bytes_growth(kint64max);
+    operation_context_->set_allowed_bytes_growth(
+        std::numeric_limits<int64_t>::max());
     task.Run();
     return;
   }
@@ -411,8 +415,8 @@
     const base::Closure& task,
     const base::Closure& error_callback,
     storage::QuotaStatusCode status,
-    int64 usage,
-    int64 quota) {
+    int64_t usage,
+    int64_t quota) {
   if (status != storage::kQuotaStatusOk) {
     LOG(WARNING) << "Got unexpected quota error : " << status;
     error_callback.Run();
@@ -483,7 +487,7 @@
 
 void FileSystemOperationImpl::DoTruncate(const FileSystemURL& url,
                                          const StatusCallback& callback,
-                                         int64 length) {
+                                         int64_t length) {
   async_file_util_->Truncate(
       operation_context_.Pass(), url, length,
       base::Bind(&FileSystemOperationImpl::DidFinishOperation,
@@ -572,7 +576,7 @@
     const FileSystemURL& url,
     const WriteCallback& write_callback,
     base::File::Error rv,
-    int64 bytes,
+    int64_t bytes,
     FileWriterDelegate::WriteProgressStatus write_status) {
   const bool complete = (
       write_status != FileWriterDelegate::SUCCESS_IO_PENDING);
diff --git a/storage/browser/fileapi/file_system_operation_impl.h b/storage/browser/fileapi/file_system_operation_impl.h
index 26a434e..5638cca 100644
--- a/storage/browser/fileapi/file_system_operation_impl.h
+++ b/storage/browser/fileapi/file_system_operation_impl.h
@@ -5,6 +5,8 @@
 #ifndef STORAGE_BROWSER_FILEAPI_FILE_SYSTEM_OPERATION_IMPL_H_
 #define STORAGE_BROWSER_FILEAPI_FILE_SYSTEM_OPERATION_IMPL_H_
 
+#include <stdint.h>
+
 #include <vector>
 
 #include "base/memory/ref_counted.h"
@@ -65,7 +67,7 @@
              scoped_ptr<net::URLRequest> blob_request,
              const WriteCallback& callback) override;
   void Truncate(const FileSystemURL& url,
-                int64 length,
+                int64_t length,
                 const StatusCallback& callback) override;
   void TouchFile(const FileSystemURL& url,
                  const base::Time& last_access_time,
@@ -123,8 +125,8 @@
   void DidGetUsageAndQuotaAndRunTask(const base::Closure& task,
                                      const base::Closure& error_callback,
                                      storage::QuotaStatusCode status,
-                                     int64 usage,
-                                     int64 quota);
+                                     int64_t usage,
+                                     int64_t quota);
 
   // The 'body' methods that perform the actual work (i.e. posting the
   // file task on proxy_) after the quota check.
@@ -147,7 +149,8 @@
                            const FileSystemURL& dest,
                            const StatusCallback& callback);
   void DoTruncate(const FileSystemURL& url,
-                  const StatusCallback& callback, int64 length);
+                  const StatusCallback& callback,
+                  int64_t length);
   void DoOpenFile(const FileSystemURL& url,
                   const OpenFileCallback& callback, int file_flags);
 
@@ -175,7 +178,7 @@
   void DidWrite(const FileSystemURL& url,
                 const WriteCallback& callback,
                 base::File::Error rv,
-                int64 bytes,
+                int64_t bytes,
                 FileWriterDelegate::WriteProgressStatus write_status);
 
   // Used only for internal assertions.
diff --git a/storage/browser/fileapi/sandbox_file_stream_writer.cc b/storage/browser/fileapi/sandbox_file_stream_writer.cc
index d6895c8..de950fec 100644
--- a/storage/browser/fileapi/sandbox_file_stream_writer.cc
+++ b/storage/browser/fileapi/sandbox_file_stream_writer.cc
@@ -4,6 +4,8 @@
 
 #include "storage/browser/fileapi/sandbox_file_stream_writer.h"
 
+#include <limits>
+
 #include "base/files/file_util_proxy.h"
 #include "base/sequenced_task_runner.h"
 #include "base/trace_event/trace_event.h"
@@ -24,14 +26,14 @@
 // |file_offset| < |file_size|) to make the remaining quota calculation easier.
 // Specifically this widens the quota for overlapping range (so that we can
 // simply compare written bytes against the adjusted quota).
-int64 AdjustQuotaForOverlap(int64 quota,
-                            int64 file_offset,
-                            int64 file_size) {
+int64_t AdjustQuotaForOverlap(int64_t quota,
+                              int64_t file_offset,
+                              int64_t file_size) {
   DCHECK_LE(file_offset, file_size);
   if (quota < 0)
     quota = 0;
-  int64 overlap = file_size - file_offset;
-  if (kint64max - overlap > quota)
+  int64_t overlap = file_size - file_offset;
+  if (std::numeric_limits<int64_t>::max() - overlap > quota)
     quota += overlap;
   return quota;
 }
@@ -41,7 +43,7 @@
 SandboxFileStreamWriter::SandboxFileStreamWriter(
     FileSystemContext* file_system_context,
     const FileSystemURL& url,
-    int64 initial_offset,
+    int64_t initial_offset,
     const UpdateObserverList& observers)
     : file_system_context_(file_system_context),
       url_(url),
@@ -51,7 +53,7 @@
       total_bytes_written_(0),
       allowed_bytes_to_write_(0),
       has_pending_operation_(false),
-      default_quota_(kint64max),
+      default_quota_(std::numeric_limits<int64_t>::max()),
       weak_factory_(this) {
   DCHECK(url_.is_valid());
 }
@@ -166,8 +168,8 @@
 void SandboxFileStreamWriter::DidGetUsageAndQuota(
     const net::CompletionCallback& callback,
     storage::QuotaStatusCode status,
-    int64 usage,
-    int64 quota) {
+    int64_t usage,
+    int64_t quota) {
   if (CancelIfRequested())
     return;
   if (status != storage::kQuotaStatusOk) {
diff --git a/storage/browser/fileapi/sandbox_file_stream_writer.h b/storage/browser/fileapi/sandbox_file_stream_writer.h
index 2e62421..91f8b0a0 100644
--- a/storage/browser/fileapi/sandbox_file_stream_writer.h
+++ b/storage/browser/fileapi/sandbox_file_stream_writer.h
@@ -5,8 +5,11 @@
 #ifndef STORAGE_BROWSER_FILEAPI_SANDBOX_FILE_STREAM_WRITER_H_
 #define STORAGE_BROWSER_FILEAPI_SANDBOX_FILE_STREAM_WRITER_H_
 
+#include <stdint.h>
+
 #include "base/files/file.h"
 #include "base/files/file_path.h"
+#include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "storage/browser/blob/shareable_file_reference.h"
 #include "storage/browser/fileapi/file_stream_writer.h"
@@ -28,7 +31,7 @@
  public:
   SandboxFileStreamWriter(FileSystemContext* file_system_context,
                           const FileSystemURL& url,
-                          int64 initial_offset,
+                          int64_t initial_offset,
                           const UpdateObserverList& observers);
   ~SandboxFileStreamWriter() override;
 
@@ -40,9 +43,7 @@
   int Flush(const net::CompletionCallback& callback) override;
 
   // Used only by tests.
-  void set_default_quota(int64 quota) {
-    default_quota_ = quota;
-  }
+  void set_default_quota(int64_t quota) { default_quota_ = quota; }
 
  private:
   // Performs quota calculation and calls local_file_writer_->Write().
@@ -59,8 +60,8 @@
       const scoped_refptr<storage::ShareableFileReference>& file_ref);
   void DidGetUsageAndQuota(const net::CompletionCallback& callback,
                            storage::QuotaStatusCode status,
-                           int64 usage,
-                           int64 quota);
+                           int64_t usage,
+                           int64_t quota);
   void DidInitializeForWrite(net::IOBuffer* buf, int buf_len,
                              const net::CompletionCallback& callback,
                              int init_status);
@@ -73,19 +74,19 @@
 
   scoped_refptr<FileSystemContext> file_system_context_;
   FileSystemURL url_;
-  int64 initial_offset_;
+  int64_t initial_offset_;
   scoped_ptr<FileStreamWriter> local_file_writer_;
   net::CompletionCallback cancel_callback_;
 
   UpdateObserverList observers_;
 
   base::FilePath file_path_;
-  int64 file_size_;
-  int64 total_bytes_written_;
-  int64 allowed_bytes_to_write_;
+  int64_t file_size_;
+  int64_t total_bytes_written_;
+  int64_t allowed_bytes_to_write_;
   bool has_pending_operation_;
 
-  int64 default_quota_;
+  int64_t default_quota_;
 
   base::WeakPtrFactory<SandboxFileStreamWriter> weak_factory_;
 
diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc
index 7e3b6be..abd72607 100644
--- a/storage/browser/quota/quota_manager.cc
+++ b/storage/browser/quota/quota_manager.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 #include <functional>
+#include <limits>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -37,10 +38,10 @@
 
 namespace {
 
-const int64 kMBytes = 1024 * 1024;
+const int64_t kMBytes = 1024 * 1024;
 const int kMinutesInMilliSeconds = 60 * 1000;
 
-const int64 kReportHistogramInterval = 60 * 60 * 1000;  // 1 hour
+const int64_t kReportHistogramInterval = 60 * 60 * 1000;  // 1 hour
 const double kTemporaryQuotaRatioToAvail = 1.0 / 3.0;  // 33%
 
 }  // namespace
@@ -48,9 +49,9 @@
 // Arbitrary for now, but must be reasonably small so that
 // in-memory databases can fit.
 // TODO(kinuko): Refer SysInfo::AmountOfPhysicalMemory() to determine this.
-const int64 QuotaManager::kIncognitoDefaultQuotaLimit = 100 * kMBytes;
+const int64_t QuotaManager::kIncognitoDefaultQuotaLimit = 100 * kMBytes;
 
-const int64 QuotaManager::kNoLimit = kint64max;
+const int64_t QuotaManager::kNoLimit = INT64_MAX;
 
 const int QuotaManager::kPerHostTemporaryPortion = 5;  // 20%
 
@@ -58,7 +59,7 @@
 // This is a bit lax value because the histogram says nothing about per-host
 // persistent storage usage and we determined by global persistent storage
 // usage that is less than 10GB for almost all users.
-const int64 QuotaManager::kPerHostPersistentQuotaLimit = 10 * 1024 * kMBytes;
+const int64_t QuotaManager::kPerHostPersistentQuotaLimit = 10 * 1024 * kMBytes;
 
 const char QuotaManager::kDatabaseName[] = "QuotaManager";
 
@@ -69,7 +70,7 @@
 // TODO(kinuko): This should be like 10% of the actual disk space.
 // For now we simply use a constant as getting the disk size needs
 // platform-dependent code. (http://crbug.com/178976)
-int64 QuotaManager::kMinimumPreserveForSystem = 1024 * kMBytes;
+int64_t QuotaManager::kMinimumPreserveForSystem = 1024 * kMBytes;
 
 const int QuotaManager::kEvictionIntervalInMilliSeconds =
     30 * kMinutesInMilliSeconds;
@@ -84,7 +85,7 @@
 // Heuristics: assuming average cloud server allows a few Gigs storage
 // on the server side and the storage needs to be shared for user data
 // and by multiple apps.
-int64 QuotaManager::kSyncableStorageDefaultHostQuota = 500 * kMBytes;
+int64_t QuotaManager::kSyncableStorageDefaultHostQuota = 500 * kMBytes;
 
 namespace {
 
@@ -108,7 +109,7 @@
   }
 }
 
-bool SetTemporaryGlobalOverrideQuotaOnDBThread(int64* new_quota,
+bool SetTemporaryGlobalOverrideQuotaOnDBThread(int64_t* new_quota,
                                                QuotaDatabase* database) {
   DCHECK(database);
   if (!database->SetQuotaConfigValue(
@@ -120,7 +121,7 @@
 }
 
 bool GetPersistentHostQuotaOnDBThread(const std::string& host,
-                                      int64* quota,
+                                      int64_t* quota,
                                       QuotaDatabase* database) {
   DCHECK(database);
   database->GetHostQuota(host, kStorageTypePersistent, quota);
@@ -128,7 +129,7 @@
 }
 
 bool SetPersistentHostQuotaOnDBThread(const std::string& host,
-                                      int64* new_quota,
+                                      int64_t* new_quota,
                                       QuotaDatabase* database) {
   DCHECK(database);
   if (database->SetHostQuota(host, kStorageTypePersistent, *new_quota))
@@ -137,8 +138,8 @@
   return false;
 }
 
-bool InitializeOnDBThread(int64* temporary_quota_override,
-                          int64* desired_available_space,
+bool InitializeOnDBThread(int64_t* temporary_quota_override,
+                          int64_t* desired_available_space,
                           QuotaDatabase* database) {
   DCHECK(database);
   database->GetQuotaConfigValue(QuotaDatabase::kTemporaryQuotaOverrideKey,
@@ -226,7 +227,7 @@
   return database->SetOriginLastModifiedTime(origin, type, modified_time);
 }
 
-int64 CallSystemGetAmountOfFreeDiskSpace(const base::FilePath& profile_path) {
+int64_t CallSystemGetAmountOfFreeDiskSpace(const base::FilePath& profile_path) {
   // crbug.com/349708
   TRACE_EVENT0("io", "CallSystemGetAmountOfFreeDiskSpace");
 
@@ -238,11 +239,12 @@
   return base::SysInfo::AmountOfFreeDiskSpace(profile_path);
 }
 
-int64 CalculateTemporaryGlobalQuota(int64 global_limited_usage,
-                                    int64 available_space) {
+int64_t CalculateTemporaryGlobalQuota(int64_t global_limited_usage,
+                                      int64_t available_space) {
   DCHECK_GE(global_limited_usage, 0);
-  int64 avail_space = available_space;
-  if (avail_space < kint64max - global_limited_usage) {
+  int64_t avail_space = available_space;
+  if (avail_space <
+      std::numeric_limits<int64_t>::max() - global_limited_usage) {
     // We basically calculate the temporary quota by
     // [available_space + space_used_for_temp] * kTempQuotaRatio,
     // but make sure we'll have no overflow.
@@ -265,8 +267,9 @@
       usage_and_quota.available_disk_space));
 }
 
-int64 CalculateQuotaWithDiskSpace(
-    int64 available_disk_space, int64 usage, int64 quota) {
+int64_t CalculateQuotaWithDiskSpace(int64_t available_disk_space,
+                                    int64_t usage,
+                                    int64_t quota) {
   if (available_disk_space < QuotaManager::kMinimumPreserveForSystem) {
     LOG(WARNING)
         << "Running out of disk space for profile."
@@ -286,11 +289,11 @@
   return quota;
 }
 
-int64 CalculateTemporaryHostQuota(int64 host_usage,
-                                  int64 global_quota,
-                                  int64 global_limited_usage) {
+int64_t CalculateTemporaryHostQuota(int64_t host_usage,
+                                    int64_t global_quota,
+                                    int64_t global_limited_usage) {
   DCHECK_GE(global_limited_usage, 0);
-  int64 host_quota = global_quota / QuotaManager::kPerHostTemporaryPortion;
+  int64_t host_quota = global_quota / QuotaManager::kPerHostTemporaryPortion;
   if (global_limited_usage > global_quota)
     host_quota = std::min(host_quota, host_usage);
   return host_quota;
@@ -309,8 +312,8 @@
     return;
   }
 
-  int64 usage = usage_and_quota.usage;
-  int64 quota = usage_and_quota.quota;
+  int64_t usage = usage_and_quota.usage;
+  int64_t quota = usage_and_quota.quota;
 
   if (type == kStorageTypeTemporary && !is_unlimited) {
     quota = CalculateTemporaryHostQuota(
@@ -348,16 +351,14 @@
       available_disk_space(0) {
 }
 
-UsageAndQuota::UsageAndQuota(
-    int64 usage,
-    int64 global_limited_usage,
-    int64 quota,
-    int64 available_disk_space)
+UsageAndQuota::UsageAndQuota(int64_t usage,
+                             int64_t global_limited_usage,
+                             int64_t quota,
+                             int64_t available_disk_space)
     : usage(usage),
       global_limited_usage(global_limited_usage),
       quota(quota),
-      available_disk_space(available_disk_space) {
-}
+      available_disk_space(available_disk_space) {}
 
 class UsageAndQuotaCallbackDispatcher
     : public QuotaTask,
@@ -380,22 +381,22 @@
     Start();
   }
 
-  void set_usage(int64 usage) {
+  void set_usage(int64_t usage) {
     usage_and_quota_.usage = usage;
     has_usage_ = true;
   }
 
-  void set_global_limited_usage(int64 global_limited_usage) {
+  void set_global_limited_usage(int64_t global_limited_usage) {
     usage_and_quota_.global_limited_usage = global_limited_usage;
     has_global_limited_usage_ = true;
   }
 
-  void set_quota(int64 quota) {
+  void set_quota(int64_t quota) {
     usage_and_quota_.quota = quota;
     has_quota_ = true;
   }
 
-  void set_available_disk_space(int64 available_disk_space) {
+  void set_available_disk_space(int64_t available_disk_space) {
     usage_and_quota_.available_disk_space = available_disk_space;
     has_available_disk_space_ = true;
   }
@@ -430,28 +431,28 @@
   }
 
  private:
-  void DidGetHostUsage(int64 usage) {
+  void DidGetHostUsage(int64_t usage) {
     if (status_ == kQuotaStatusUnknown)
       status_ = kQuotaStatusOk;
     usage_and_quota_.usage = usage;
     CheckCompleted();
   }
 
-  void DidGetGlobalLimitedUsage(int64 limited_usage) {
+  void DidGetGlobalLimitedUsage(int64_t limited_usage) {
     if (status_ == kQuotaStatusUnknown)
       status_ = kQuotaStatusOk;
     usage_and_quota_.global_limited_usage = limited_usage;
     CheckCompleted();
   }
 
-  void DidGetQuota(QuotaStatusCode status, int64 quota) {
+  void DidGetQuota(QuotaStatusCode status, int64_t quota) {
     if (status_ == kQuotaStatusUnknown || status_ == kQuotaStatusOk)
       status_ = status;
     usage_and_quota_.quota = quota;
     CheckCompleted();
   }
 
-  void DidGetAvailableSpace(QuotaStatusCode status, int64 space) {
+  void DidGetAvailableSpace(QuotaStatusCode status, int64_t space) {
     // crbug.com/349708
     TRACE_EVENT0(
         "io", "UsageAndQuotaCallbackDispatcher::DidGetAvailableSpace");
@@ -555,18 +556,18 @@
 
  private:
   void AddEntries(StorageType type, UsageTracker* tracker) {
-    std::map<std::string, int64> host_usage;
+    std::map<std::string, int64_t> host_usage;
     tracker->GetCachedHostsUsage(&host_usage);
-    for (std::map<std::string, int64>::const_iterator iter = host_usage.begin();
-         iter != host_usage.end();
-         ++iter) {
+    for (std::map<std::string, int64_t>::const_iterator iter =
+             host_usage.begin();
+         iter != host_usage.end(); ++iter) {
       entries_.push_back(UsageInfo(iter->first, type, iter->second));
     }
     if (--remaining_trackers_ == 0)
       CallCompleted();
   }
 
-  void DidGetGlobalUsage(StorageType type, int64, int64) {
+  void DidGetGlobalUsage(StorageType type, int64_t, int64_t) {
     DCHECK(manager()->GetUsageTracker(type));
     AddEntries(type, manager()->GetUsageTracker(type));
   }
@@ -964,9 +965,10 @@
   NotifyStorageAccessedInternal(client_id, origin, type, base::Time::Now());
 }
 
-void QuotaManager::NotifyStorageModified(
-    QuotaClient::ID client_id,
-    const GURL& origin, StorageType type, int64 delta) {
+void QuotaManager::NotifyStorageModified(QuotaClient::ID client_id,
+                                         const GURL& origin,
+                                         StorageType type,
+                                         int64_t delta) {
   DCHECK(origin == origin.GetOrigin());
   NotifyStorageModifiedInternal(client_id, origin, type, delta,
                                 base::Time::Now());
@@ -1059,7 +1061,8 @@
 }
 
 void QuotaManager::SetTemporaryGlobalOverrideQuota(
-    int64 new_quota, const QuotaCallback& callback) {
+    int64_t new_quota,
+    const QuotaCallback& callback) {
   LazyInitialize();
 
   if (new_quota < 0) {
@@ -1074,7 +1077,7 @@
     return;
   }
 
-  int64* new_quota_ptr = new int64(new_quota);
+  int64_t* new_quota_ptr = new int64_t(new_quota);
   PostTaskAndReplyWithResultForDBThread(
       FROM_HERE,
       base::Bind(&SetTemporaryGlobalOverrideQuotaOnDBThread,
@@ -1099,7 +1102,7 @@
   if (!persistent_host_quota_callbacks_.Add(host, callback))
     return;
 
-  int64* quota_ptr = new int64(0);
+  int64_t* quota_ptr = new int64_t(0);
   PostTaskAndReplyWithResultForDBThread(
       FROM_HERE,
       base::Bind(&GetPersistentHostQuotaOnDBThread,
@@ -1112,7 +1115,7 @@
 }
 
 void QuotaManager::SetPersistentHostQuota(const std::string& host,
-                                          int64 new_quota,
+                                          int64_t new_quota,
                                           const QuotaCallback& callback) {
   LazyInitialize();
   if (host.empty()) {
@@ -1136,7 +1139,7 @@
     return;
   }
 
-  int64* new_quota_ptr = new int64(new_quota);
+  int64_t* new_quota_ptr = new int64_t(new_quota);
   PostTaskAndReplyWithResultForDBThread(
       FROM_HERE,
       base::Bind(&SetPersistentHostQuotaOnDBThread,
@@ -1189,12 +1192,12 @@
     std::map<std::string, std::string>* statistics) {
   DCHECK(statistics);
   if (temporary_storage_evictor_) {
-    std::map<std::string, int64> stats;
+    std::map<std::string, int64_t> stats;
     temporary_storage_evictor_->GetStatistics(&stats);
-    for (std::map<std::string, int64>::iterator p = stats.begin();
-         p != stats.end();
-         ++p)
+    for (std::map<std::string, int64_t>::iterator p = stats.begin();
+         p != stats.end(); ++p) {
       (*statistics)[p->first] = base::Int64ToString(p->second);
+    }
   }
 }
 
@@ -1307,8 +1310,8 @@
       clients_, kStorageTypeSyncable, special_storage_policy_.get(),
       storage_monitor_.get()));
 
-  int64* temporary_quota_override = new int64(-1);
-  int64* desired_available_space = new int64(-1);
+  int64_t* temporary_quota_override = new int64_t(-1);
+  int64_t* desired_available_space = new int64_t(-1);
   PostTaskAndReplyWithResultForDBThread(
       FROM_HERE,
       base::Bind(&InitializeOnDBThread,
@@ -1369,12 +1372,11 @@
                  weak_factory_.GetWeakPtr()));
 }
 
-void QuotaManager::NotifyStorageModifiedInternal(
-    QuotaClient::ID client_id,
-    const GURL& origin,
-    StorageType type,
-    int64 delta,
-    base::Time modified_time) {
+void QuotaManager::NotifyStorageModifiedInternal(QuotaClient::ID client_id,
+                                                 const GURL& origin,
+                                                 StorageType type,
+                                                 int64_t delta,
+                                                 base::Time modified_time) {
   LazyInitialize();
   DCHECK(GetUsageTracker(type));
   GetUsageTracker(type)->UpdateUsageCache(client_id, origin, delta);
@@ -1478,8 +1480,8 @@
 }
 
 void QuotaManager::DidGetTemporaryGlobalUsageForHistogram(
-    int64 usage,
-    int64 unlimited_usage) {
+    int64_t usage,
+    int64_t unlimited_usage) {
   UMA_HISTOGRAM_MBYTES("Quota.GlobalUsageOfTemporaryStorage", usage);
 
   std::set<GURL> origins;
@@ -1502,8 +1504,8 @@
 }
 
 void QuotaManager::DidGetPersistentGlobalUsageForHistogram(
-    int64 usage,
-    int64 unlimited_usage) {
+    int64_t usage,
+    int64_t unlimited_usage) {
   UMA_HISTOGRAM_MBYTES("Quota.GlobalUsageOfPersistentStorage", usage);
 
   std::set<GURL> origins;
@@ -1558,7 +1560,7 @@
 
 void QuotaManager::GetEvictionOrigin(StorageType type,
                                      const std::set<GURL>& extra_exceptions,
-                                     int64 global_quota,
+                                     int64_t global_quota,
                                      const GetOriginCallback& callback) {
   LazyInitialize();
   // This must not be called while there's an in-flight task.
@@ -1570,7 +1572,7 @@
                  weak_factory_.GetWeakPtr(), callback);
 
   if (type == kStorageTypeTemporary && temporary_storage_eviction_policy_) {
-    std::map<GURL, int64> usage_map;
+    std::map<GURL, int64_t> usage_map;
     // The cached origins are populated by the prior call to
     // GetUsageAndQuotaForEviction().
     GetUsageTracker(kStorageTypeTemporary)->GetCachedOriginsUsage(&usage_map);
@@ -1641,7 +1643,7 @@
 
 void QuotaManager::DidSetTemporaryGlobalOverrideQuota(
     const QuotaCallback& callback,
-    const int64* new_quota,
+    const int64_t* new_quota,
     bool success) {
   QuotaStatusCode status = kQuotaErrorInvalidAccess;
   DidDatabaseWork(success);
@@ -1657,7 +1659,7 @@
 }
 
 void QuotaManager::DidGetPersistentHostQuota(const std::string& host,
-                                             const int64* quota,
+                                             const int64_t* quota,
                                              bool success) {
   DidDatabaseWork(success);
   persistent_host_quota_callbacks_.Run(host, kQuotaStatusOk, *quota);
@@ -1665,14 +1667,14 @@
 
 void QuotaManager::DidSetPersistentHostQuota(const std::string& host,
                                              const QuotaCallback& callback,
-                                             const int64* new_quota,
+                                             const int64_t* new_quota,
                                              bool success) {
   DidDatabaseWork(success);
   callback.Run(success ? kQuotaStatusOk : kQuotaErrorInvalidAccess, *new_quota);
 }
 
-void QuotaManager::DidInitialize(int64* temporary_quota_override,
-                                 int64* desired_available_space,
+void QuotaManager::DidInitialize(int64_t* temporary_quota_override,
+                                 int64_t* desired_available_space,
                                  bool success) {
   temporary_quota_override_ = *temporary_quota_override;
   desired_available_space_ = *desired_available_space;
@@ -1698,8 +1700,8 @@
   lru_origin_callback_.Reset();
 }
 
-void QuotaManager::DidGetInitialTemporaryGlobalQuota(
-    QuotaStatusCode status, int64 quota_unused) {
+void QuotaManager::DidGetInitialTemporaryGlobalQuota(QuotaStatusCode status,
+                                                     int64_t quota_unused) {
   if (eviction_disabled_)
     return;
 
@@ -1721,7 +1723,7 @@
     StartEviction();
 }
 
-void QuotaManager::DidGetAvailableSpace(int64 space) {
+void QuotaManager::DidGetAvailableSpace(int64_t space) {
   // crbug.com/349708
   TRACE_EVENT1("io", "QuotaManager::DidGetAvailableSpace",
                "n_callbacks", available_space_callbacks_.size());
diff --git a/storage/browser/quota/quota_manager.h b/storage/browser/quota/quota_manager.h
index 210f4c8..b8747a8c 100644
--- a/storage/browser/quota/quota_manager.h
+++ b/storage/browser/quota/quota_manager.h
@@ -5,6 +5,8 @@
 #ifndef STORAGE_BROWSER_QUOTA_QUOTA_MANAGER_H_
 #define STORAGE_BROWSER_QUOTA_QUOTA_MANAGER_H_
 
+#include <stdint.h>
+
 #include <deque>
 #include <list>
 #include <map>
@@ -13,9 +15,9 @@
 #include <utility>
 #include <vector>
 
-#include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/files/file_path.h"
+#include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
@@ -59,16 +61,16 @@
 struct QuotaManagerDeleter;
 
 struct STORAGE_EXPORT UsageAndQuota {
-  int64 usage;
-  int64 global_limited_usage;
-  int64 quota;
-  int64 available_disk_space;
+  int64_t usage;
+  int64_t global_limited_usage;
+  int64_t quota;
+  int64_t available_disk_space;
 
   UsageAndQuota();
-  UsageAndQuota(int64 usage,
-                int64 global_limited_usage,
-                int64 quota,
-                int64 available_disk_space);
+  UsageAndQuota(int64_t usage,
+                int64_t global_limited_usage,
+                int64_t quota,
+                int64_t available_disk_space);
 };
 
 // TODO(calamity): Use this in the temporary storage eviction path.
@@ -83,8 +85,8 @@
   virtual void GetEvictionOrigin(
       const scoped_refptr<SpecialStoragePolicy>& special_storage_policy,
       const std::set<GURL>& exceptions,
-      const std::map<GURL, int64>& usage_map,
-      int64 global_quota,
+      const std::map<GURL, int64_t>& usage_map,
+      int64_t global_quota,
       const GetOriginCallback& callback) = 0;
 };
 
@@ -100,7 +102,7 @@
   // no evictable origins.
   virtual void GetEvictionOrigin(StorageType type,
                                  const std::set<GURL>& extra_exceptions,
-                                 int64 global_quota,
+                                 int64_t global_quota,
                                  const GetOriginCallback& callback) = 0;
 
   virtual void EvictOriginData(
@@ -116,13 +118,11 @@
 };
 
 struct UsageInfo {
-  UsageInfo(const std::string& host, StorageType type, int64 usage)
-      : host(host),
-        type(type),
-        usage(usage) {}
+  UsageInfo(const std::string& host, StorageType type, int64_t usage)
+      : host(host), type(type), usage(usage) {}
   std::string host;
   StorageType type;
-  int64 usage;
+  int64_t usage;
 };
 
 // The quota manager class.  This class is instantiated per profile and
@@ -134,12 +134,11 @@
       public base::RefCountedThreadSafe<QuotaManager, QuotaManagerDeleter> {
  public:
   typedef base::Callback<void(QuotaStatusCode,
-                              int64 /* usage */,
-                              int64 /* quota */)>
-      GetUsageAndQuotaCallback;
+                              int64_t /* usage */,
+                              int64_t /* quota */)> GetUsageAndQuotaCallback;
 
-  static const int64 kIncognitoDefaultQuotaLimit;
-  static const int64 kNoLimit;
+  static const int64_t kIncognitoDefaultQuotaLimit;
+  static const int64_t kNoLimit;
 
   QuotaManager(
       bool is_incognito,
@@ -185,7 +184,7 @@
   void NotifyStorageModified(QuotaClient::ID client_id,
                              const GURL& origin,
                              StorageType type,
-                             int64 delta);
+                             int64_t delta);
 
   // Used to avoid evicting origins with open pages.
   // A call to NotifyOriginInUse must be balanced by a later call
@@ -226,13 +225,13 @@
   void GetTemporaryGlobalQuota(const QuotaCallback& callback);
 
   // Ok to call with NULL callback.
-  void SetTemporaryGlobalOverrideQuota(int64 new_quota,
+  void SetTemporaryGlobalOverrideQuota(int64_t new_quota,
                                        const QuotaCallback& callback);
 
   void GetPersistentHostQuota(const std::string& host,
                               const QuotaCallback& callback);
   void SetPersistentHostQuota(const std::string& host,
-                              int64 new_quota,
+                              int64_t new_quota,
                               const QuotaCallback& callback);
   void GetGlobalUsage(StorageType type, const GlobalUsageCallback& callback);
   void GetHostUsage(const std::string& host, StorageType type,
@@ -269,7 +268,7 @@
   // utilized by a single host (ie. 5 for 20%).
   static const int kPerHostTemporaryPortion;
 
-  static const int64 kPerHostPersistentQuotaLimit;
+  static const int64_t kPerHostPersistentQuotaLimit;
 
   static const char kDatabaseName[];
 
@@ -284,8 +283,8 @@
   // These are kept non-const so that test code can change the value.
   // TODO(kinuko): Make this a real const value and add a proper way to set
   // the quota for syncable storage. (http://crbug.com/155488)
-  static int64 kMinimumPreserveForSystem;
-  static int64 kSyncableStorageDefaultHostQuota;
+  static int64_t kMinimumPreserveForSystem;
+  static int64_t kSyncableStorageDefaultHostQuota;
 
  protected:
   ~QuotaManager() override;
@@ -319,7 +318,7 @@
 
   // Function pointer type used to store the function which returns the
   // available disk space for the disk containing the given FilePath.
-  typedef int64 (*GetAvailableDiskSpaceFn)(const base::FilePath&);
+  typedef int64_t (*GetAvailableDiskSpaceFn)(const base::FilePath&);
 
   typedef base::Callback<void(const QuotaTableEntries&)>
       DumpQuotaTableCallback;
@@ -327,9 +326,9 @@
       DumpOriginInfoTableCallback;
 
   typedef CallbackQueue<base::Closure> ClosureQueue;
-  typedef CallbackQueue<AvailableSpaceCallback, QuotaStatusCode, int64>
+  typedef CallbackQueue<AvailableSpaceCallback, QuotaStatusCode, int64_t>
       AvailableSpaceCallbackQueue;
-  typedef CallbackQueueMap<QuotaCallback, std::string, QuotaStatusCode, int64>
+  typedef CallbackQueueMap<QuotaCallback, std::string, QuotaStatusCode, int64_t>
       HostQuotaCallbackMap;
 
   struct EvictionContext {
@@ -367,12 +366,11 @@
       const GURL& origin,
       StorageType type,
       base::Time accessed_time);
-  void NotifyStorageModifiedInternal(
-      QuotaClient::ID client_id,
-      const GURL& origin,
-      StorageType type,
-      int64 delta,
-      base::Time modified_time);
+  void NotifyStorageModifiedInternal(QuotaClient::ID client_id,
+                                     const GURL& origin,
+                                     StorageType type,
+                                     int64_t delta,
+                                     base::Time modified_time);
 
   void DumpQuotaTable(const DumpQuotaTableCallback& callback);
   void DumpOriginInfoTable(const DumpOriginInfoTableCallback& callback);
@@ -392,10 +390,10 @@
   void DidOriginDataEvicted(QuotaStatusCode status);
 
   void ReportHistogram();
-  void DidGetTemporaryGlobalUsageForHistogram(int64 usage,
-                                              int64 unlimited_usage);
-  void DidGetPersistentGlobalUsageForHistogram(int64 usage,
-                                               int64 unlimited_usage);
+  void DidGetTemporaryGlobalUsageForHistogram(int64_t usage,
+                                              int64_t unlimited_usage);
+  void DidGetPersistentGlobalUsageForHistogram(int64_t usage,
+                                               int64_t unlimited_usage);
 
   std::set<GURL> GetEvictionOriginExceptions(
       const std::set<GURL>& extra_exceptions);
@@ -405,7 +403,7 @@
   // QuotaEvictionHandler.
   void GetEvictionOrigin(StorageType type,
                          const std::set<GURL>& extra_exceptions,
-                         int64 global_quota,
+                         int64_t global_quota,
                          const GetOriginCallback& callback) override;
   void EvictOriginData(const GURL& origin,
                        StorageType type,
@@ -416,24 +414,24 @@
   void GetLRUOrigin(StorageType type, const GetOriginCallback& callback);
 
   void DidSetTemporaryGlobalOverrideQuota(const QuotaCallback& callback,
-                                          const int64* new_quota,
+                                          const int64_t* new_quota,
                                           bool success);
   void DidGetPersistentHostQuota(const std::string& host,
-                                 const int64* quota,
+                                 const int64_t* quota,
                                  bool success);
   void DidSetPersistentHostQuota(const std::string& host,
                                  const QuotaCallback& callback,
-                                 const int64* new_quota,
+                                 const int64_t* new_quota,
                                  bool success);
-  void DidInitialize(int64* temporary_quota_override,
-                     int64* desired_available_space,
+  void DidInitialize(int64_t* temporary_quota_override,
+                     int64_t* desired_available_space,
                      bool success);
   void DidGetLRUOrigin(const GURL* origin,
                        bool success);
   void DidGetInitialTemporaryGlobalQuota(QuotaStatusCode status,
-                                         int64 quota_unused);
+                                         int64_t quota_unused);
   void DidInitializeTemporaryOriginsInfo(bool success);
-  void DidGetAvailableSpace(int64 space);
+  void DidGetAvailableSpace(int64_t space);
   void DidDatabaseWork(bool success);
 
   void DeleteOnCorrectThread() const;
@@ -474,9 +472,9 @@
   HostQuotaCallbackMap persistent_host_quota_callbacks_;
 
   bool temporary_quota_initialized_;
-  int64 temporary_quota_override_;
+  int64_t temporary_quota_override_;
 
-  int64 desired_available_space_;
+  int64_t desired_available_space_;
 
   // Map from origin to count.
   std::map<GURL, int> origins_in_use_;
diff --git a/storage/common/blob_storage/blob_item_bytes_request.h b/storage/common/blob_storage/blob_item_bytes_request.h
index b40c2e4..00d6d18 100644
--- a/storage/common/blob_storage/blob_item_bytes_request.h
+++ b/storage/common/blob_storage/blob_item_bytes_request.h
@@ -18,7 +18,7 @@
 struct STORAGE_COMMON_EXPORT BlobItemBytesRequest {
   // Not using std::numeric_limits<T>::max() because of non-C++11 builds.
   static const size_t kInvalidIndex = SIZE_MAX;
-  static const uint64_t kInvalidSize = kuint64max;
+  static const uint64_t kInvalidSize = UINT64_MAX;
 
   static BlobItemBytesRequest CreateIPCRequest(size_t request_number,
                                                size_t renderer_item_index,
diff --git a/storage/common/data_element.cc b/storage/common/data_element.cc
index fe003ebf..8b1fc4da 100644
--- a/storage/common/data_element.cc
+++ b/storage/common/data_element.cc
@@ -14,14 +14,14 @@
     : type_(TYPE_UNKNOWN),
       bytes_(NULL),
       offset_(0),
-      length_(kuint64max) {
-}
+      length_(std::numeric_limits<uint64_t>::max()) {}
 
 DataElement::~DataElement() {}
 
 void DataElement::SetToFilePathRange(
     const base::FilePath& path,
-    uint64 offset, uint64 length,
+    uint64_t offset,
+    uint64_t length,
     const base::Time& expected_modification_time) {
   type_ = TYPE_FILE;
   path_ = path;
@@ -30,9 +30,9 @@
   expected_modification_time_ = expected_modification_time;
 }
 
-void DataElement::SetToBlobRange(
-    const std::string& blob_uuid,
-    uint64 offset, uint64 length) {
+void DataElement::SetToBlobRange(const std::string& blob_uuid,
+                                 uint64_t offset,
+                                 uint64_t length) {
   type_ = TYPE_BLOB;
   blob_uuid_ = blob_uuid;
   offset_ = offset;
@@ -41,7 +41,8 @@
 
 void DataElement::SetToFileSystemUrlRange(
     const GURL& filesystem_url,
-    uint64 offset, uint64 length,
+    uint64_t offset,
+    uint64_t length,
     const base::Time& expected_modification_time) {
   type_ = TYPE_FILE_FILESYSTEM;
   filesystem_url_ = filesystem_url;
@@ -50,18 +51,18 @@
   expected_modification_time_ = expected_modification_time;
 }
 
-void DataElement::SetToDiskCacheEntryRange(uint64 offset, uint64 length) {
+void DataElement::SetToDiskCacheEntryRange(uint64_t offset, uint64_t length) {
   type_ = TYPE_DISK_CACHE_ENTRY;
   offset_ = offset;
   length_ = length;
 }
 
 void PrintTo(const DataElement& x, std::ostream* os) {
-  const uint64 kMaxDataPrintLength = 40;
+  const uint64_t kMaxDataPrintLength = 40;
   *os << "<DataElement>{type: ";
   switch (x.type()) {
     case DataElement::TYPE_BYTES: {
-      uint64 length = std::min(x.length(), kMaxDataPrintLength);
+      uint64_t length = std::min(x.length(), kMaxDataPrintLength);
       *os << "TYPE_BYTES, data: ["
           << base::HexEncode(x.bytes(), static_cast<size_t>(length));
       if (length < x.length()) {
diff --git a/storage/common/data_element.h b/storage/common/data_element.h
index 8376751b..2e9ce9c 100644
--- a/storage/common/data_element.h
+++ b/storage/common/data_element.h
@@ -5,11 +5,13 @@
 #ifndef STORAGE_COMMON_DATA_ELEMENT_H_
 #define STORAGE_COMMON_DATA_ELEMENT_H_
 
+#include <stdint.h>
+
+#include <limits>
 #include <ostream>
 #include <string>
 #include <vector>
 
-#include "base/basictypes.h"
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
 #include "base/logging.h"
@@ -42,8 +44,8 @@
   const base::FilePath& path() const { return path_; }
   const GURL& filesystem_url() const { return filesystem_url_; }
   const std::string& blob_uuid() const { return blob_uuid_; }
-  uint64 offset() const { return offset_; }
-  uint64 length() const { return length_; }
+  uint64_t offset() const { return offset_; }
+  uint64_t length() const { return length_; }
   const base::Time& expected_modification_time() const {
     return expected_modification_time_;
   }
@@ -73,7 +75,7 @@
   // SetToBytes must be called before this method.
   void AppendBytes(const char* bytes, int bytes_len) {
     DCHECK_EQ(type_, TYPE_BYTES);
-    DCHECK_NE(length_, kuint64max);
+    DCHECK_NE(length_, std::numeric_limits<uint64_t>::max());
     DCHECK(!bytes_);
     buf_.insert(buf_.end(), bytes, bytes + bytes_len);
     length_ = buf_.size();
@@ -106,30 +108,34 @@
 
   // Sets TYPE_FILE data.
   void SetToFilePath(const base::FilePath& path) {
-    SetToFilePathRange(path, 0, kuint64max, base::Time());
+    SetToFilePathRange(path, 0, std::numeric_limits<uint64_t>::max(),
+                       base::Time());
   }
 
   // Sets TYPE_BLOB data.
   void SetToBlob(const std::string& uuid) {
-    SetToBlobRange(uuid, 0, kuint64max);
+    SetToBlobRange(uuid, 0, std::numeric_limits<uint64_t>::max());
   }
 
   // Sets TYPE_FILE data with range.
   void SetToFilePathRange(const base::FilePath& path,
-                          uint64 offset, uint64 length,
+                          uint64_t offset,
+                          uint64_t length,
                           const base::Time& expected_modification_time);
 
   // Sets TYPE_BLOB data with range.
   void SetToBlobRange(const std::string& blob_uuid,
-                      uint64 offset, uint64 length);
+                      uint64_t offset,
+                      uint64_t length);
 
   // Sets TYPE_FILE_FILESYSTEM with range.
   void SetToFileSystemUrlRange(const GURL& filesystem_url,
-                               uint64 offset, uint64 length,
+                               uint64_t offset,
+                               uint64_t length,
                                const base::Time& expected_modification_time);
 
   // Sets to TYPE_DISK_CACHE_ENTRY with range.
-  void SetToDiskCacheEntryRange(uint64 offset, uint64 length);
+  void SetToDiskCacheEntryRange(uint64_t offset, uint64_t length);
 
  private:
   FRIEND_TEST_ALL_PREFIXES(BlobAsyncTransportStrategyTest, TestInvalidParams);
@@ -141,8 +147,8 @@
   base::FilePath path_;  // For TYPE_FILE.
   GURL filesystem_url_;  // For TYPE_FILE_FILESYSTEM.
   std::string blob_uuid_;
-  uint64 offset_;
-  uint64 length_;
+  uint64_t offset_;
+  uint64_t length_;
   base::Time expected_modification_time_;
 };
 
diff --git a/styleguide/c++/OWNERS b/styleguide/c++/OWNERS
index bb9ed6c..ef89234 100644
--- a/styleguide/c++/OWNERS
+++ b/styleguide/c++/OWNERS
@@ -1,3 +1,3 @@
 danakj@chromium.org
-jamesr@chromium.org
+jbroman@chromium.org
 thakis@chromium.org
diff --git a/styleguide/c++/c++11.html b/styleguide/c++/c++11.html
index 9c261fc..1e14b42d 100644
--- a/styleguide/c++/c++11.html
+++ b/styleguide/c++/c++11.html
@@ -131,6 +131,16 @@
 </tr>
 
 <tr>
+<td>Default Function Template Arguments</td>
+<td><code>template &lt;typename T = <i>type</i>&gt; <br />
+&nbsp;&nbsp;<i>type</i> <i>Function</i>(T <i>var</i>) {}</code></td>
+<td>Allow function templates, like classes, to have default arguments</td>
+<td><a href="http://stackoverflow.com/questions/2447458/default-template-arguments-for-function-templates">
+Default Template Arguments for Function Templates</a></td>
+<td><a href="https://groups.google.com/a/chromium.org/forum/#!topic/cxx/9KtaAsome-o">Discussion thread</a></td>
+</tr>
+
+<tr>
 <td>Delegated Constructors</td>
 <td><code>Class() : Class(0) {}</code><br />
 <code>Class(<i>type</i> <i>var</i>) : Class(<i>var</i>, 0)</code></td>
@@ -426,6 +436,25 @@
 </tr>
 
 <tr>
+<td>Alignment Features</td>
+<td>
+<code>alignas</code> specifier,
+<code>alignof</code> operator
+<td>Object alignment</td>
+<td>
+<a href="http://en.cppreference.com/w/cpp/language/alignas">alignas</a>,
+<a href="http://en.cppreference.com/w/cpp/language/alignof">alignof</a>
+</td>
+<td>
+<a href="https://codereview.chromium.org/1497963002/">Doesn't work in
+MSVS2013</a>.
+<a href="https://msdn.microsoft.com/en-us/library/dn956970.aspx">MSVS2015
+supports them</a>; reevaluate after MSVS2015 is available.
+<a href="https://groups.google.com/a/chromium.org/d/msg/cxx/rwXN02jzzq0/CpUc1ZzMBQAJ">Discussion thread</a>
+</td>
+</tr>
+
+<tr>
 <td>Constant Expressions</td>
 <td><code>constexpr</code></td>
 <td>Compile-time constant expressions</td>
@@ -585,16 +614,6 @@
 </tr>
 
 <tr>
-<td>Alignment Features</td>
-<td>
-<code>alignas</code> specifier,
-<code>alignof</code> operator,
-<td>Object alignment</td>
-<td><a href="http://en.cppreference.com/w/cpp/language/alignof">alignof</a></td>
-<td></td>
-</tr>
-
-<tr>
 <td>Attributes</td>
 <td><code>[[<i>attribute_name</i>]]</code></td>
 <td>Attaches properties to declarations that
@@ -605,16 +624,6 @@
 </tr>
 
 <tr>
-<td>Default Function Template Arguments</td>
-<td><code>template &lt;typename T = <i>type</i>&gt; <br />
-&nbsp;&nbsp;<i>type</i> <i>Function</i>(T <i>var</i>) {}</code></td>
-<td>Allow function templates, like classes, to have default arguments</td>
-<td><a href="http://stackoverflow.com/questions/2447458/default-template-arguments-for-function-templates">
-Default Template Arguments for Function Templates</a></td>
-<td></td>
-</tr>
-
-<tr>
 <td>Exception Features</td>
 <td><code>noexcept</code>, <code>exception_ptr</code>,
 <code>current_exception()</code>, <code>rethrow_exception</code>,
@@ -686,9 +695,9 @@
 <td><a href="http://en.cppreference.com/w/cpp/memory/addressof">std::addressof</a></td>
 <td>Usage should be rare as
 <a href="https://google.github.io/styleguide/cppguide.html#Operator_Overloading">
-Operator Overloading</a> is rare and <code>&amps;</code>
+Operator Overloading</a> is rare and <code>&amp;</code>
 should suffice in most cases. May be preferable
-over <code>&amps;</code> for performing object
+over <code>&amp;</code> for performing object
 identity checks.</td>
 </tr>
 
diff --git a/sync/syncable/directory_backing_store.cc b/sync/syncable/directory_backing_store.cc
index cbe943b..e57f246e 100644
--- a/sync/syncable/directory_backing_store.cc
+++ b/sync/syncable/directory_backing_store.cc
@@ -34,7 +34,7 @@
 namespace syncable {
 
 // Increment this version whenever updating DB tables.
-const int32 kCurrentDBVersion = 89;
+const int32 kCurrentDBVersion = 90;
 
 // Iterate over the fields of |entry| and bind each to |statement| for
 // updating.  Returns the number of args bound.
@@ -257,7 +257,8 @@
 DirectoryBackingStore::DirectoryBackingStore(const string& dir_name)
     : dir_name_(dir_name),
       database_page_size_(32768),
-      needs_column_refresh_(false) {
+      needs_metas_column_refresh_(false),
+      needs_share_info_column_refresh_(false) {
   DCHECK(base::ThreadTaskRunnerHandle::IsSet());
   ResetAndCreateConnection();
 }
@@ -267,7 +268,8 @@
     : dir_name_(dir_name),
       database_page_size_(32768),
       db_(db),
-      needs_column_refresh_(false) {
+      needs_metas_column_refresh_(false),
+      needs_share_info_column_refresh_(false) {
   DCHECK(base::ThreadTaskRunnerHandle::IsSet());
 }
 
@@ -552,10 +554,16 @@
       version_on_disk = 89;
   }
 
+  // Version 90 migration removes several columns from share_info table.
+  if (version_on_disk == 89) {
+    if (MigrateVersion89To90())
+      version_on_disk = 90;
+  }
+
   // If one of the migrations requested it, drop columns that aren't current.
   // It's only safe to do this after migrating all the way to the current
   // version.
-  if (version_on_disk == kCurrentDBVersion && needs_column_refresh_) {
+  if (version_on_disk == kCurrentDBVersion && needs_column_refresh()) {
     if (!RefreshColumns())
       version_on_disk = 0;
   }
@@ -573,15 +581,6 @@
       return false;
   }
 
-  sql::Statement s(db_->GetUniqueStatement(
-          "SELECT db_create_version, db_create_time FROM share_info"));
-  if (!s.Step())
-    return false;
-  string db_create_version = s.ColumnString(0);
-  int db_create_time = s.ColumnInt(1);
-  DVLOG(1) << "DB created at " << db_create_time << " by version " <<
-      db_create_version;
-
   return transaction.Commit();
 }
 
@@ -589,55 +588,58 @@
 // the currently used columns then copying all rows from the old tables into
 // this new one.  The tables are then rearranged so the new replaces the old.
 bool DirectoryBackingStore::RefreshColumns() {
-  DCHECK(needs_column_refresh_);
+  DCHECK(needs_metas_column_refresh_ || needs_share_info_column_refresh_);
 
-  // Create a new table named temp_metas.
-  SafeDropTable("temp_metas");
-  if (!CreateMetasTable(true))
-    return false;
+  if (needs_metas_column_refresh_) {
+    // Create a new table named temp_metas.
+    SafeDropTable("temp_metas");
+    if (!CreateMetasTable(true))
+      return false;
 
-  // Populate temp_metas from metas.
-  //
-  // At this point, the metas table may contain columns belonging to obsolete
-  // schema versions.  This statement explicitly lists only the columns that
-  // belong to the current schema version, so the obsolete columns will be
-  // effectively dropped once we rename temp_metas over top of metas.
-  std::string query = "INSERT INTO temp_metas (";
-  AppendColumnList(&query);
-  query.append(") SELECT ");
-  AppendColumnList(&query);
-  query.append(" FROM metas");
-  if (!db_->Execute(query.c_str()))
-    return false;
+    // Populate temp_metas from metas.
+    //
+    // At this point, the metas table may contain columns belonging to obsolete
+    // schema versions.  This statement explicitly lists only the columns that
+    // belong to the current schema version, so the obsolete columns will be
+    // effectively dropped once we rename temp_metas over top of metas.
+    std::string query = "INSERT INTO temp_metas (";
+    AppendColumnList(&query);
+    query.append(") SELECT ");
+    AppendColumnList(&query);
+    query.append(" FROM metas");
+    if (!db_->Execute(query.c_str()))
+      return false;
 
-  // Drop metas.
-  SafeDropTable("metas");
+    // Drop metas.
+    SafeDropTable("metas");
 
-  // Rename temp_metas -> metas.
-  if (!db_->Execute("ALTER TABLE temp_metas RENAME TO metas"))
-    return false;
+    // Rename temp_metas -> metas.
+    if (!db_->Execute("ALTER TABLE temp_metas RENAME TO metas"))
+      return false;
 
-  // Repeat the process for share_info.
-  SafeDropTable("temp_share_info");
-  if (!CreateShareInfoTable(true))
-    return false;
+    needs_metas_column_refresh_ = false;
+  }
 
-  // TODO(rlarocque, 124140): Remove notification_state.
-  if (!db_->Execute(
-          "INSERT INTO temp_share_info (id, name, store_birthday, "
-          "db_create_version, db_create_time, next_id, cache_guid,"
-          "notification_state, bag_of_chips) "
-          "SELECT id, name, store_birthday, db_create_version, "
-          "db_create_time, next_id, cache_guid, notification_state, "
-          "bag_of_chips "
-          "FROM share_info"))
-    return false;
+  if (needs_share_info_column_refresh_) {
+    // Repeat the process for share_info.
+    SafeDropTable("temp_share_info");
+    if (!CreateShareInfoTable(true))
+      return false;
 
-  SafeDropTable("share_info");
-  if (!db_->Execute("ALTER TABLE temp_share_info RENAME TO share_info"))
-    return false;
+    if (!db_->Execute(
+            "INSERT INTO temp_share_info (id, name, store_birthday, "
+            "cache_guid, bag_of_chips) "
+            "SELECT id, name, store_birthday, cache_guid, bag_of_chips "
+            "FROM share_info"))
+      return false;
 
-  needs_column_refresh_ = false;
+    SafeDropTable("share_info");
+    if (!db_->Execute("ALTER TABLE temp_share_info RENAME TO share_info"))
+      return false;
+
+    needs_share_info_column_refresh_ = false;
+  }
+
   return true;
 }
 
@@ -776,7 +778,8 @@
   SafeDropTable("extended_attributes");
   SafeDropTable("models");
   SafeDropTable("temp_models");
-  needs_column_refresh_ = false;
+  needs_metas_column_refresh_ = false;
+  needs_share_info_column_refresh_ = false;
 }
 
 // static
@@ -864,7 +867,7 @@
   //   string SERVER_NAME
   // No data migration is necessary, but we should do a column refresh.
   SetVersion(68);
-  needs_column_refresh_ = true;
+  needs_metas_column_refresh_ = true;
   return true;
 }
 
@@ -877,7 +880,7 @@
   if (!db_->Execute(
           "ALTER TABLE metas ADD COLUMN unique_client_tag varchar"))
     return false;
-  needs_column_refresh_ = true;
+  needs_metas_column_refresh_ = true;
 
   if (!db_->Execute(
           "UPDATE metas SET unique_server_tag = singleton_tag"))
@@ -958,7 +961,7 @@
     return false;
 
   SetVersion(69);
-  needs_column_refresh_ = true;  // Trigger deletion of old columns.
+  needs_metas_column_refresh_ = true;  // Trigger deletion of old columns.
   return true;
 }
 
@@ -1138,7 +1141,7 @@
   //   autofill_profiles_added_during_migration
   // No data migration is necessary, but we should do a column refresh.
   SetVersion(76);
-  needs_column_refresh_ = true;
+  needs_share_info_column_refresh_ = true;
   return true;
 }
 
@@ -1232,7 +1235,7 @@
   }
 
   SetVersion(81);
-  needs_column_refresh_ = true;
+  needs_metas_column_refresh_ = true;
   return true;
 }
 
@@ -1410,7 +1413,7 @@
   }
 
   SetVersion(86);
-  needs_column_refresh_ = true;
+  needs_metas_column_refresh_ = true;
   return true;
 }
 
@@ -1422,7 +1425,7 @@
     return false;
   }
   SetVersion(87);
-  needs_column_refresh_ = true;
+  needs_metas_column_refresh_ = true;
   return true;
 }
 
@@ -1443,7 +1446,19 @@
     return false;
   }
   SetVersion(89);
-  needs_column_refresh_ = true;
+  needs_metas_column_refresh_ = true;
+  return true;
+}
+
+bool DirectoryBackingStore::MigrateVersion89To90() {
+  // This change removed 4 columns from meta_info:
+  //   db_create_version
+  //   db_create_time
+  //   next_id
+  //   notification_state
+  // No data migration is necessary, but we should do a column refresh.
+  SetVersion(90);
+  needs_share_info_column_refresh_ = true;
   return true;
 }
 
@@ -1477,24 +1492,13 @@
             "(?, "  // id
             "?, "   // name
             "?, "   // store_birthday
-            "?, "   // db_create_version
-            "?, "   // db_create_time
-            "-2, "  // next_id
             "?, "   // cache_guid
-            // TODO(rlarocque, 124140): Remove notification_state field.
-            "?, "   // notification_state
             "?);"));  // bag_of_chips
     s.BindString(0, dir_name_);                   // id
     s.BindString(1, dir_name_);                   // name
     s.BindString(2, std::string());               // store_birthday
-    // TODO(akalin): Remove this unused db_create_version field. (Or
-    // actually use it for something.) http://crbug.com/118356
-    s.BindString(3, "Unknown");                   // db_create_version
-    s.BindInt(4, static_cast<int32>(time(0)));    // db_create_time
-    s.BindString(5, GenerateCacheGUID());         // cache_guid
-    // TODO(rlarocque, 124140): Remove this unused notification-state field.
-    s.BindBlob(6, NULL, 0);                       // notification_state
-    s.BindBlob(7, NULL, 0);                       // bag_of_chips
+    s.BindString(3, GenerateCacheGUID());         // cache_guid
+    s.BindBlob(4, NULL, 0);                       // bag_of_chips
     if (!s.Run())
       return false;
   }
@@ -1600,12 +1604,7 @@
       "id TEXT primary key, "
       "name TEXT, "
       "store_birthday TEXT, "
-      "db_create_version TEXT, "
-      "db_create_time INT, "
-      "next_id INT default -2, "
       "cache_guid TEXT, "
-      // TODO(rlarocque, 124140): Remove notification_state field.
-      "notification_state BLOB, "
       "bag_of_chips BLOB"
       ")");
   return db_->Execute(query.c_str());
@@ -1721,7 +1720,7 @@
 }
 
 bool DirectoryBackingStore::needs_column_refresh() const {
-  return needs_column_refresh_;
+  return needs_metas_column_refresh_ || needs_share_info_column_refresh_;
 }
 
 void DirectoryBackingStore::ResetAndCreateConnection() {
diff --git a/sync/syncable/directory_backing_store.h b/sync/syncable/directory_backing_store.h
index 422d13d..e3c85982 100644
--- a/sync/syncable/directory_backing_store.h
+++ b/sync/syncable/directory_backing_store.h
@@ -173,6 +173,7 @@
   bool MigrateVersion86To87();
   bool MigrateVersion87To88();
   bool MigrateVersion88To89();
+  bool MigrateVersion89To90();
 
   // Accessor for needs_column_refresh_.  Used in tests.
   bool needs_column_refresh() const;
@@ -249,7 +250,8 @@
 
   // Set to true if migration left some old columns around that need to be
   // discarded.
-  bool needs_column_refresh_;
+  bool needs_metas_column_refresh_;
+  bool needs_share_info_column_refresh_;
 
   // We keep a copy of the Closure so we reinstall it when the underlying
   // sql::Connection is destroyed/recreated.
diff --git a/sync/syncable/directory_backing_store_unittest.cc b/sync/syncable/directory_backing_store_unittest.cc
index 24a2014..56e91b0 100644
--- a/sync/syncable/directory_backing_store_unittest.cc
+++ b/sync/syncable/directory_backing_store_unittest.cc
@@ -100,9 +100,10 @@
   void SetUpVersion87Database(sql::Connection* connection);
   void SetUpVersion88Database(sql::Connection* connection);
   void SetUpVersion89Database(sql::Connection* connection);
+  void SetUpVersion90Database(sql::Connection* connection);
 
   void SetUpCurrentDatabaseAndCheckVersion(sql::Connection* connection) {
-    SetUpVersion89Database(connection);  // Prepopulates data.
+    SetUpVersion90Database(connection);  // Prepopulates data.
     scoped_ptr<TestDirectoryBackingStore> dbs(
         new TestDirectoryBackingStore(GetUsername(), connection));
     ASSERT_EQ(kCurrentDBVersion, dbs->GetVersion());
@@ -2791,7 +2792,6 @@
   ASSERT_TRUE(connection->CommitTransaction());
 }
 
-
 void MigrationTest::SetUpVersion89Database(sql::Connection* connection) {
   ASSERT_TRUE(connection->is_open());
   ASSERT_TRUE(connection->BeginTransaction());
@@ -2905,6 +2905,117 @@
   ASSERT_TRUE(connection->CommitTransaction());
 }
 
+void MigrationTest::SetUpVersion90Database(sql::Connection* connection) {
+  ASSERT_TRUE(connection->is_open());
+  ASSERT_TRUE(connection->BeginTransaction());
+  ASSERT_TRUE(connection->Execute(
+      "CREATE TABLE share_version (id VARCHAR(128) primary key, data INT);"
+      "INSERT INTO 'share_version' VALUES('nick@chromium.org',90);"
+      "CREATE TABLE models (model_id BLOB primary key, progress_marker BLOB, tr"
+         "ansaction_version BIGINT default 0, context BLOB);"
+      "INSERT INTO 'models' VALUES(X'C2881000',X'0888810218B605',1,NULL);"
+      "CREATE TABLE 'metas'(metahandle bigint primary key ON CONFLICT FAIL,base"
+         "_version bigint default -1,server_version bigint default 0,local_exte"
+         "rnal_id bigint default 0,transaction_version bigint default 0,mtime b"
+         "igint default 0,server_mtime bigint default 0,ctime bigint default 0,"
+         "server_ctime bigint default 0,id varchar(255) default 'r',parent_id v"
+         "archar(255) default 'r',server_parent_id varchar(255) default 'r',is_"
+         "unsynced bit default 0,is_unapplied_update bit default 0,is_del bit d"
+         "efault 0,is_dir bit default 0,server_is_dir bit default 0,server_is_d"
+         "el bit default 0,non_unique_name varchar,server_non_unique_name varch"
+         "ar(255),unique_server_tag varchar,unique_client_tag varchar,unique_bo"
+         "okmark_tag varchar,specifics blob,server_specifics blob,base_server_s"
+         "pecifics blob,server_unique_position blob,unique_position blob,attach"
+         "ment_metadata blob,server_attachment_metadata blob);"
+      "INSERT INTO 'metas' VALUES(1,-1,0,0,0,"
+         META_PROTO_TIMES_VALS(1)
+         ",'r','r','r',0,0,0,1,0,0,NULL,NULL,NULL,NULL,X'',X'',X'',NULL,X'2200'"
+         ",X'2200',NULL,NULL);"
+      "INSERT INTO 'metas' VALUES(6,694,694,6,0,"
+         META_PROTO_TIMES_VALS(6)
+         ",'s_ID_6','s_ID_9','s_ID_9',0,0,0,1,1,0,'The Internet','The Internet'"
+         ",NULL,NULL,X'6754307476346749735A5734654D653273625336557753582F77673D"
+         "',X'C2881000',X'C2881000',NULL,X'22247FFFFFFFFFC000006754307476346749"
+         "735A5734654D653273625336557753582F77673D',X'22247FFFFFFFFFC0000067543"
+         "07476346749735A5734654D653273625336557753582F77673D',NULL,NULL);"
+      "INSERT INTO 'metas' VALUES(7,663,663,0,0,"
+         META_PROTO_TIMES_VALS(7)
+         ",'s_ID_7','r','r',0,0,0,1,1,0,'Google Chrome','Google Chrome','google"
+         "_chrome',NULL,X'',NULL,NULL,NULL,X'2200',X'2200',NULL,NULL);"
+      "INSERT INTO 'metas' VALUES(8,664,664,0,0,"
+         META_PROTO_TIMES_VALS(8)
+         ",'s_ID_8','s_ID_7','s_ID_7',0,0,0,1,1,0,'Bookmarks','Bookmarks','goog"
+         "le_chrome_bookmarks',NULL,X'',X'C2881000',X'C2881000',NULL,X'2200',X'"
+         "2200',NULL,NULL);"
+      "INSERT INTO 'metas' VALUES(9,665,665,1,0,"
+         META_PROTO_TIMES_VALS(9)
+         ",'s_ID_9','s_ID_8','s_ID_8',0,0,0,1,1,0,'Bookmark Bar','Bookmark Bar'"
+         ",'bookmark_bar',NULL,X'',X'C2881000',X'C2881000',NULL,X'2200',X'2200'"
+         ",NULL,NULL);"
+      "INSERT INTO 'metas' VALUES(10,666,666,2,0,"
+         META_PROTO_TIMES_VALS(10)
+         ",'s_ID_10','s_ID_8','s_ID_8',0,0,0,1,1,0,'Other Bookmarks','Other Boo"
+         "kmarks','other_bookmarks',NULL,X'',X'C2881000',X'C2881000',NULL,X'220"
+         "0',X'2200',NULL,NULL);"
+      "INSERT INTO 'metas' VALUES(11,683,683,8,0,"
+         META_PROTO_TIMES_VALS(11)
+         ",'s_ID_11','s_ID_6','s_ID_6',0,0,0,0,0,0,'Home (The Chromium Projects"
+         ")','Home (The Chromium Projects)',NULL,NULL,X'50514C784A456D623579366"
+         "267644237646A7A2B62314130346E493D',X'C28810220A18687474703A2F2F646576"
+         "2E6368726F6D69756D2E6F72672F1206414741545741',X'C28810290A1D687474703"
+         "A2F2F6465762E6368726F6D69756D2E6F72672F6F7468657212084146414756415346"
+         "',NULL,X'22247FFFFFFFFFF0000050514C784A456D623579366267644237646A7A2B"
+         "62314130346E493D',X'22247FFFFFFFFFF0000050514C784A456D623579366267644"
+         "237646A7A2B62314130346E493D',NULL,NULL);"
+      "INSERT INTO 'metas' VALUES(12,685,685,9,0,"
+         META_PROTO_TIMES_VALS(12)
+         ",'s_ID_12','s_ID_6','s_ID_6',0,0,0,1,1,0,'Extra Bookmarks','Extra Boo"
+         "kmarks',NULL,NULL,X'7867626A704A646134635A6F616C376A49513338734B46324"
+         "837773D',X'C2881000',X'C2881000',NULL,X'222480000000000000007867626A7"
+         "04A646134635A6F616C376A49513338734B46324837773D',X'222480000000000000"
+         "007867626A704A646134635A6F616C376A49513338734B46324837773D',NULL,NULL"
+         ");"
+      "INSERT INTO 'metas' VALUES(13,687,687,10,0,"
+         META_PROTO_TIMES_VALS(13)
+         ",'s_ID_13','s_ID_6','s_ID_6',0,0,0,0,0,0,'ICANN | Internet Corporatio"
+         "n for Assigned Names and Numbers','ICANN | Internet Corporation for A"
+         "ssigned Names and Numbers',NULL,NULL,X'3142756B572F774176695650417967"
+         "2B304A614A514B3452384A413D',X'C28810240A15687474703A2F2F7777772E69636"
+         "16E6E2E636F6D2F120B504E474158463041414646',X'C28810200A15687474703A2F"
+         "2F7777772E6963616E6E2E636F6D2F120744414146415346',NULL,X'22247FFFFFFF"
+         "FFF200003142756B572F7741766956504179672B304A614A514B3452384A413D',X'2"
+         "2247FFFFFFFFFF200003142756B572F7741766956504179672B304A614A514B345238"
+         "4A413D',NULL,NULL);"
+      "INSERT INTO 'metas' VALUES(14,692,692,11,0,"
+         META_PROTO_TIMES_VALS(14)
+         ",'s_ID_14','s_ID_6','s_ID_6',0,0,0,0,0,0,'The WebKit Open Source Proj"
+         "ect','The WebKit Open Source Project',NULL,NULL,X'5A5678314E797636457"
+         "9524D3177494F7236563159552F6E644C553D',X'C288101A0A12687474703A2F2F77"
+         "65626B69742E6F72672F1204504E4758',X'C288101C0A13687474703A2F2F7765626"
+         "B69742E6F72672F781205504E473259',NULL,X'222480000000001000005A5678314"
+         "E7976364579524D3177494F7236563159552F6E644C553D',X'222480000000001000"
+         "005A5678314E7976364579524D3177494F7236563159552F6E644C553D',NULL,NULL"
+         ");"
+      "CREATE TABLE deleted_metas (metahandle bigint primary key ON CONFLICT FA"
+         "IL,base_version bigint default -1,server_version bigint default 0,loc"
+         "al_external_id bigint default 0,transaction_version bigint default 0,"
+         "mtime bigint default 0,server_mtime bigint default 0,ctime bigint def"
+         "ault 0,server_ctime bigint default 0,id varchar(255) default 'r',pare"
+         "nt_id varchar(255) default 'r',server_parent_id varchar(255) default "
+         "'r',is_unsynced bit default 0,is_unapplied_update bit default 0,is_de"
+         "l bit default 0,is_dir bit default 0,server_is_dir bit default 0,serv"
+         "er_is_del bit default 0,non_unique_name varchar,server_non_unique_nam"
+         "e varchar(255),unique_server_tag varchar,unique_client_tag varchar,un"
+         "ique_bookmark_tag varchar,specifics blob,server_specifics blob,base_s"
+         "erver_specifics blob,server_unique_position blob,unique_position blob"
+         ",attachment_metadata blob,server_attachment_metadata blob);"
+      "CREATE TABLE 'share_info' (id TEXT primary key, name TEXT, store_birthda"
+         "y TEXT, cache_guid TEXT, bag_of_chips BLOB);"
+      "INSERT INTO 'share_info' VALUES('nick@chromium.org','nick@chromium.org',"
+         "'c27e9f59-08ca-46f8-b0cc-f16a2ed778bb','9010788312004066376x-66092343"
+         "93368420856x',NULL);"));
+  ASSERT_TRUE(connection->CommitTransaction());
+}
 
 TEST_F(DirectoryBackingStoreTest, MigrateVersion67To68) {
   sql::Connection connection;
@@ -3396,6 +3507,30 @@
   EXPECT_TRUE(dbs->needs_column_refresh());
 }
 
+TEST_F(DirectoryBackingStoreTest, MigrateVersion89To90) {
+  sql::Connection connection;
+  ASSERT_TRUE(connection.OpenInMemory());
+  SetUpVersion89Database(&connection);
+  ASSERT_TRUE(connection.DoesColumnExist("share_info", "db_create_version"));
+  ASSERT_TRUE(connection.DoesColumnExist("share_info", "db_create_time"));
+  ASSERT_TRUE(connection.DoesColumnExist("share_info", "next_id"));
+  ASSERT_TRUE(connection.DoesColumnExist("share_info", "notification_state"));
+
+  scoped_ptr<TestDirectoryBackingStore> dbs(
+      new TestDirectoryBackingStore(GetUsername(), &connection));
+  ASSERT_TRUE(dbs->MigrateVersion89To90());
+  ASSERT_EQ(90, dbs->GetVersion());
+  EXPECT_TRUE(dbs->needs_column_refresh());
+
+  ASSERT_TRUE(dbs->RefreshColumns());
+  EXPECT_FALSE(dbs->needs_column_refresh());
+
+  ASSERT_FALSE(connection.DoesColumnExist("share_info", "db_create_version"));
+  ASSERT_FALSE(connection.DoesColumnExist("share_info", "db_create_time"));
+  ASSERT_FALSE(connection.DoesColumnExist("share_info", "next_id"));
+  ASSERT_FALSE(connection.DoesColumnExist("share_info", "notification_state"));
+}
+
 // The purpose of this test case is to make it easier to get a dump of the
 // database so you can implement a SetUpVersionYDatabase method.  Here's what
 // you should do:
@@ -3417,13 +3552,13 @@
   {
     sql::Connection connection;
     ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    SetUpVersion88Database(&connection);  // Update this.
+    SetUpVersion89Database(&connection);  // Update this.
 
     scoped_ptr<TestDirectoryBackingStore> dbs(
         new TestDirectoryBackingStore(GetUsername(), &connection));
-    ASSERT_TRUE(dbs->MigrateVersion88To89());  // Update this.
+    ASSERT_TRUE(dbs->MigrateVersion89To90());  // Update this.
     ASSERT_TRUE(LoadAndIgnoreReturnedData(dbs.get()));
-    EXPECT_EQ(89, dbs->GetVersion());  // Update this.
+    EXPECT_EQ(90, dbs->GetVersion());  // Update this.
     ASSERT_FALSE(dbs->needs_column_refresh());
   }
   // Set breakpoint here.
@@ -3530,6 +3665,9 @@
     case 89:
       SetUpVersion89Database(&connection);
       break;
+    case 90:
+      SetUpVersion90Database(&connection);
+      break;
     default:
       // If you see this error, it may mean that you've increased the
       // database version number but you haven't finished adding unit tests
@@ -3581,9 +3719,6 @@
   // Removed extended attributes in Version 72.
   ASSERT_FALSE(connection.DoesTableExist("extended_attributes"));
 
-  // Columns added in Version 73.
-  ASSERT_TRUE(connection.DoesColumnExist("share_info", "notification_state"));
-
   // Column replaced in version 75.
   ASSERT_TRUE(connection.DoesColumnExist("models", "progress_marker"));
   ASSERT_FALSE(connection.DoesColumnExist("models", "last_download_timestamp"));
@@ -3630,6 +3765,12 @@
   ASSERT_TRUE(
       connection.DoesColumnExist("metas", "server_attachment_metadata"));
 
+  // Columns removed in version 90.
+  ASSERT_FALSE(connection.DoesColumnExist("share_info", "db_create_version"));
+  ASSERT_FALSE(connection.DoesColumnExist("share_info", "db_create_time"));
+  ASSERT_FALSE(connection.DoesColumnExist("share_info", "next_id"));
+  ASSERT_FALSE(connection.DoesColumnExist("share_info", "notification_state"));
+
   // Check download_progress state (v75 migration)
   ASSERT_EQ(694,
       dir_info.kernel_info.download_progress[BOOKMARKS]
diff --git a/sync/test/test_directory_backing_store.h b/sync/test/test_directory_backing_store.h
index 1e71816..53f89e56 100644
--- a/sync/test/test_directory_backing_store.h
+++ b/sync/test/test_directory_backing_store.h
@@ -52,6 +52,7 @@
   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion86To87);
   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion87To88);
   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion88To89);
+  FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion89To90);
   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, DetectInvalidPosition);
   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, ModelTypeIds);
   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, Corruption);
diff --git a/testing/android/driver/BUILD.gn b/testing/android/driver/BUILD.gn
index 436ac63c..e99e350 100644
--- a/testing/android/driver/BUILD.gn
+++ b/testing/android/driver/BUILD.gn
@@ -11,6 +11,7 @@
   testonly = true
 
   deps = [
+    "//base:base_java_test_support",
     "//testing/android/appurify_support:appurify_support_java",
     "//testing/android/broker:broker_java",
     "//testing/android/reporter:reporter_java",
diff --git a/testing/android/driver/java/src/org/chromium/test/driver/OnDeviceInstrumentationDriver.java b/testing/android/driver/java/src/org/chromium/test/driver/OnDeviceInstrumentationDriver.java
index c209ac7..f9b31b03 100644
--- a/testing/android/driver/java/src/org/chromium/test/driver/OnDeviceInstrumentationDriver.java
+++ b/testing/android/driver/java/src/org/chromium/test/driver/OnDeviceInstrumentationDriver.java
@@ -13,6 +13,7 @@
 import android.test.InstrumentationTestRunner;
 import android.util.Log;
 
+import org.chromium.base.test.util.ScalableTimeout;
 import org.chromium.test.broker.OnDeviceInstrumentationBroker;
 import org.chromium.test.reporter.TestStatusReceiver;
 import org.chromium.test.reporter.TestStatusReporter;
@@ -21,8 +22,10 @@
 
 import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.IOException;
+import java.io.OutputStreamWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -44,6 +47,8 @@
             "org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetPackage";
     private static final String EXTRA_TARGET_CLASS =
             "org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetClass";
+    private static final String EXTRA_TIMEOUT_SCALE =
+            "org.chromium.test.driver.OnDeviceInstrumentationDriver.TimeoutScale";
 
     private static final Pattern COMMA = Pattern.compile(",");
     private static final int TEST_WAIT_TIMEOUT = 5 * TestStatusReporter.HEARTBEAT_INTERVAL_MS;
@@ -54,6 +59,7 @@
     private String mTargetClass;
     private String mTargetPackage;
     private List<String> mTestClasses;
+    private String mTimeoutScale;
 
     /** Parse any arguments and prepare to run tests.
 
@@ -101,6 +107,18 @@
             mTargetArgs.remove(EXTRA_TEST_LIST_FILE);
         }
 
+        mTimeoutScale = arguments.getString(EXTRA_TIMEOUT_SCALE);
+        if (mTimeoutScale != null) {
+            try {
+                OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
+                        new FileOutputStream(ScalableTimeout.PROPERTY_FILE));
+                outputStreamWriter.write(mTimeoutScale);
+                outputStreamWriter.close();
+            } catch (IOException e) {
+                Log.e(TAG, "Error writing " + ScalableTimeout.PROPERTY_FILE, e);
+            }
+        }
+
         if (mTestClasses.isEmpty()) {
             fail("No tests.");
             return;
@@ -129,6 +147,11 @@
     @Override
     public void onDestroy() {
         super.onDestroy();
+        if (mTimeoutScale != null) {
+            if (!new File(ScalableTimeout.PROPERTY_FILE).delete()) {
+                Log.e(TAG, "Error deleting " + ScalableTimeout.PROPERTY_FILE);
+            }
+        }
     }
 
     private class Driver implements Runnable {
diff --git a/testing/android/on_device_instrumentation.gyp b/testing/android/on_device_instrumentation.gyp
index 12e0f35..0828559 100644
--- a/testing/android/on_device_instrumentation.gyp
+++ b/testing/android/on_device_instrumentation.gyp
@@ -38,6 +38,7 @@
             'broker_java',
             'reporter_java',
             'appurify_support.gyp:appurify_support_java',
+            '../../base/base.gyp:base_java_test_support',
           ],
           'variables': {
             'apk_name': '<(driver_apk_name)',
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index c54c5a356..18fd914 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.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: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.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: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/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index feb0ac1..5aec1d8 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -193,7 +193,8 @@
           "--enable-local-file-accesses",
           "--enable-cma-media-pipeline",
           "--ozone-platform=cast",
-          "--no-sandbox"
+          "--no-sandbox",
+          "--test-launcher-jobs=1"
         ],
         "test": "cast_shell_browser_test"
       },
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 565a91720..40e4a884 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -1,5 +1,21 @@
 {
-  "Android MotoE Perf": {
+  "Android Galaxy S5 Perf (1)": {
+    "scripts": [
+      {
+        "name": "host_info",
+        "script": "host_info.py"
+      }
+    ]
+  },
+  "Android Galaxy S5 Perf (2)": {
+    "scripts": [
+      {
+        "name": "host_info",
+        "script": "host_info.py"
+      }
+    ]
+  },
+  "Android Galaxy S5 Perf (3)": {
     "scripts": [
       {
         "name": "host_info",
@@ -21,7 +37,15 @@
       }
     ]
   },
-  "Android Nexus10 Perf": {
+  "Android Nexus5 Perf (1)": {
+    "scripts": [
+      {
+        "name": "host_info",
+        "script": "host_info.py"
+      }
+    ]
+  },
+  "Android Nexus5 Perf (2)": {
     "scripts": [
       {
         "name": "host_info",
@@ -43,7 +67,30 @@
       }
     ]
   },
-  "Android Nexus4 Perf": {
+  "Android Nexus6 Perf (1)": {
+    "scripts": [
+      {
+        "name": "host_info",
+        "script": "host_info.py"
+      }
+    ]
+  },
+  "Android Nexus6 Perf (2)": {
+    "scripts": [
+      {
+        "name": "host_info",
+        "script": "host_info.py"
+      },
+      {
+        "args": [
+          "cc_perftests"
+        ],
+        "name": "cc_perftests",
+        "script": "gtest_perf_test.py"
+      }
+    ]
+  },
+  "Android Nexus7v2 Perf (1)": {
     "scripts": [
       {
         "name": "host_info",
@@ -65,7 +112,7 @@
       }
     ]
   },
-  "Android Nexus5 Perf": {
+  "Android Nexus7v2 Perf (2)": {
     "scripts": [
       {
         "name": "host_info",
@@ -87,22 +134,15 @@
       }
     ]
   },
-  "Android Nexus6 Perf": {
+  "Android Nexus9 Perf (1)": {
     "scripts": [
       {
         "name": "host_info",
         "script": "host_info.py"
-      },
-      {
-        "args": [
-          "cc_perftests"
-        ],
-        "name": "cc_perftests",
-        "script": "gtest_perf_test.py"
       }
     ]
   },
-  "Android Nexus7v2 Perf": {
+  "Android Nexus9 Perf (2)": {
     "scripts": [
       {
         "name": "host_info",
@@ -124,29 +164,15 @@
       }
     ]
   },
-  "Android Nexus9 Perf": {
+  "Android One Perf (1)": {
     "scripts": [
       {
         "name": "host_info",
         "script": "host_info.py"
-      },
-      {
-        "args": [
-          "gpu_perftests"
-        ],
-        "name": "gpu_perftests",
-        "script": "gtest_perf_test.py"
-      },
-      {
-        "args": [
-          "cc_perftests"
-        ],
-        "name": "cc_perftests",
-        "script": "gtest_perf_test.py"
       }
     ]
   },
-  "Android One Perf": {
+  "Android One Perf (2)": {
     "scripts": [
       {
         "name": "host_info",
diff --git a/testing/buildbot/chromium.webrtc.fyi.json b/testing/buildbot/chromium.webrtc.fyi.json
index 5fd7dcd..72d3002 100644
--- a/testing/buildbot/chromium.webrtc.fyi.json
+++ b/testing/buildbot/chromium.webrtc.fyi.json
@@ -12,111 +12,12 @@
   "Linux Builder": {
     "additional_compile_targets": [
       "browser_tests",
-      "chromium_builder_webrtc",
-      "content_browsertests",
-      "content_unittests"
-    ]
-  },
-  "Linux GN": {
-    "additional_compile_targets": [
-      "accessibility_unittests",
-      "app_list_unittests",
-      "aura_unittests",
-      "base_unittests",
-      "browser_tests",
-      "cacheinvalidation_unittests",
-      "cast_unittests",
-      "cc_unittests",
-      "chromedriver_unittests",
-      "components_browsertests",
-      "components_unittests",
       "content_browsertests",
       "content_unittests",
-      "crypto_unittests",
-      "dbus_unittests",
-      "device_unittests",
-      "display_unittests",
-      "events_unittests",
-      "extensions_browsertests",
-      "extensions_unittests",
-      "gcm_unit_tests",
-      "gfx_unittests",
-      "gn_unittests",
-      "google_apis_unittests",
-      "gpu_unittests",
-      "interactive_ui_tests",
-      "ipc_mojo_unittests",
-      "ipc_tests",
-      "jingle_unittests",
-      "mandoline:all",
+      "frame_analyzer",
       "media_unittests",
-      "media_blink_unittests",
-      "net_unittests",
-      "ppapi_unittests",
-      "printing_unittests",
-      "remoting_unittests",
-      "sandbox_linux_unittests",
-      "skia_unittests",
-      "sql_unittests",
-      "sync_integration_tests",
-      "sync_unit_tests",
-      "ui_base_unittests",
-      "ui_touch_selection_unittests",
-      "unit_tests",
-      "url_unittests",
-      "views_unittests",
-      "wm_unittests"
-    ]
-  },
-  "Linux GN (dbg)": {
-    "additional_compile_targets": [
-      "accessibility_unittests",
-      "app_list_unittests",
-      "aura_unittests",
-      "base_unittests",
-      "browser_tests",
-      "cacheinvalidation_unittests",
-      "cast_unittests",
-      "cc_unittests",
-      "chromedriver_unittests",
-      "components_browsertests",
-      "components_unittests",
-      "content_browsertests",
-      "content_unittests",
-      "crypto_unittests",
-      "dbus_unittests",
-      "device_unittests",
-      "display_unittests",
-      "events_unittests",
-      "extensions_browsertests",
-      "extensions_unittests",
-      "gcm_unit_tests",
-      "gfx_unittests",
-      "gn_unittests",
-      "google_apis_unittests",
-      "gpu_unittests",
-      "interactive_ui_tests",
-      "ipc_mojo_unittests",
-      "ipc_tests",
-      "jingle_unittests",
-      "mandoline:all",
-      "media_unittests",
-      "media_blink_unittests",
-      "net_unittests",
-      "ppapi_unittests",
-      "printing_unittests",
-      "remoting_unittests",
-      "sandbox_linux_unittests",
-      "skia_unittests",
-      "sql_unittests",
-      "sync_integration_tests",
-      "sync_unit_tests",
-      "ui_base_unittests",
-      "ui_touch_selection_unittests",
-      "unit_tests",
-      "url_unittests",
-      "views_unittests",
-      "wm_unittests"
+      "midi_unittests",
+      "rgba_to_i420_converter"
     ]
   },
   "Linux Tester": {
@@ -132,64 +33,24 @@
   },
   "Mac GN": {
     "additional_compile_targets": [
-      "accessibility_unittests",
-      "base_unittests",
-      "cacheinvalidation_unittests",
-      "cast_unittests",
-      "cc_unittests",
-      "chromedriver_unittests",
-      "crypto_unittests",
-      "gcm_unit_tests",
-      "gn_unittests",
-      "gpu_unittests",
-      "ipc_tests",
-      "jingle_unittests",
+      "browser_tests",
+      "content_browsertests",
+      "content_unittests",
+      "frame_analyzer",
       "media_unittests",
-      "media_blink_unittests",
-      "mojo_common_unittests",
-      "mojo_public_bindings_unittests",
-      "mojo_public_environment_unittests",
-      "mojo_public_system_unittests",
-      "mojo_public_utility_unittests",
-      "mojo_system_unittests",
-      "ppapi_unittests",
-      "printing_unittests",
-      "skia_unittests",
-      "sql_unittests",
-      "sync_unit_tests",
-      "ui_base_unittests",
-      "url_unittests"
+      "midi_unittests",
+      "rgba_to_i420_converter"
     ]
   },
   "Mac GN (dbg)": {
     "additional_compile_targets": [
-      "accessibility_unittests",
-      "base_unittests",
-      "cacheinvalidation_unittests",
-      "cast_unittests",
-      "cc_unittests",
-      "chromedriver_unittests",
-      "crypto_unittests",
-      "gcm_unit_tests",
-      "gn_unittests",
-      "gpu_unittests",
-      "ipc_tests",
-      "jingle_unittests",
+      "browser_tests",
+      "content_browsertests",
+      "content_unittests",
+      "frame_analyzer",
       "media_unittests",
-      "media_blink_unittests",
-      "mojo_common_unittests",
-      "mojo_public_bindings_unittests",
-      "mojo_public_environment_unittests",
-      "mojo_public_system_unittests",
-      "mojo_public_utility_unittests",
-      "mojo_system_unittests",
-      "ppapi_unittests",
-      "printing_unittests",
-      "skia_unittests",
-      "sql_unittests",
-      "sync_unit_tests",
-      "ui_base_unittests",
-      "url_unittests"
+      "midi_unittests",
+      "rgba_to_i420_converter"
     ]
   },
   "Mac Tester": {
@@ -205,108 +66,26 @@
   },
   "Win x64 GN": {
     "additional_compile_targets": [
-      "accessibility_unittests",
-      "app_list_unittests",
-      "app_shell_unittests",
-      "ash_unittests",
-      "aura_unittests",
-      "cacheinvalidation_unittests",
-      "cast_unittests",
-      "cc_unittests",
-      "chrome",
-      "chrome_elf_unittests",
-      "chromedriver_unittests",
-      "components_browsertests",
-      "components_unittests",
-      "compositor_unittests",
+      "browser_tests",
+      "crash_service",
       "content_browsertests",
       "content_unittests",
-      "courgette_unittests",
-      "crypto_unittests",
-      "device_unittests",
-      "events_unittests",
-      "extensions_browsertests",
-      "extensions_unittests",
-      "gcm_unit_tests",
-      "gfx_unittests",
-      "google_apis_unittests",
-      "gpu_unittests",
-      "interactive_ui_tests",
-      "ipc_mojo_unittests",
-      "ipc_tests",
-      "jingle_unittests",
-      "keyboard_unittests",
-      "mandoline:all",
+      "frame_analyzer",
       "media_unittests",
-      "media_blink_unittests",
-      "message_center_unittests",
-      "ppapi_unittests",
-      "printing_unittests",
-      "sbox_integration_tests",
-      "sbox_unittests",
-      "sbox_validation_tests",
-      "skia_unittests",
-      "sql_unittests",
-      "sync_integration_tests",
-      "sync_unit_tests",
-      "ui_base_unittests",
-      "ui_touch_selection_unittests",
-      "url_unittests",
-      "views_unittests",
-      "wm_unittests"
+      "midi_unittests",
+      "rgba_to_i420_converter"
     ]
   },
   "Win x64 GN (dbg)": {
     "additional_compile_targets": [
-      "accessibility_unittests",
-      "app_list_unittests",
-      "app_shell_unittests",
-      "ash_unittests",
-      "aura_unittests",
-      "cacheinvalidation_unittests",
-      "cast_unittests",
-      "cc_unittests",
-      "chrome",
-      "chrome_elf_unittests",
-      "chromedriver_unittests",
-      "components_browsertests",
-      "components_unittests",
-      "compositor_unittests",
+      "browser_tests",
+      "crash_service",
       "content_browsertests",
       "content_unittests",
-      "courgette_unittests",
-      "crypto_unittests",
-      "device_unittests",
-      "events_unittests",
-      "extensions_browsertests",
-      "extensions_unittests",
-      "gcm_unit_tests",
-      "gfx_unittests",
-      "google_apis_unittests",
-      "gpu_unittests",
-      "interactive_ui_tests",
-      "ipc_mojo_unittests",
-      "ipc_tests",
-      "jingle_unittests",
-      "keyboard_unittests",
-      "mandoline:all",
+      "frame_analyzer",
       "media_unittests",
-      "media_blink_unittests",
-      "message_center_unittests",
-      "ppapi_unittests",
-      "printing_unittests",
-      "sbox_integration_tests",
-      "sbox_unittests",
-      "sbox_validation_tests",
-      "skia_unittests",
-      "sql_unittests",
-      "sync_integration_tests",
-      "sync_unit_tests",
-      "ui_base_unittests",
-      "ui_touch_selection_unittests",
-      "url_unittests",
-      "views_unittests",
-      "wm_unittests"
+      "midi_unittests",
+      "rgba_to_i420_converter"
     ]
   },
   "Win10 Tester": {
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 95503bb1..aea3ffb 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -73,12 +73,12 @@
     "type": "console_test_launcher",
   },
   "blink_heap_unittests": {
-    "label": "//third_party/WebKit/public:blink_heap_unittests",
-    "type": "unknown",
+    "label": "//third_party/WebKit/Source/platform:blink_heap_unittests",
+    "type": "console_test_launcher",
   },
   "blink_platform_unittests": {
-    "label": "//third_party/WebKit/public:blink_platform_unittests",
-    "type": "unknown",
+    "label": "//third_party/WebKit/Source/platform:blink_platform_unittests",
+    "type": "console_test_launcher",
   },
   "breakpad_unittests": {
     "label": "//breakpad:breakpad_unittests",
@@ -468,15 +468,15 @@
     "type": "unknown",
   },
   "webkit_unit_tests": {
-    "label": "//third_party/WebKit/public:webkit_unit_tests",
-    "type": "unknown",
+    "label": "//third_party/WebKit/Source/web:webkit_unit_tests",
+    "type": "console_test_launcher",
   },
   "wm_unittests": {
     "label": "//ui/wm:wm_unittests",
     "type": "windowed_test_launcher",
   },
   "wtf_unittests": {
-    "label": "//third_party/WebKit/public:wtf_unittests",
-    "type": "unknown",
+    "label": "//third_party/WebKit/Source/wtf:wtf_unittests",
+    "type": "console_test_launcher",
   },
 }
diff --git a/testing/variations/fieldtrial_testing_config_android.json b/testing/variations/fieldtrial_testing_config_android.json
index c500a5df..6cdbc26 100644
--- a/testing/variations/fieldtrial_testing_config_android.json
+++ b/testing/variations/fieldtrial_testing_config_android.json
@@ -4,6 +4,11 @@
             "group_name": "Disabled"
         }
     ],
+    "AutodetectEncoding": [
+        {
+            "group_name": "Enabled"
+        }
+    ],
     "AutofillClassifier": [
         {
             "group_name": "Enabled"
@@ -164,6 +169,15 @@
             }
         }
     ],
+    "NTPPopularSites": [
+        {
+            "group_name": "Enabled",
+            "params": {
+                "country": "IN",
+                "version": "4"
+            }
+        }
+    ],
     "NetworkQualityEstimator": [
         {
             "group_name": "Enabled",
diff --git a/testing/variations/fieldtrial_testing_config_chromeos.json b/testing/variations/fieldtrial_testing_config_chromeos.json
index 512cc21..5dbcc1c 100644
--- a/testing/variations/fieldtrial_testing_config_chromeos.json
+++ b/testing/variations/fieldtrial_testing_config_chromeos.json
@@ -87,6 +87,14 @@
             "group_name": "DontShowAndDontSend"
         }
     ],
+    "SafeBrowsingUnverifiedDownloads": [
+        {
+            "group_name": "DisableByParameterExe",
+            "params": {
+                "blacklist": ".exe"
+            }
+        }
+    ],
     "SdchPersistence": [
         {
             "group_name": "Enabled"
diff --git a/testing/variations/fieldtrial_testing_config_linux.json b/testing/variations/fieldtrial_testing_config_linux.json
index 44abad8b..a87ed38 100644
--- a/testing/variations/fieldtrial_testing_config_linux.json
+++ b/testing/variations/fieldtrial_testing_config_linux.json
@@ -113,6 +113,22 @@
             "group_name": "Disabled"
         }
     ],
+    "SafeBrowsingUnverifiedDownloads": [
+        {
+            "group_name": "DisableByParameterExe",
+            "params": {
+                "blacklist": ".exe"
+            }
+        }
+    ],
+    "SafeBrowsingUpdateFrequency": [
+        {
+            "group_name": "UpdateTime15m",
+            "params": {
+                "NextUpdateIntervalInMinutes": "15"
+            }
+        }
+    ],
     "SdchPersistence": [
         {
             "group_name": "Enabled"
diff --git a/testing/variations/fieldtrial_testing_config_mac.json b/testing/variations/fieldtrial_testing_config_mac.json
index 66a5c13..34acd243 100644
--- a/testing/variations/fieldtrial_testing_config_mac.json
+++ b/testing/variations/fieldtrial_testing_config_mac.json
@@ -128,6 +128,22 @@
             "group_name": "Disabled"
         }
     ],
+    "SafeBrowsingUnverifiedDownloads": [
+        {
+            "group_name": "DisableByParameterExe",
+            "params": {
+                "blacklist": ".exe"
+            }
+        }
+    ],
+    "SafeBrowsingUpdateFrequency": [
+        {
+            "group_name": "UpdateTime15m",
+            "params": {
+                "NextUpdateIntervalInMinutes": "15"
+            }
+        }
+    ],
     "SdchPersistence": [
         {
             "group_name": "Enabled"
diff --git a/testing/variations/fieldtrial_testing_config_win.json b/testing/variations/fieldtrial_testing_config_win.json
index ad8e316e..b1ffe0a 100644
--- a/testing/variations/fieldtrial_testing_config_win.json
+++ b/testing/variations/fieldtrial_testing_config_win.json
@@ -188,7 +188,7 @@
     ],
     "SRTPromptFieldTrial": [
         {
-            "group_name": "Default"
+            "group_name": "On"
         }
     ],
     "SafeBrowsingReportPhishingErrorLink": [
@@ -202,6 +202,22 @@
             "group_name": "Disabled"
         }
     ],
+    "SafeBrowsingUnverifiedDownloads": [
+        {
+            "group_name": "DisableByParameterExe",
+            "params": {
+                "blacklist": ".exe"
+            }
+        }
+    ],
+    "SafeBrowsingUpdateFrequency": [
+        {
+            "group_name": "UpdateTime15m",
+            "params": {
+                "NextUpdateIntervalInMinutes": "15"
+            }
+        }
+    ],
     "SdchPersistence": [
         {
             "group_name": "Enabled"
diff --git a/third_party/WebKit/LayoutTests/PRESUBMIT.py b/third_party/WebKit/LayoutTests/PRESUBMIT.py
index 0fb932d..de31265 100644
--- a/third_party/WebKit/LayoutTests/PRESUBMIT.py
+++ b/third_party/WebKit/LayoutTests/PRESUBMIT.py
@@ -58,7 +58,7 @@
         return input_api.os_path.join(input_api.PresubmitLocalPath(), *s.split('/'))
 
     def _local_path(s):
-        return input_api.os_path.join('LayoutTests', *s.split('/'))
+        return input_api.os_path.join('third_party', 'WebKit', 'LayoutTests', *s.split('/'))
 
     errors = []
     for group in groups:
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 44965d8..001aff2 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -69,14 +69,13 @@
 crbug.com/492664 [ Mac ] imported/csswg-test/css-writing-modes-3/bidi-isolate-002.html [ Failure ]
 crbug.com/492664 [ Win ] imported/csswg-test/css-writing-modes-3/bidi-override-005.html [ Failure ]
 crbug.com/492664 [ Win ] imported/csswg-test/css-writing-modes-3/bidi-plaintext-001.html [ Failure ]
-crbug.com/492664 imported/csswg-test/css-transitions-2/transitioncancel-001.html [ Failure ]
 crbug.com/418091 [ Mac10.6 ] fast/text/aat-morx.html [ Failure ]
 crbug.com/463358 [ Linux Mac ] svg/transforms/text-with-pattern-inside-transformed-html.xhtml [ Failure ]
 crbug.com/463358 [ Mac Linux Debug ] fast/backgrounds/transformed-body-html-background.html [ Failure ]
 crbug.com/463358 [ Mac Linux Debug ] css3/masking/clip-path-polygon-nonzero.html [ Failure ]
 crbug.com/463358 [ Mac Linux ] fast/transforms/transformed-caret.html [ Pass Failure ]
 crbug.com/463358 [ Mac Linux Debug ] fast/backgrounds/transformed-body-background.html [ Failure ]
-crbug.com/463358 [ Mac Linux ] svg/W3C-SVG-1.1/paths-data-02-t.svg [ Failure ]
+crbug.com/463358 [ Mac Linux Debug ] svg/W3C-SVG-1.1/paths-data-02-t.svg [ Failure ]
 crbug.com/463358 [ Mac Linux Debug ] css3/masking/clip-path-polygon.html [ Failure ]
 
 crbug.com/267206 [ Mac ] virtual/rootlayerscrolls/fast/scrolling/scrollbar-tickmarks-hittest.html [ Timeout ]
@@ -168,11 +167,16 @@
 crbug.com/518987 http/tests/xmlhttprequest/navigation-abort-detaches-frame.html [ Pass Timeout ]
 crbug.com/518988 [ Win7 ] http/tests/xmlhttprequest/xmlhttprequest-50ms-download-dispatch.html [ Failure Pass ]
 crbug.com/518989 [ Mac ] imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-002.xht [ Failure Pass Timeout ]
-crbug.com/518992 [ Win ] imported/web-platform-tests/user-timing/test_user_timing_measure.html [ Skip ]
-crbug.com/518993 [ Win ] imported/web-platform-tests/user-timing/test_user_timing_measure_navigation_timing.html [ Skip ]
 crbug.com/518995 media/track/media-element-move-to-new-document-assert.html [ Failure Pass ]
 crbug.com/518998 media/video-poster-after-loadedmetadata.html [ Failure Pass ]
 
+# These performance-sensitive user-timing tests are flaky in debug on all platforms, and flaky on all configurations of windows.
+# See: crbug.com/567965, crbug.com/518992, and crbug.com/518993
+crbug.com/567965 [ Debug ] imported/web-platform-tests/user-timing/test_user_timing_measure.html [ Skip ]
+crbug.com/518992 [ Win Release ] imported/web-platform-tests/user-timing/test_user_timing_measure.html [ Skip ]
+crbug.com/567965 [ Debug ] imported/web-platform-tests/user-timing/test_user_timing_mark.html [ Skip ]
+crbug.com/518993 [ Win ] imported/web-platform-tests/user-timing/test_user_timing_measure_navigation_timing.html [ Skip ]
+
 crbug.com/526594 [ Win ] plugins/webview-plugin-lifecycle.html [ Failure ]
 
 crbug.com/519001 storage/indexeddb/pending-version-change-stuck-works-with-terminate.html [ Pass Timeout ]
@@ -332,6 +336,11 @@
 crbug.com/561394 inspector/console/console-log-document-proto.html [ NeedsManualRebaseline ]
 crbug.com/561394 inspector/console/console-object-constructor-name.html [ NeedsManualRebaseline ]
 
+# ES6 makes (Native)Error.prototype not be an error instance
+crbug.com/568026 fast/dom/DOMException/XPathException.html [ NeedsManualRebaseline ]
+crbug.com/568026 fast/dom/DOMException/prototype-object.html [ NeedsManualRebaseline ]
+crbug.com/568026 storage/websql/transaction-error-callback.html [ NeedsManualRebaseline ]
+
 crbug.com/552433 svg/W3C-SVG-1.1/coords-units-02-b.svg [ Pass Failure ]
 crbug.com/552433 [ Linux Mac Win10 Win7 ] svg/dom/length-list-parser.html [ Failure Pass ]
 crbug.com/552433 [ Linux Mac Win10 Win7 ] svg/transforms/text-with-pattern-with-svg-transform.svg [ Failure Pass ]
@@ -350,8 +359,6 @@
 # Text::inDocument() returns false but should not.
 crbug.com/264138 dom/xhtml/level3/core/nodecomparedocumentposition38.xhtml [ Failure ]
 
-crbug.com/503626 virtual/gpu/fast/canvas/canvas-filter-shadow.html [ Failure ]
-
 crbug.com/240374 compositing/overlap-blending/reflection-opacity-huge.html [ Failure ]
 crbug.com/240374 compositing/overlap-blending/children-opacity-huge.html [ Failure ]
 crbug.com/240374 compositing/overlap-blending/children-opacity-no-overlap.html [ Failure ]
@@ -375,50 +382,7 @@
 crbug.com/510337 inspector/elements/styles-1/edit-value-url-with-color.html [ Slow ]
 
 # SPv2 paint properties are still being implemented.
-crbug.com/537409 virtual/spv2/paint/frames/frameset-with-stacking-context-and-not-stacking-context-children.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/frames/frameset-with-stacking-contexts.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/fixed-position-descendant-paint-offset.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/non-stacking-scroller-with-abspos-descendant-indirect.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/non-stacking-scroller-with-abspos-descendant.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/percentage-transform-paint-offset.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/change-transform.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/child-of-sub-pixel-offset-composited-layer.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/fixed-after-scroll.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/fixed-move-after-scroll.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/fixed-pos-inside-composited-intermediate-layer.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/fixed-scale.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/fixed-scroll-in-empty-root-layer.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/fixed-scroll-simple.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/fixed-table-cell.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/fixed-table-overflow-zindex.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/fixed-table-overflow.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/fixed-tranformed.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/fixed-under-composited-absolute-scrolled.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/intermediate-layout-position-clip.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/invalidate-paint-in-iframe-in-composited-layer.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/invalidate-when-leaving-squashed-layer.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/invalidations-on-composited-layers.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/negative-text-indent-with-overflow-hidden.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/overflow-hidden-in-overflow-hidden-scrolled.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/repaint-squashed-layer-in-rect.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/repaint-via-layout-offset.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/resize-repaint.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/scroll-fixed-layer-with-reflection.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/scroll-fixed-squahed-layer.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/scroll-fixed-reflected-layer.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/selection-change-in-iframe-with-relative-parent.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/selection-within-composited-scroller.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/should-not-clip-composited-overflow-scrolling-layer.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/squashing-inside-preserve-3d-element.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/text-match-highlight.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/transform-translate.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/tricky-element-removal-crash.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/invalidation/spv2/updating-scrolling-content.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/masks/fieldset-mask.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/overflow/fixed-background-scroll-in-frame.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/overflow/fixed-background-scroll.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/overflow/fixed-children-should-not-scroll.html [ Skip ]
-crbug.com/537409 virtual/spv2/paint/tables/tbody-transformed.html [ Skip ]
+crbug.com/537409 virtual/spv2/ [ Skip ]
 
 # In imported/web-platform-tests/html/, we prefer checking in failure
 # expectation files. The following tests with [ Failure ] don't have failure
@@ -756,8 +720,6 @@
 crbug.com/377696 printing/setPrinting.html [ Skip ]
 crbug.com/377696 printing/width-overflow.html [ Skip ]
 
-crbug.com/567039 fast/block/skip-cleaning-up-anonymous-wrappers-when-subtree-being-destroyed.html [ Skip ]
-
 # Reftests that needs investigation.
 crbug.com/397232 [ XP ] css2.1/20110323/c541-word-sp-000.htm [ Failure ]
 crbug.com/397232 [ XP ] css2.1/20110323/vertical-align-boxes-001.htm [ Failure ]
@@ -770,9 +732,18 @@
 crbug.com/396941 ietestcenter/css3/multicolumn/column-width-applies-to-010.htm [ Failure ]
 crbug.com/396941 ietestcenter/css3/multicolumn/column-width-applies-to-012.htm [ Failure ]
 crbug.com/396941 ietestcenter/css3/multicolumn/column-width-applies-to-015.htm [ Failure ]
-crbug.com/378610 svg/custom/focus-ring-text.svg [ Failure ]
+crbug.com/378610 [ Win ] svg/custom/focus-ring-text.svg [ Failure ]
+crbug.com/378610 [ Mac ] svg/custom/focus-ring-text.svg [ Failure Pass ]
 
-crbug.com/515454 css3/fonts/font-style-matching.html [ Skip ]
+crbug.com/523021 [ XP ] css3/fonts/font-style-matching-0.html [ Failure ]
+crbug.com/523021 [ XP ] css3/fonts/font-style-matching-1.html [ Failure ]
+crbug.com/523021 [ XP ] css3/fonts/font-style-matching-2.html [ Failure ]
+crbug.com/523021 [ XP ] css3/fonts/font-style-matching-3.html [ Failure ]
+crbug.com/523021 [ XP ] css3/fonts/font-style-matching-4.html [ Failure ]
+crbug.com/523021 [ XP ] css3/fonts/font-style-matching-5.html [ Failure ]
+crbug.com/523021 [ XP ] css3/fonts/font-style-matching-6.html [ Failure ]
+crbug.com/523021 [ XP ] css3/fonts/font-style-matching-7.html [ Failure ]
+crbug.com/523021 [ XP ] css3/fonts/font-style-matching-8.html [ Failure ]
 
 crbug.com/474987 [ Win Mac ] css3/flexbox/auto-margins.html [ Failure ]
 
@@ -915,7 +886,6 @@
 # Temporary until we start generating Trusty baselines.
 crbug.com/498021 [ Linux ] fast/text/unicode-fallback-font.html [ Failure ]
 crbug.com/498021 [ Linux ] http/tests/security/contentTypeOptions/nosniff-script-without-content-type-blocked.html [ Failure ]
-crbug.com/498021 [ Linux ] svg/custom/use-on-symbol-inside-pattern.svg [ Failure ]
 crbug.com/498021 [ Linux ] fast/forms/month/month-appearance-l10n.html [ Failure ]
 crbug.com/498021 [ Linux ] fast/text/ellipsis-stroked.html [ Failure ]
 crbug.com/498021 [ Linux ] fast/text/emphasis-complex.html [ Failure ]
@@ -923,9 +893,7 @@
 crbug.com/498021 [ Linux ] fast/text/international/hindi-whitespace.html [ Failure ]
 crbug.com/498021 [ Linux ] fast/text/international/thai-line-breaks.html [ Failure ]
 crbug.com/498021 [ Linux ] fast/text/selection-multiple-runs.html [ Failure ]
-crbug.com/498021 [ Linux ] svg/W3C-SVG-1.1/paths-data-03-f.svg [ Failure ]
 crbug.com/498021 [ Linux ] svg/W3C-SVG-1.1/text-align-08-b.svg [ Failure ]
-crbug.com/498021 [ Linux ] svg/custom/control-points-for-S-and-T.svg [ Failure ]
 crbug.com/498021 [ Linux ] editing/pasteboard/4944770-2.html [ Failure ]
 crbug.com/498021 [ Linux ] fast/encoding/invalid-UTF-8.html [ Failure ]
 crbug.com/498021 [ Linux ] fast/text/emoticons.html [ Failure ]
@@ -960,7 +928,6 @@
 crbug.com/521124 [ Win7 ] fast/text/international/text-combine-image-test.html [ Pass Failure ]
 crbug.com/521124 [ Win7 ] fast/css/font-weight-1.html [ Pass Failure ]
 crbug.com/521124 [ Win7 Release ] fast/text/justify-ideograph-vertical.html [ Pass Failure ]
-crbug.com/521124 [ Win7 Release ] fast/writing-mode/english-lr-text.html [ Pass Failure ]
 crbug.com/521124 [ Win7 ] fast/text/orientation-sideways.html [ Pass Failure ]
 
 # Temporary, until we stop use_system_harfbuzz on Linux including non-official builds
@@ -1021,8 +988,6 @@
 
 crbug.com/505415 [ XP ] accessibility/canvas-fallback-content-labels.html [ Failure ]
 
-crbug.com/506312 imported/csswg-test/css-pseudo-4/first-letter-001.html [ Failure ]
-
 # Mac10.10-specific failures that still need triaging.
 # Form controls need rebaseline because of the default font change.
 # If you see wider INPUT elements or narrower TEXTAREA elements, you may do just
@@ -1270,6 +1235,9 @@
 crbug.com/521730 [ Win10 ] svg/text/text-selection-fonts-01-t.svg [ Failure ]
 crbug.com/521730 [ Win10 ] svg/text/text-selection-intro-05-t.svg [ Failure ]
 
+# This test's results will be tweaked slightly by an upcoming Skia change.
+crbug.com/240827 svg/filters/feOffset.svg [ NeedsManualRebaseline ]
+
 crbug.com/550285 [ XP ] virtual/syncpaint/inspector/tracing/decode-resize.html [ Slow Pass Failure ]
 
 crbug.com/474759 fast/writing-mode/vertical-rl-replaced-selection.html [ Failure ]
@@ -1320,12 +1288,8 @@
 crbug.com/538717 [ Win Mac Linux ] http/tests/permissions/chromium/test-request-multiple-worker.html [ Failure Pass Timeout ]
 crbug.com/538717 [ Win Mac Linux ] http/tests/permissions/chromium/test-request-multiple-sharedworker.html [ Failure Pass Timeout ]
 
-crbug.com/541601 svg/overflow/overflow-on-outermost-svg-element-in-xhtml-defaults.xhtml [ Failure ]
-
 crbug.com/543369 [ Linux ] fast/forms/select/popup-menu-appearance-tall.html [ Failure ]
 
-crbug.com/545551 [ Win Mac ] svg/custom/repaint-shadow.svg [ Failure Pass ]
-
 crbug.com/546215 [ Android ] fast/inline-block/overflow-clip.html [ Failure ]
 
 crbug.com/548765 http/tests/inspector/console-fetch-logging.html [ Failure Pass Slow ]
@@ -1339,3 +1303,8 @@
 crbug.com/558574 [ Win7 ] fast/text/emphasis.html [ Failure ]
 
 crbug.com/561595 [ XP ] plugins/webview-plugin-scroll.html [ Failure ]
+crbug.com/561595 [ XP ] plugins/webview-plugin-nested-iframe-scroll.html [ Failure ]
+
+crbug.com/568157 [ XP ] virtual/syncpaint/fast/repaint/details-open-repaint.html [ Failure ]
+crbug.com/568157 [ XP ] virtual/syncpaint/fast/repaint/overflow-scroll-body-appear.html [ Failure ]
+crbug.com/568157 [ XP ] virtual/syncpaint/fast/repaint/resize-scrollable-iframe.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/W3CImportExpectations b/third_party/WebKit/LayoutTests/W3CImportExpectations
index d7c2fa7..1d911af 100644
--- a/third_party/WebKit/LayoutTests/W3CImportExpectations
+++ b/third_party/WebKit/LayoutTests/W3CImportExpectations
@@ -30,6 +30,7 @@
 imported/csswg-test/css-multicol-1 [ Skip ]
 imported/csswg-test/css-namespaces-1 [ Skip ]
 imported/csswg-test/css-page-3 [ Skip ]
+imported/csswg-test/css-pseudo-4 [ Skip ]
 imported/csswg-test/css-regions-1 [ Skip ]
 imported/csswg-test/css-ruby-1 [ Skip ]
 ## Owners: bjonesbe@adobe.com
@@ -42,6 +43,7 @@
 imported/csswg-test/css-text-decor-3 [ Skip ]
 imported/csswg-test/css-transforms-1 [ Skip ]
 imported/csswg-test/css-transitions-1 [ Skip ]
+imported/csswg-test/css-transitions-2 [ Skip ]
 imported/csswg-test/css-ui-3 [ Skip ]
 imported/csswg-test/css-values-3 [ Skip ]
 imported/csswg-test/css-variables-1 [ Skip ]
@@ -514,11 +516,7 @@
 imported/csswg-test/css-writing-modes-3/table-progression-srl-001.html [ Skip ]
 imported/csswg-test/css-writing-modes-3/table-progression-srl-002.html [ Skip ]
 imported/csswg-test/css-writing-modes-3/text-baseline-slr-009.xht [ Skip ]
-imported/csswg-test/css-writing-modes-3/text-baseline-slr-011.xht [ Skip ]
-imported/csswg-test/css-writing-modes-3/text-baseline-slr-013.xht [ Skip ]
 imported/csswg-test/css-writing-modes-3/text-baseline-srl-008.xht [ Skip ]
-imported/csswg-test/css-writing-modes-3/text-baseline-srl-010.xht [ Skip ]
-imported/csswg-test/css-writing-modes-3/text-baseline-srl-012.xht [ Skip ]
 imported/csswg-test/css-writing-modes-3/vertical-alignment-slr-029.xht [ Skip ]
 imported/csswg-test/css-writing-modes-3/vertical-alignment-slr-031.xht [ Skip ]
 imported/csswg-test/css-writing-modes-3/vertical-alignment-slr-033.xht [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/accessibility/presentational-leaf.html b/third_party/WebKit/LayoutTests/accessibility/presentational-leaf.html
new file mode 100644
index 0000000..cc2e5f4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/accessibility/presentational-leaf.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+
+<style>
+.hideAllContainers .container {
+    display: none;
+}
+</style>
+
+<div class="container" id="container1">
+  <img id="img1" src="missing-image.png" alt="Missing">
+</div>
+
+<script>
+test(function(t) {
+    var axImg1 = accessibilityController.accessibleElementById("img1");
+    assert_equals(axImg1.name, "Missing");
+    assert_equals(axImg1.childrenCount, 0);
+}, "An image exposes alt text as its name, and has no children.");
+</script>
+
+<div class="container" id="container2">
+  <img id="img2" src="missing-image.png" alt="Missing" role="presentation">
+</div>
+
+<script>
+test(function(t) {
+    var axImg2 = accessibilityController.accessibleElementById("img2");
+    assert_equals(axImg2, undefined);
+    var axContainer2 = accessibilityController.accessibleElementById("container2");
+    assert_equals(axContainer2.role, "AXRole: AXDiv");
+    assert_equals(axContainer2.childrenCount, 0);
+}, "A presentational image is missing from the accessibility tree entirely.");
+</script>
+
+<script>
+if (window.testRunner)
+    document.body.className = "hideAllContainers";
+</script>
diff --git a/third_party/WebKit/LayoutTests/animations/svg-animation-affects-use-elements-expected.html b/third_party/WebKit/LayoutTests/animations/svg-animation-affects-use-elements-expected.html
new file mode 100644
index 0000000..7f38a91
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/animations/svg-animation-affects-use-elements-expected.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<svg>
+  <rect x="100" y="50" width="100" height="40" fill="green" />
+  <rect x="100" y="100" width="100" height="40" fill="green" />
+</svg>
diff --git a/third_party/WebKit/LayoutTests/animations/svg-animation-affects-use-elements.html b/third_party/WebKit/LayoutTests/animations/svg-animation-affects-use-elements.html
new file mode 100644
index 0000000..3fcb8ad
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/animations/svg-animation-affects-use-elements.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<svg>
+  <defs>
+    <rect x="0" y="0" width="100" height="40" id="target" fill="green" />
+    <rect x="100" y="0" width="100" height="40" id="expected" fill="red" />
+    <use xlink:href="#target" id="use"/>
+  </defs>
+
+  <use y="50" xlink:href="#expected"/>
+  <use y="100" xlink:href="#expected"/>
+
+  <use y="50" xlink:href="#target"/>
+  <use y="100" xlink:href="#use"/>
+</svg>
+<script>
+target.animate([{'svg-x': '100'}, {'svg-x': '100'}], {fill: 'forwards'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/compositing/culling/scrolled-within-boxshadow-expected.png b/third_party/WebKit/LayoutTests/compositing/culling/scrolled-within-boxshadow-expected.png
new file mode 100644
index 0000000..17c85ce
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/culling/scrolled-within-boxshadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/culling/translated-boxshadow-expected.png b/third_party/WebKit/LayoutTests/compositing/culling/translated-boxshadow-expected.png
new file mode 100644
index 0000000..da750225
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/culling/translated-boxshadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/culling/unscrolled-within-boxshadow-expected.png b/third_party/WebKit/LayoutTests/compositing/culling/unscrolled-within-boxshadow-expected.png
new file mode 100644
index 0000000..17c85ce
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/culling/unscrolled-within-boxshadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.png b/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.png
new file mode 100644
index 0000000..9f1cee2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-in-fixed-overflow-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-in-fixed-overflow-expected.txt
index b0058b6..7117f5be 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-in-fixed-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-in-fixed-overflow-expected.txt
@@ -9,14 +9,15 @@
         {
           "position": [8, 13],
           "bounds": [800, 600],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [785, 600],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [785, 1000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "children": [
                     {
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
index b41aaec..89faca6 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
@@ -11,15 +11,16 @@
         {
           "position": [8, 68],
           "bounds": [302, 302],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [1, 1],
               "bounds": [285, 285],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 800],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
index 39c25efe..ad67ede 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/clear-scroll-parent-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/clear-scroll-parent-expected.txt
index 21ff09a..82736418 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/clear-scroll-parent-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/clear-scroll-parent-expected.txt
@@ -9,15 +9,16 @@
         {
           "position": [8, 8],
           "bounds": [308, 208],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [4, 4],
               "bounds": [285, 200],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 530],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/composited-scrolling-paint-phases-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/composited-scrolling-paint-phases-expected.txt
index 6d86be9..4013b92d 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/composited-scrolling-paint-phases-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/composited-scrolling-paint-phases-expected.txt
@@ -45,6 +45,7 @@
             {
               "position": [28, 20],
               "bounds": [202, 202],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "paintingPhases": [
                 "GraphicsLayerPaintBackground",
@@ -55,6 +56,7 @@
                 {
                   "position": [1, 1],
                   "bounds": [185, 185],
+                  "shouldFlattenTransform": false,
                   "paintingPhases": [
                     "GraphicsLayerPaintBackground",
                     "GraphicsLayerPaintForeground",
@@ -63,7 +65,6 @@
                   "children": [
                     {
                       "bounds": [185, 715],
-                      "shouldFlattenTransform": false,
                       "drawsContent": true,
                       "paintingPhases": [
                         "GraphicsLayerPaintForeground",
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/content-gains-scrollbars-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/content-gains-scrollbars-expected.txt
index d243ed8b..10f2551 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/content-gains-scrollbars-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/content-gains-scrollbars-expected.txt
@@ -9,14 +9,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [85, 100],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [85, 200],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [10, 200]
@@ -39,14 +40,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [100, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 85],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [200, 10]
@@ -69,14 +71,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 200],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [200, 200]
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scrollbar-layers-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scrollbar-layers-expected.txt
index d243ed8b..10f2551 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scrollbar-layers-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scrollbar-layers-expected.txt
@@ -9,14 +9,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [85, 100],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [85, 200],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [10, 200]
@@ -39,14 +40,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [100, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 85],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [200, 10]
@@ -69,14 +71,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 200],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [200, 200]
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
index b11e3e4..5244c6e 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
@@ -24,14 +24,15 @@
                       "children": [
                         {
                           "bounds": [1200, 1000],
+                          "shouldFlattenTransform": false,
                           "drawsContent": true,
                           "children": [
                             {
                               "bounds": [1200, 1000],
+                              "shouldFlattenTransform": false,
                               "children": [
                                 {
                                   "bounds": [1200, 10000],
-                                  "shouldFlattenTransform": false,
                                   "drawsContent": true
                                 }
                               ]
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-absolute-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-absolute-expected.txt
index a861f58..631b21d 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-absolute-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-absolute-expected.txt
@@ -13,15 +13,16 @@
               "position": [8, 8],
               "bounds": [500, 500],
               "contentsOpaque": true,
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "backgroundColor": "#0000FF",
               "children": [
                 {
                   "bounds": [485, 485],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [485, 5000],
-                      "shouldFlattenTransform": false,
                       "drawsContent": true
                     }
                   ]
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
index eca105b..de97ec2 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
@@ -16,15 +16,16 @@
           "children": [
             {
               "bounds": [102, 102],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [1, 1],
                   "bounds": [100, 100],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
-                      "bounds": [100, 180],
-                      "shouldFlattenTransform": false
+                      "bounds": [100, 180]
                     }
                   ]
                 }
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
index a74270d..e456a58 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
@@ -8,14 +8,15 @@
       "children": [
         {
           "bounds": [320, 340],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [305, 325],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [305, 1224],
-                  "shouldFlattenTransform": false
+                  "bounds": [305, 1224]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/scrolling-without-painting-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/scrolling-without-painting-expected.txt
index 466febf8..11f017e2 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/scrolling-without-painting-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/scrolling-without-painting-expected.txt
@@ -9,15 +9,16 @@
         {
           "position": [8, 8],
           "bounds": [202, 202],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [1, 1],
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 1025],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
index 4b59382..6ca1829 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
@@ -12,15 +12,16 @@
             {
               "position": [10, 10],
               "bounds": [104, 104],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [2, 2],
                   "bounds": [85, 85],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [85, 144],
-                      "shouldFlattenTransform": false,
                       "drawsContent": true
                     }
                   ]
@@ -72,15 +73,16 @@
         {
           "position": [130, 10],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [105, 144],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -128,15 +130,16 @@
             {
               "position": [250, 10],
               "bounds": [104, 104],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [2, 2],
                   "bounds": [85, 85],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
-                      "bounds": [85, 144],
-                      "shouldFlattenTransform": false
+                      "bounds": [85, 144]
                     }
                   ]
                 },
@@ -190,15 +193,16 @@
             {
               "position": [370, 10],
               "bounds": [104, 104],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [2, 2],
                   "bounds": [85, 85],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [85, 144],
-                      "shouldFlattenTransform": false,
                       "drawsContent": true
                     }
                   ]
@@ -250,15 +254,16 @@
         {
           "position": [10, 130],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [105, 144],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -306,15 +311,16 @@
             {
               "position": [130, 130],
               "bounds": [104, 104],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [2, 2],
                   "bounds": [85, 85],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
-                      "bounds": [85, 144],
-                      "shouldFlattenTransform": false
+                      "bounds": [85, 144]
                     }
                   ]
                 },
@@ -365,15 +371,16 @@
         {
           "position": [250, 130],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [105, 144],
-                  "shouldFlattenTransform": false
+                  "bounds": [105, 144]
                 }
               ]
             },
@@ -417,15 +424,16 @@
         {
           "position": [370, 130],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [105, 144],
-                  "shouldFlattenTransform": false
+                  "bounds": [105, 144]
                 }
               ]
             },
@@ -469,15 +477,16 @@
         {
           "position": [10, 250],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [85, 144],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -529,15 +538,16 @@
         {
           "position": [130, 250],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [85, 144],
-                  "shouldFlattenTransform": false
+                  "bounds": [85, 144]
                 }
               ]
             },
@@ -588,15 +598,16 @@
         {
           "position": [250, 250],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [85, 144],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -648,15 +659,16 @@
         {
           "position": [370, 250],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [85, 144],
-                  "shouldFlattenTransform": false
+                  "bounds": [85, 144]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/updating-scrolling-content-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/updating-scrolling-content-expected.txt
index 59fbd8e..ecb91aa 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/updating-scrolling-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/updating-scrolling-content-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 0, 185, 200]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 1200],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 0, 185, 200]
diff --git a/third_party/WebKit/LayoutTests/compositing/scrollbars/nested-overlay-scrollbars-expected.txt b/third_party/WebKit/LayoutTests/compositing/scrollbars/nested-overlay-scrollbars-expected.txt
index c7027fd..fb3a8a1c 100644
--- a/third_party/WebKit/LayoutTests/compositing/scrollbars/nested-overlay-scrollbars-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/scrollbars/nested-overlay-scrollbars-expected.txt
@@ -9,29 +9,31 @@
         {
           "position": [8, 8],
           "bounds": [404, 404],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [400, 400],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [400, 704],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "children": [
                     {
                       "position": [0, 500],
                       "bounds": [204, 204],
+                      "shouldFlattenTransform": false,
                       "drawsContent": true,
                       "children": [
                         {
                           "position": [2, 2],
                           "bounds": [200, 200],
+                          "shouldFlattenTransform": false,
                           "children": [
                             {
                               "bounds": [5000, 9000],
-                              "shouldFlattenTransform": false,
                               "drawsContent": true
                             }
                           ]
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/composited-bounds-for-negative-z-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/composited-bounds-for-negative-z-expected.txt
index 9db0a91..06ec77e6 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/composited-bounds-for-negative-z-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/composited-bounds-for-negative-z-expected.txt
@@ -23,14 +23,15 @@
             {
               "position": [108, 100],
               "bounds": [300, 300],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "bounds": [285, 300],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
-                      "bounds": [285, 1000],
-                      "shouldFlattenTransform": false
+                      "bounds": [285, 1000]
                     }
                   ]
                 },
diff --git a/third_party/WebKit/LayoutTests/compositing/update-paint-phases-expected.txt b/third_party/WebKit/LayoutTests/compositing/update-paint-phases-expected.txt
index fe482d2c..66ab0ee 100644
--- a/third_party/WebKit/LayoutTests/compositing/update-paint-phases-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/update-paint-phases-expected.txt
@@ -19,6 +19,7 @@
         {
           "position": [8, 8],
           "bounds": [102, 102],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "paintingPhases": [
             "GraphicsLayerPaintBackground",
@@ -29,6 +30,7 @@
             {
               "position": [1, 1],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "paintingPhases": [
                 "GraphicsLayerPaintBackground",
                 "GraphicsLayerPaintForeground",
@@ -37,7 +39,6 @@
               "children": [
                 {
                   "bounds": [85, 120],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "paintingPhases": [
                     "GraphicsLayerPaintForeground",
diff --git a/third_party/WebKit/LayoutTests/css3/escape-dom-api-expected.txt b/third_party/WebKit/LayoutTests/css3/escape-dom-api-expected.txt
index 39bb8de..943a2ee 100644
--- a/third_party/WebKit/LayoutTests/css3/escape-dom-api-expected.txt
+++ b/third_party/WebKit/LayoutTests/css3/escape-dom-api-expected.txt
@@ -3,10 +3,14 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS CSS.escape('\0') threw exception InvalidCharacterError: Failed to execute 'escape' on 'CSS': The string contains an invalid character..
-PASS CSS.escape('a\0') threw exception InvalidCharacterError: Failed to execute 'escape' on 'CSS': The string contains an invalid character..
-PASS CSS.escape('\0b') threw exception InvalidCharacterError: Failed to execute 'escape' on 'CSS': The string contains an invalid character..
-PASS CSS.escape('a\0b') threw exception InvalidCharacterError: Failed to execute 'escape' on 'CSS': The string contains an invalid character..
+PASS CSS.escape('\0') is "�"
+PASS CSS.escape('a\0') is "a�"
+PASS CSS.escape('\0b') is "�b"
+PASS CSS.escape('a\0b') is "a�b"
+PASS CSS.escape('�') is "�"
+PASS CSS.escape('a�') is "a�"
+PASS CSS.escape('�b') is "�b"
+PASS CSS.escape('a�b') is "a�b"
 PASS CSS.escape() threw exception TypeError: Failed to execute 'escape' on 'CSS': 1 argument required, but only 0 present..
 PASS CSS.escape(true) is "true"
 PASS CSS.escape(false) is "false"
diff --git a/third_party/WebKit/LayoutTests/css3/escape-dom-api.html b/third_party/WebKit/LayoutTests/css3/escape-dom-api.html
index b1d31fb..a0d249a6 100644
--- a/third_party/WebKit/LayoutTests/css3/escape-dom-api.html
+++ b/third_party/WebKit/LayoutTests/css3/escape-dom-api.html
@@ -8,10 +8,15 @@
     // Test from https://github.com/mathiasbynens/CSS.escape
     description("Test window.CSS.escape()");
 
-    shouldThrow("CSS.escape('\0')");
-    shouldThrow("CSS.escape('a\0')");
-    shouldThrow("CSS.escape('\0b')");
-    shouldThrow("CSS.escape('a\0b')");
+    shouldBeEqualToString("CSS.escape('\0')", "\ufffd");
+    shouldBeEqualToString("CSS.escape('a\0')", "a\ufffd");
+    shouldBeEqualToString("CSS.escape('\0b')", "\ufffdb");
+    shouldBeEqualToString("CSS.escape('a\0b')", "a\ufffdb");
+
+    shouldBeEqualToString("CSS.escape('\ufffd')", "\ufffd");
+    shouldBeEqualToString("CSS.escape('a\ufffd')", "a\ufffd");
+    shouldBeEqualToString("CSS.escape('\ufffdb')", "\ufffdb");
+    shouldBeEqualToString("CSS.escape('a\ufffdb')", "a\ufffdb");
 
     shouldThrow("CSS.escape()");
     shouldBeEqualToString("CSS.escape(true)", "true");
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-0-expected.txt b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-0-expected.txt
new file mode 100644
index 0000000..3065048
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-0-expected.txt
@@ -0,0 +1,140 @@
+According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+Testing font set variations 0 to 2 out of 0-26
+Available fonts updated: ["condensed_normal_100","condensed_normal_900","condensed_italic_100","condensed_italic_900","expanded_normal_100","expanded_normal_900","expanded_italic_100","expanded_italic_900"]
+
+#condensed_normal_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#condensed_normal_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#condensed_italic_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#condensed_italic_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#expanded_normal_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#expanded_normal_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#expanded_italic_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#expanded_italic_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+Available fonts updated: ["condensed_normal_100","condensed_italic_100","expanded_normal_100","expanded_italic_100"]
+
+#condensed_normal_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#condensed_normal_900
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#condensed_italic_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#condensed_italic_900
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#expanded_normal_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#expanded_normal_900
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#expanded_italic_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#expanded_italic_900
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+Available fonts updated: ["condensed_normal_900","condensed_italic_900","expanded_normal_900","expanded_italic_900"]
+
+#condensed_normal_100
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#condensed_normal_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#condensed_italic_100
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#condensed_italic_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#expanded_normal_100
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#expanded_normal_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#expanded_italic_100
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#expanded_italic_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-0.html b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-0.html
new file mode 100644
index 0000000..999f075
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-0.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<meta charset="UTF-8">
+<head>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/inspector-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/css-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/dom-protocol-test.js"></script>
+    <script type="text/javascript" src="resources/style-matching-test.js"></script>
+    <!-- available fonts --->
+    <style type="text/css">
+    </style>
+    <link rel="stylesheet" type="text/css" href="resources/applied-styles.css">
+</head>
+<body>
+<pre>According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+</pre>
+    <div class="test">
+        <div id="condensed_normal_100">abcdefg</div>
+        <div id="condensed_normal_900">abcdefg</div>
+        <div id="condensed_italic_100">abcdefg</div>
+        <div id="condensed_italic_900">abcdefg</div>
+        <div id="expanded_normal_100">abcdefg</div>
+        <div id="expanded_normal_900">abcdefg</div>
+        <div id="expanded_italic_100">abcdefg</div>
+        <div id="expanded_italic_900">abcdefg</div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-1-expected.txt b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-1-expected.txt
new file mode 100644
index 0000000..5a19d19
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-1-expected.txt
@@ -0,0 +1,140 @@
+According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+Testing font set variations 3 to 5 out of 0-26
+Available fonts updated: ["condensed_normal_100","condensed_normal_900","expanded_normal_100","expanded_normal_900"]
+
+#condensed_normal_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#condensed_normal_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#condensed_italic_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#condensed_italic_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#expanded_normal_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#expanded_normal_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#expanded_italic_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#expanded_italic_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+Available fonts updated: ["condensed_normal_100","expanded_normal_100"]
+
+#condensed_normal_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#condensed_normal_900
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#condensed_italic_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#condensed_italic_900
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#expanded_normal_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#expanded_normal_900
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#expanded_italic_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#expanded_italic_900
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+Available fonts updated: ["condensed_normal_900","expanded_normal_900"]
+
+#condensed_normal_100
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#condensed_normal_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#condensed_italic_100
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#condensed_italic_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#expanded_normal_100
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#expanded_normal_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#expanded_italic_100
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#expanded_italic_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-1.html b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-1.html
new file mode 100644
index 0000000..999f075
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-1.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<meta charset="UTF-8">
+<head>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/inspector-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/css-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/dom-protocol-test.js"></script>
+    <script type="text/javascript" src="resources/style-matching-test.js"></script>
+    <!-- available fonts --->
+    <style type="text/css">
+    </style>
+    <link rel="stylesheet" type="text/css" href="resources/applied-styles.css">
+</head>
+<body>
+<pre>According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+</pre>
+    <div class="test">
+        <div id="condensed_normal_100">abcdefg</div>
+        <div id="condensed_normal_900">abcdefg</div>
+        <div id="condensed_italic_100">abcdefg</div>
+        <div id="condensed_italic_900">abcdefg</div>
+        <div id="expanded_normal_100">abcdefg</div>
+        <div id="expanded_normal_900">abcdefg</div>
+        <div id="expanded_italic_100">abcdefg</div>
+        <div id="expanded_italic_900">abcdefg</div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-2-expected.txt b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-2-expected.txt
new file mode 100644
index 0000000..e498bf4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-2-expected.txt
@@ -0,0 +1,140 @@
+According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+Testing font set variations 6 to 8 out of 0-26
+Available fonts updated: ["condensed_italic_100","condensed_italic_900","expanded_italic_100","expanded_italic_900"]
+
+#condensed_normal_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#condensed_normal_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#condensed_italic_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#condensed_italic_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#expanded_normal_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#expanded_normal_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#expanded_italic_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#expanded_italic_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+Available fonts updated: ["condensed_italic_100","expanded_italic_100"]
+
+#condensed_normal_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#condensed_normal_900
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#condensed_italic_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#condensed_italic_900
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#expanded_normal_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#expanded_normal_900
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#expanded_italic_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#expanded_italic_900
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+Available fonts updated: ["condensed_italic_900","expanded_italic_900"]
+
+#condensed_normal_100
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#condensed_normal_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#condensed_italic_100
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#condensed_italic_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#expanded_normal_100
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#expanded_normal_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#expanded_italic_100
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#expanded_italic_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-2.html b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-2.html
new file mode 100644
index 0000000..999f075
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-2.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<meta charset="UTF-8">
+<head>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/inspector-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/css-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/dom-protocol-test.js"></script>
+    <script type="text/javascript" src="resources/style-matching-test.js"></script>
+    <!-- available fonts --->
+    <style type="text/css">
+    </style>
+    <link rel="stylesheet" type="text/css" href="resources/applied-styles.css">
+</head>
+<body>
+<pre>According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+</pre>
+    <div class="test">
+        <div id="condensed_normal_100">abcdefg</div>
+        <div id="condensed_normal_900">abcdefg</div>
+        <div id="condensed_italic_100">abcdefg</div>
+        <div id="condensed_italic_900">abcdefg</div>
+        <div id="expanded_normal_100">abcdefg</div>
+        <div id="expanded_normal_900">abcdefg</div>
+        <div id="expanded_italic_100">abcdefg</div>
+        <div id="expanded_italic_900">abcdefg</div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-3-expected.txt b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-3-expected.txt
new file mode 100644
index 0000000..e038b6e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-3-expected.txt
@@ -0,0 +1,140 @@
+According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+Testing font set variations 9 to 11 out of 0-26
+Available fonts updated: ["condensed_normal_100","condensed_normal_900","condensed_italic_100","condensed_italic_900"]
+
+#condensed_normal_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#condensed_normal_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#condensed_italic_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#condensed_italic_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#expanded_normal_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#expanded_normal_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#expanded_italic_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#expanded_italic_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+Available fonts updated: ["condensed_normal_100","condensed_italic_100"]
+
+#condensed_normal_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#condensed_normal_900
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#condensed_italic_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#condensed_italic_900
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#expanded_normal_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#expanded_normal_900
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#expanded_italic_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#expanded_italic_900
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+Available fonts updated: ["condensed_normal_900","condensed_italic_900"]
+
+#condensed_normal_100
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#condensed_normal_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#condensed_italic_100
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#condensed_italic_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#expanded_normal_100
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#expanded_normal_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#expanded_italic_100
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#expanded_italic_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-3.html b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-3.html
new file mode 100644
index 0000000..999f075
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-3.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<meta charset="UTF-8">
+<head>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/inspector-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/css-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/dom-protocol-test.js"></script>
+    <script type="text/javascript" src="resources/style-matching-test.js"></script>
+    <!-- available fonts --->
+    <style type="text/css">
+    </style>
+    <link rel="stylesheet" type="text/css" href="resources/applied-styles.css">
+</head>
+<body>
+<pre>According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+</pre>
+    <div class="test">
+        <div id="condensed_normal_100">abcdefg</div>
+        <div id="condensed_normal_900">abcdefg</div>
+        <div id="condensed_italic_100">abcdefg</div>
+        <div id="condensed_italic_900">abcdefg</div>
+        <div id="expanded_normal_100">abcdefg</div>
+        <div id="expanded_normal_900">abcdefg</div>
+        <div id="expanded_italic_100">abcdefg</div>
+        <div id="expanded_italic_900">abcdefg</div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-4-expected.txt b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-4-expected.txt
new file mode 100644
index 0000000..08fc219
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-4-expected.txt
@@ -0,0 +1,140 @@
+According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+Testing font set variations 12 to 14 out of 0-26
+Available fonts updated: ["condensed_normal_100","condensed_normal_900"]
+
+#condensed_normal_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#condensed_normal_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#condensed_italic_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#condensed_italic_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#expanded_normal_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#expanded_normal_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#expanded_italic_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#expanded_italic_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+Available fonts updated: ["condensed_normal_100"]
+
+#condensed_normal_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#condensed_normal_900
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#condensed_italic_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#condensed_italic_900
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#expanded_normal_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#expanded_normal_900
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#expanded_italic_100
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+#expanded_italic_900
+Expected: condensed normal 100
+Actual: condensed normal 100
+PASS
+
+Available fonts updated: ["condensed_normal_900"]
+
+#condensed_normal_100
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#condensed_normal_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#condensed_italic_100
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#condensed_italic_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#expanded_normal_100
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#expanded_normal_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#expanded_italic_100
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+#expanded_italic_900
+Expected: condensed normal 900
+Actual: condensed normal 900
+PASS
+
+
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-4.html b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-4.html
new file mode 100644
index 0000000..999f075
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-4.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<meta charset="UTF-8">
+<head>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/inspector-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/css-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/dom-protocol-test.js"></script>
+    <script type="text/javascript" src="resources/style-matching-test.js"></script>
+    <!-- available fonts --->
+    <style type="text/css">
+    </style>
+    <link rel="stylesheet" type="text/css" href="resources/applied-styles.css">
+</head>
+<body>
+<pre>According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+</pre>
+    <div class="test">
+        <div id="condensed_normal_100">abcdefg</div>
+        <div id="condensed_normal_900">abcdefg</div>
+        <div id="condensed_italic_100">abcdefg</div>
+        <div id="condensed_italic_900">abcdefg</div>
+        <div id="expanded_normal_100">abcdefg</div>
+        <div id="expanded_normal_900">abcdefg</div>
+        <div id="expanded_italic_100">abcdefg</div>
+        <div id="expanded_italic_900">abcdefg</div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-5-expected.txt b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-5-expected.txt
new file mode 100644
index 0000000..640038f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-5-expected.txt
@@ -0,0 +1,140 @@
+According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+Testing font set variations 15 to 17 out of 0-26
+Available fonts updated: ["condensed_italic_100","condensed_italic_900"]
+
+#condensed_normal_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#condensed_normal_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#condensed_italic_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#condensed_italic_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#expanded_normal_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#expanded_normal_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#expanded_italic_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#expanded_italic_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+Available fonts updated: ["condensed_italic_100"]
+
+#condensed_normal_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#condensed_normal_900
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#condensed_italic_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#condensed_italic_900
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#expanded_normal_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#expanded_normal_900
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#expanded_italic_100
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+#expanded_italic_900
+Expected: condensed italic 100
+Actual: condensed italic 100
+PASS
+
+Available fonts updated: ["condensed_italic_900"]
+
+#condensed_normal_100
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#condensed_normal_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#condensed_italic_100
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#condensed_italic_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#expanded_normal_100
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#expanded_normal_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#expanded_italic_100
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+#expanded_italic_900
+Expected: condensed italic 900
+Actual: condensed italic 900
+PASS
+
+
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-5.html b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-5.html
new file mode 100644
index 0000000..999f075
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-5.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<meta charset="UTF-8">
+<head>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/inspector-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/css-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/dom-protocol-test.js"></script>
+    <script type="text/javascript" src="resources/style-matching-test.js"></script>
+    <!-- available fonts --->
+    <style type="text/css">
+    </style>
+    <link rel="stylesheet" type="text/css" href="resources/applied-styles.css">
+</head>
+<body>
+<pre>According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+</pre>
+    <div class="test">
+        <div id="condensed_normal_100">abcdefg</div>
+        <div id="condensed_normal_900">abcdefg</div>
+        <div id="condensed_italic_100">abcdefg</div>
+        <div id="condensed_italic_900">abcdefg</div>
+        <div id="expanded_normal_100">abcdefg</div>
+        <div id="expanded_normal_900">abcdefg</div>
+        <div id="expanded_italic_100">abcdefg</div>
+        <div id="expanded_italic_900">abcdefg</div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-6-expected.txt b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-6-expected.txt
new file mode 100644
index 0000000..9ab6f1c3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-6-expected.txt
@@ -0,0 +1,140 @@
+According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+Testing font set variations 18 to 20 out of 0-26
+Available fonts updated: ["expanded_normal_100","expanded_normal_900","expanded_italic_100","expanded_italic_900"]
+
+#condensed_normal_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#condensed_normal_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#condensed_italic_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#condensed_italic_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#expanded_normal_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#expanded_normal_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#expanded_italic_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#expanded_italic_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+Available fonts updated: ["expanded_normal_100","expanded_italic_100"]
+
+#condensed_normal_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#condensed_normal_900
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#condensed_italic_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#condensed_italic_900
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#expanded_normal_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#expanded_normal_900
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#expanded_italic_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#expanded_italic_900
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+Available fonts updated: ["expanded_normal_900","expanded_italic_900"]
+
+#condensed_normal_100
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#condensed_normal_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#condensed_italic_100
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#condensed_italic_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#expanded_normal_100
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#expanded_normal_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#expanded_italic_100
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#expanded_italic_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-6.html b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-6.html
new file mode 100644
index 0000000..999f075
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-6.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<meta charset="UTF-8">
+<head>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/inspector-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/css-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/dom-protocol-test.js"></script>
+    <script type="text/javascript" src="resources/style-matching-test.js"></script>
+    <!-- available fonts --->
+    <style type="text/css">
+    </style>
+    <link rel="stylesheet" type="text/css" href="resources/applied-styles.css">
+</head>
+<body>
+<pre>According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+</pre>
+    <div class="test">
+        <div id="condensed_normal_100">abcdefg</div>
+        <div id="condensed_normal_900">abcdefg</div>
+        <div id="condensed_italic_100">abcdefg</div>
+        <div id="condensed_italic_900">abcdefg</div>
+        <div id="expanded_normal_100">abcdefg</div>
+        <div id="expanded_normal_900">abcdefg</div>
+        <div id="expanded_italic_100">abcdefg</div>
+        <div id="expanded_italic_900">abcdefg</div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-7-expected.txt b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-7-expected.txt
new file mode 100644
index 0000000..7fc39a1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-7-expected.txt
@@ -0,0 +1,140 @@
+According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+Testing font set variations 21 to 23 out of 0-26
+Available fonts updated: ["expanded_normal_100","expanded_normal_900"]
+
+#condensed_normal_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#condensed_normal_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#condensed_italic_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#condensed_italic_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#expanded_normal_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#expanded_normal_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#expanded_italic_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#expanded_italic_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+Available fonts updated: ["expanded_normal_100"]
+
+#condensed_normal_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#condensed_normal_900
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#condensed_italic_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#condensed_italic_900
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#expanded_normal_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#expanded_normal_900
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#expanded_italic_100
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+#expanded_italic_900
+Expected: expanded normal 100
+Actual: expanded normal 100
+PASS
+
+Available fonts updated: ["expanded_normal_900"]
+
+#condensed_normal_100
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#condensed_normal_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#condensed_italic_100
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#condensed_italic_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#expanded_normal_100
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#expanded_normal_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#expanded_italic_100
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+#expanded_italic_900
+Expected: expanded normal 900
+Actual: expanded normal 900
+PASS
+
+
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-7.html b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-7.html
new file mode 100644
index 0000000..999f075
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-7.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<meta charset="UTF-8">
+<head>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/inspector-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/css-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/dom-protocol-test.js"></script>
+    <script type="text/javascript" src="resources/style-matching-test.js"></script>
+    <!-- available fonts --->
+    <style type="text/css">
+    </style>
+    <link rel="stylesheet" type="text/css" href="resources/applied-styles.css">
+</head>
+<body>
+<pre>According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+</pre>
+    <div class="test">
+        <div id="condensed_normal_100">abcdefg</div>
+        <div id="condensed_normal_900">abcdefg</div>
+        <div id="condensed_italic_100">abcdefg</div>
+        <div id="condensed_italic_900">abcdefg</div>
+        <div id="expanded_normal_100">abcdefg</div>
+        <div id="expanded_normal_900">abcdefg</div>
+        <div id="expanded_italic_100">abcdefg</div>
+        <div id="expanded_italic_900">abcdefg</div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-8-expected.txt b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-8-expected.txt
new file mode 100644
index 0000000..d4658cc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-8-expected.txt
@@ -0,0 +1,140 @@
+According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+abcdefg
+Testing font set variations 24 to 26 out of 0-26
+Available fonts updated: ["expanded_italic_100","expanded_italic_900"]
+
+#condensed_normal_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#condensed_normal_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#condensed_italic_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#condensed_italic_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#expanded_normal_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#expanded_normal_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#expanded_italic_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#expanded_italic_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+Available fonts updated: ["expanded_italic_100"]
+
+#condensed_normal_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#condensed_normal_900
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#condensed_italic_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#condensed_italic_900
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#expanded_normal_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#expanded_normal_900
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#expanded_italic_100
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+#expanded_italic_900
+Expected: expanded italic 100
+Actual: expanded italic 100
+PASS
+
+Available fonts updated: ["expanded_italic_900"]
+
+#condensed_normal_100
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#condensed_normal_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#condensed_italic_100
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#condensed_italic_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#expanded_normal_100
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#expanded_normal_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#expanded_italic_100
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+#expanded_italic_900
+Expected: expanded italic 900
+Actual: expanded italic 900
+PASS
+
+
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-8.html b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-8.html
new file mode 100644
index 0000000..999f075
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching-8.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<meta charset="UTF-8">
+<head>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/inspector-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/css-protocol-test.js"></script>
+    <script type="text/javascript" src="../../http/tests/inspector-protocol/dom-protocol-test.js"></script>
+    <script type="text/javascript" src="resources/style-matching-test.js"></script>
+    <!-- available fonts --->
+    <style type="text/css">
+    </style>
+    <link rel="stylesheet" type="text/css" href="resources/applied-styles.css">
+</head>
+<body>
+<pre>According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
+( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
+available font faces by finding the nearest match in the following order of
+precedence: stretch, style, weight.
+</pre>
+    <div class="test">
+        <div id="condensed_normal_100">abcdefg</div>
+        <div id="condensed_normal_900">abcdefg</div>
+        <div id="condensed_italic_100">abcdefg</div>
+        <div id="condensed_italic_900">abcdefg</div>
+        <div id="expanded_normal_100">abcdefg</div>
+        <div id="expanded_normal_900">abcdefg</div>
+        <div id="expanded_italic_100">abcdefg</div>
+        <div id="expanded_italic_900">abcdefg</div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching.html b/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching.html
deleted file mode 100644
index bd99ae8..0000000
--- a/third_party/WebKit/LayoutTests/css3/fonts/font-style-matching.html
+++ /dev/null
@@ -1,95 +0,0 @@
-<!DOCTYPE html>
-<html>
-<meta charset="UTF-8">
-<head>
-    <script type="text/javascript" src="../../http/tests/inspector-protocol/inspector-protocol-test.js"></script>
-    <script type="text/javascript" src="../../http/tests/inspector-protocol/css-protocol-test.js"></script>
-    <script type="text/javascript" src="../../http/tests/inspector-protocol/dom-protocol-test.js"></script>
-    <script type="text/javascript" src="resources/style-matching-test.js"></script>
-    <!-- available fonts --->
-    <style type="text/css">
-    </style>
-    <!-- Applied styles -->
-    <style type="text/css">
-      body {
-        font-size: 24px;
-        line-height: 110%;
-        text-rendering: optimizeLegibility;
-        font-feature-settings: "liga" 1;
-      }
-
-      #condensed_normal_100 {
-          font-family: CSSMatchingTest;
-          font-stretch: condensed;
-          font-style: normal;
-          font-weight: 100;
-      }
-
-      #condensed_normal_900 {
-          font-family: CSSMatchingTest;
-          font-stretch: condensed;
-          font-style: normal;
-          font-weight: 900;
-      }
-
-      #condensed_italic_100 {
-          font-family: CSSMatchingTest;
-          font-stretch: condensed;
-          font-style: italic;
-          font-weight: 100;
-      }
-
-      #condensed_italic_900 {
-          font-family: CSSMatchingTest;
-          font-stretch: condensed;
-          font-style: italic;
-          font-weight: 900;
-      }
-
-      #expanded_normal_100 {
-          font-family: CSSMatchingTest;
-          font-stretch: expanded;
-          font-style: normal;
-          font-weight: 100;
-      }
-
-      #expanded_normal_900 {
-          font-family: CSSMatchingTest;
-          font-stretch: expanded;
-          font-style: normal;
-          font-weight: 900;
-      }
-
-      #expanded_italic_100 {
-          font-family: CSSMatchingTest;
-          font-stretch: expanded;
-          font-style: italic;
-          font-weight: 100;
-      }
-
-      #expanded_italic_900 {
-          font-family: CSSMatchingTest;
-          font-stretch: expanded;
-          font-style: italic;
-          font-weight: 900;
-      }
-    </style>
-</head>
-<body>
-<pre>According to the CSS3 Fonts Module, Step 4 or the Font Style Matching Algorithm
-( https://drafts.csswg.org/css-fonts-3/#font-style-matching ) must narrow down the
-available font faces by finding the nearest match in the following order of
-precedence: stretch, style, weight.
-</pre>
-    <div class="test">
-        <div id="condensed_normal_100">abcdefg</div>
-        <div id="condensed_normal_900">abcdefg</div>
-        <div id="condensed_italic_100">abcdefg</div>
-        <div id="condensed_italic_900">abcdefg</div>
-        <div id="expanded_normal_100">abcdefg</div>
-        <div id="expanded_normal_900">abcdefg</div>
-        <div id="expanded_italic_100">abcdefg</div>
-        <div id="expanded_italic_900">abcdefg</div>
-    </div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/resources/applied-styles.css b/third_party/WebKit/LayoutTests/css3/fonts/resources/applied-styles.css
new file mode 100644
index 0000000..ad83704
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/fonts/resources/applied-styles.css
@@ -0,0 +1,62 @@
+body {
+    font-size: 24px;
+    line-height: 110%;
+    text-rendering: optimizeLegibility;
+    font-feature-settings: "liga" 1;
+}
+
+#condensed_normal_100 {
+    font-family: CSSMatchingTest;
+    font-stretch: condensed;
+    font-style: normal;
+    font-weight: 100;
+}
+
+#condensed_normal_900 {
+    font-family: CSSMatchingTest;
+    font-stretch: condensed;
+    font-style: normal;
+    font-weight: 900;
+}
+
+#condensed_italic_100 {
+    font-family: CSSMatchingTest;
+    font-stretch: condensed;
+    font-style: italic;
+    font-weight: 100;
+}
+
+#condensed_italic_900 {
+    font-family: CSSMatchingTest;
+    font-stretch: condensed;
+    font-style: italic;
+    font-weight: 900;
+}
+
+#expanded_normal_100 {
+    font-family: CSSMatchingTest;
+    font-stretch: expanded;
+    font-style: normal;
+    font-weight: 100;
+}
+
+#expanded_normal_900 {
+    font-family: CSSMatchingTest;
+    font-stretch: expanded;
+    font-style: normal;
+    font-weight: 900;
+}
+
+#expanded_italic_100 {
+    font-family: CSSMatchingTest;
+    font-stretch: expanded;
+    font-style: italic;
+    font-weight: 100;
+}
+
+#expanded_italic_900 {
+    font-family: CSSMatchingTest;
+    font-stretch: expanded;
+    font-style: italic;
+    font-weight: 900;
+}
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/resources/style-matching-test.js b/third_party/WebKit/LayoutTests/css3/fonts/resources/style-matching-test.js
index 62fb9f2..c5f964ba 100644
--- a/third_party/WebKit/LayoutTests/css3/fonts/resources/style-matching-test.js
+++ b/third_party/WebKit/LayoutTests/css3/fonts/resources/style-matching-test.js
@@ -44,7 +44,14 @@
                     makeFontFaceDeclaration(stretch, style, weight));
             }
 
-    document.fonts.ready.then(window.notifyInspectorFontsReady);
+    document.fonts.ready.then(() => {
+        // fonts.ready event fires too early, used fonts for rendering have not
+        // been updated yet. Force a layout to hopefully work around this.
+        // Remove this when crbug.com/516680 is fixed.
+        // https://drafts.csswg.org/css-font-loading/#font-face-set-ready
+        document.body.offsetTop;
+        window.notifyInspectorFontsReady()
+    });
 }
 
 function test()
@@ -53,6 +60,7 @@
     var documentNodeSelector;
     var allTestSelectors = [];
     var testSelectors = [];
+    var testGroup = 0;
 
     var stretches = [ 'condensed', 'expanded' ];
     var styles = [ 'normal', 'italic' ];
@@ -90,6 +98,17 @@
         }
     }
 
+    function subsetFontSetVariations() {
+        var NUM_GROUPS = 9;
+        var numVariations = fontSetVariations.length;
+        var groupLength = numVariations / NUM_GROUPS;
+        var start = testGroup * groupLength;
+        var end = start + groupLength;
+        InspectorTest.log("Testing font set variations " + start + " to " +
+            (end - 1) + " out of 0-" + (numVariations - 1));
+        fontSetVariations = fontSetVariations.slice(start, end);
+    }
+
     InspectorTest.requestDocumentNodeId(onDocumentNodeId);
 
     function onDocumentNodeId(nodeId)
@@ -97,6 +116,16 @@
         documentNodeId = nodeId;
 
         InspectorTest.evaluateInInspectedPage(
+            'JSON.stringify(document.location.href)',
+            extractTestGroup);
+    }
+
+    function extractTestGroup(result)
+    {
+        testGroup = /font-style-matching-(\d).html/.exec(
+            JSON.parse(result.result.result.value))[1];
+        subsetFontSetVariations();
+        InspectorTest.evaluateInInspectedPage(
             'JSON.stringify(' +
                 'Array.prototype.map.call(' +
                 'document.querySelectorAll(".test *"),' +
@@ -142,11 +171,7 @@
     window.onFontsLoaded = function(loadedFonts) {
         InspectorTest.log("Available fonts updated: " +
                           JSON.stringify(loadedFonts) + "\n");
-        // fonts.ready event fires too early, used fonts for rendering
-        // have not been updated yet. Remove this wehn crbug.com/516680
-        // is fixed.
-        // https://drafts.csswg.org/css-font-loading/#font-face-set-ready
-        setTimeout(nextTest, 100);
+        nextTest();
     }
 
     function testNextPageElement(result)
diff --git a/third_party/WebKit/LayoutTests/editing/selection/selectallchildren-crash.html b/third_party/WebKit/LayoutTests/editing/selection/selectallchildren-crash.html
new file mode 100644
index 0000000..a06510a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/selection/selectallchildren-crash.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<body>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+var test = async_test('Do not crash in Selection.selectAllChildren().');
+var doc2;
+var selection;
+
+test.step(function() {
+    var iframe1 = document.createElement('iframe');
+    iframe1.srcdoc = '<input autofocus>';
+    window.addEventListener('focus', function() { document.write(); });
+    document.documentElement.appendChild(iframe1);
+    document.designMode = 'on';
+
+    var iframe2 = document.createElement('iframe');
+    iframe2.srcdoc = '<iframe></iframe>';
+    iframe2.addEventListener('load', onLoadIframe2);
+    document.documentElement.appendChild(iframe2);
+});
+
+function onLoadIframe2(e) {
+    var w = e.target.contentWindow;
+    doc2 = w.document;
+    selection = w.getSelection();
+    window.top.setTimeout(selectLater);
+}
+
+function selectLater() {
+    selection.selectAllChildren(doc2);
+
+    // TODO(tkent): A workdaround of a testharnessreport.js issue.  Without this,
+    // testharnessreport.js has a null access.
+    if (!document.documentElement)
+        document.appendChild(document.createElement('html'));
+    test.done();
+}
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/resources/star_sprites.png b/third_party/WebKit/LayoutTests/fast/backgrounds/resources/star_sprites.png
new file mode 100644
index 0000000..747171ae
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/resources/star_sprites.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize08-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize08-expected.png
index 8452938..fbef12c 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize08-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize08-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize10-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize10-expected.png
index 9c59d19..f815211 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize10-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize10-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize11-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize11-expected.png
index c8bff2a..246e1e7 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize11-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize11-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize12-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize12-expected.png
index f7d1b8f..9e543a02 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize12-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize12-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize18-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize18-expected.png
index 956ba90..7d4d9751 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize18-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize18-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize19-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize19-expected.png
index 8e85dca..1f8dace1f 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize19-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize19-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize21-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize21-expected.png
index 956ba90..7d4d9751 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize21-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize21-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize22-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize22-expected.png
index 8a425811..49fe0fe 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize22-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize22-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-expected.png
index 8754e9a..c930981 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-zoomed-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-zoomed-expected.png
index db5b2ae..74a2b7106 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-zoomed-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-zoomed-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/scaled-sprited-background-expected.html b/third_party/WebKit/LayoutTests/fast/backgrounds/size/scaled-sprited-background-expected.html
new file mode 100644
index 0000000..978768f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/scaled-sprited-background-expected.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<style>
+div {
+    width: 108px;
+    height: 20px;
+    background: url(../resources/star_sprites.png) no-repeat 0 bottom;
+    background-size: 108px 172px;
+}
+</style>
+<body>
+<div></div>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/scaled-sprited-background.html b/third_party/WebKit/LayoutTests/fast/backgrounds/size/scaled-sprited-background.html
new file mode 100644
index 0000000..e5b9a0fb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/scaled-sprited-background.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<style>
+div {
+    width: 108px;
+    height: 20px;
+    background: url(../resources/star_sprites.png) no-repeat 0 bottom;
+    background-size: 108px auto;
+}
+</style>
+<body>
+<div></div>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/add-inline-to-block-flow-and-ensure-layout-on-containers-of-removed-floats-expected.html b/third_party/WebKit/LayoutTests/fast/block/float/add-inline-to-block-flow-and-ensure-layout-on-containers-of-removed-floats-expected.html
new file mode 100644
index 0000000..17f80f1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/block/float/add-inline-to-block-flow-and-ensure-layout-on-containers-of-removed-floats-expected.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<style>
+#a {
+    width:50px;
+    height:50px;
+    float: left;
+    background: green;
+}
+</style>
+<p>There should be a green <em>square</em> below.</p>
+<div>
+    <div id="a"></div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/add-inline-to-block-flow-and-ensure-layout-on-containers-of-removed-floats.html b/third_party/WebKit/LayoutTests/fast/block/float/add-inline-to-block-flow-and-ensure-layout-on-containers-of-removed-floats.html
new file mode 100644
index 0000000..50d136b4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/block/float/add-inline-to-block-flow-and-ensure-layout-on-containers-of-removed-floats.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<style>
+#a, #c {
+    width:25px;
+    height:50px;
+    float: left;
+}
+</style>
+<p>There should be a green <em>square</em> below.</p>
+<div>
+    <div id="a" style="background: green;"></div>
+    <div id="b">
+    </div>
+    <div id="c" style="background: red;">
+        <div style="float: left; width: 25px; height: 50px; background: green;"></div>
+    </div>
+</div>
+<script>
+document.body.offsetTop;
+document.getElementById('b').style.display = 'inline-block';
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/clear-intruding-floats-when-moving-to-inline-parent-2-expected.txt b/third_party/WebKit/LayoutTests/fast/block/float/clear-intruding-floats-when-moving-to-inline-parent-2-expected.txt
new file mode 100644
index 0000000..722ed4d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/block/float/clear-intruding-floats-when-moving-to-inline-parent-2-expected.txt
@@ -0,0 +1,5 @@
+PASS crbug.com/562208: Clear intruding floats when moving child to inline parent. Passes if it doesn't crash.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/clear-intruding-floats-when-moving-to-inline-parent-2.html b/third_party/WebKit/LayoutTests/fast/block/float/clear-intruding-floats-when-moving-to-inline-parent-2.html
new file mode 100644
index 0000000..eb4b105
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/block/float/clear-intruding-floats-when-moving-to-inline-parent-2.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<script src="../../../resources/js-test.js"></script>
+<style>
+.float {
+    float: right;
+    width: 100px;
+    height: 100px;
+}
+</style>
+<div>
+    <div></div>
+    <span></span>
+    <div class="float"></div>
+    <div id="block-flow-container">
+        <div></div>
+    </div>
+</div>
+<script>
+    document.body.offsetTop;
+    document.getElementById("block-flow-container").style.position = 'absolute';
+    testPassed("crbug.com/562208: Clear intruding floats when moving child to inline parent. Passes if it doesn't crash.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/clear-intruding-floats-when-moving-to-inline-parent-expected.txt b/third_party/WebKit/LayoutTests/fast/block/float/clear-intruding-floats-when-moving-to-inline-parent-expected.txt
new file mode 100644
index 0000000..722ed4d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/block/float/clear-intruding-floats-when-moving-to-inline-parent-expected.txt
@@ -0,0 +1,5 @@
+PASS crbug.com/562208: Clear intruding floats when moving child to inline parent. Passes if it doesn't crash.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/clear-intruding-floats-when-moving-to-inline-parent.html b/third_party/WebKit/LayoutTests/fast/block/float/clear-intruding-floats-when-moving-to-inline-parent.html
new file mode 100644
index 0000000..dcd6240
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/block/float/clear-intruding-floats-when-moving-to-inline-parent.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<script src="../../../resources/js-test.js"></script>
+<div></div>
+<span></span>
+<div id="killMe" style="float:right; width:100px; height:100px;"></div>
+<div id="container">
+    <canvas id="canvas" style="display:block;"></canvas>
+</div>
+<script>
+    // Trigger layout.
+    document.body.offsetTop;
+
+    // Delete the float.
+    document.getElementById("killMe").style.display = "none";
+
+    // Take it out of normal flow and establish a new block formatting
+    // context, so that the preceding float (which no longer exists, by
+    // the way) can no longer intrude. Not being in normal flow anymore
+    // also means that it can be moved into an adjacent anonymous block if
+    // one exists.
+    document.getElementById("container").style.position = 'absolute';
+
+    // Trigger style recalculation, but NOT layout.
+    getComputedStyle(document.getElementById("container")).color;
+
+    // When zoom changes, LayoutReplaced::styleDidChange() will call
+    // intrinsicSizeChanged(), which will do an out-of-course layout on the canvas element.
+    document.getElementById("canvas").style.zoom = 0.50;
+    testPassed("crbug.com/562208: Clear intruding floats when moving child to inline parent. Passes if it doesn't crash.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-slice-parsing-support.html b/third_party/WebKit/LayoutTests/fast/borders/border-image-slice-parsing-support.html
new file mode 100644
index 0000000..504562d7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/borders/border-image-slice-parsing-support.html
@@ -0,0 +1,11 @@
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+test(() => {
+  assert_true(CSS.supports('border-image-slice', '1.2'), 'accepts non-integer numbers');
+  assert_true(CSS.supports('border-image-slice', '1 2'), 'accepts integers');
+  assert_true(CSS.supports('border-image-slice', '1.2 12'), 'accepts both integers and non-integers');
+  assert_false(CSS.supports('border-image-slice', '1 -2'), 'rejects negative integers');
+  assert_false(CSS.supports('border-image-slice', '1 -1.2'), 'rejects negative non-integers');
+}, 'border-image-slice parsing support');
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-slice-rounding-expected.html b/third_party/WebKit/LayoutTests/fast/borders/border-image-slice-rounding-expected.html
new file mode 100644
index 0000000..ef85b43
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/borders/border-image-slice-rounding-expected.html
@@ -0,0 +1,16 @@
+<style>
+div {
+  border-image-source: url('resources/border-image.png');
+  border-image-repeat: round;
+  border-width: 10px;
+  margin: 4px;
+  width: 4px;
+  height: 4px;
+}
+</style>
+<div style="border-image-slice: 0;"></div>
+<div style="border-image-slice: 0;"></div>
+<div style="border-image-slice: 1;"></div>
+<div style="border-image-slice: 1;"></div>
+<div style="border-image-slice: 2;"></div>
+<div style="border-image-slice: 2;"></div>
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-slice-rounding.html b/third_party/WebKit/LayoutTests/fast/borders/border-image-slice-rounding.html
new file mode 100644
index 0000000..86f4edaa7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/borders/border-image-slice-rounding.html
@@ -0,0 +1,16 @@
+<style>
+div {
+  border-image-source: url('resources/border-image.png');
+  border-image-repeat: round;
+  border-width: 10px;
+  margin: 4px;
+  width: 4px;
+  height: 4px;
+}
+</style>
+<div style="border-image-slice: 0.0;"></div>
+<div style="border-image-slice: 0.1;"></div>
+<div style="border-image-slice: 0.9;"></div>
+<div style="border-image-slice: 1.1;"></div>
+<div style="border-image-slice: 1.9;"></div>
+<div style="border-image-slice: 2.1;"></div>
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-radius-with-box-shadow-01-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-radius-with-box-shadow-01-expected.png
index db91c09..d6d002b 100644
--- a/third_party/WebKit/LayoutTests/fast/borders/border-radius-with-box-shadow-01-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/borders/border-radius-with-box-shadow-01-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-radius-with-box-shadow-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-radius-with-box-shadow-expected.png
index ed0d2eb..26e6040 100644
--- a/third_party/WebKit/LayoutTests/fast/borders/border-radius-with-box-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/borders/border-radius-with-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/box-shadow/box-shadow-clipped-slices-expected.png b/third_party/WebKit/LayoutTests/fast/box-shadow/box-shadow-clipped-slices-expected.png
index ef4c6b6f..670a8163 100644
--- a/third_party/WebKit/LayoutTests/fast/box-shadow/box-shadow-clipped-slices-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/box-shadow/box-shadow-clipped-slices-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/box-shadow/box-shadow-radius-expected.png b/third_party/WebKit/LayoutTests/fast/box-shadow/box-shadow-radius-expected.png
index 484579df..cff1630 100644
--- a/third_party/WebKit/LayoutTests/fast/box-shadow/box-shadow-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/box-shadow/box-shadow-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/box-shadow/inset-box-shadow-radius-expected.png b/third_party/WebKit/LayoutTests/fast/box-shadow/inset-box-shadow-radius-expected.png
index 858389fa..998c549 100644
--- a/third_party/WebKit/LayoutTests/fast/box-shadow/inset-box-shadow-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/box-shadow/inset-box-shadow-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/box-shadow/inset-box-shadows-expected.png b/third_party/WebKit/LayoutTests/fast/box-shadow/inset-box-shadows-expected.png
index c26bdb7a..e472cd3 100644
--- a/third_party/WebKit/LayoutTests/fast/box-shadow/inset-box-shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/box-shadow/inset-box-shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/box-shadow/scaled-box-shadow-expected.png b/third_party/WebKit/LayoutTests/fast/box-shadow/scaled-box-shadow-expected.png
new file mode 100644
index 0000000..001b359
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/box-shadow/scaled-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/box-shadow/shadow-buffer-partial-expected.png b/third_party/WebKit/LayoutTests/fast/box-shadow/shadow-buffer-partial-expected.png
new file mode 100644
index 0000000..bb8035d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/box-shadow/shadow-buffer-partial-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/box-shadow/shadow-tiling-artifact-expected.png b/third_party/WebKit/LayoutTests/fast/box-shadow/shadow-tiling-artifact-expected.png
index 2618d98..4696e54 100644
--- a/third_party/WebKit/LayoutTests/fast/box-shadow/shadow-tiling-artifact-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/box-shadow/shadow-tiling-artifact-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/box-shadow/single-pixel-shadow-expected.png b/third_party/WebKit/LayoutTests/fast/box-shadow/single-pixel-shadow-expected.png
new file mode 100644
index 0000000..eb688a4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/box-shadow/single-pixel-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/css-intrinsic-dimensions/fit-content-container-with-replaced-child-expected.txt b/third_party/WebKit/LayoutTests/fast/css-intrinsic-dimensions/fit-content-container-with-replaced-child-expected.txt
new file mode 100644
index 0000000..6a8ebff
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css-intrinsic-dimensions/fit-content-container-with-replaced-child-expected.txt
@@ -0,0 +1,9 @@
+Tests that intrinsic width values on replaced element with fit-content container work.
+ PASS
+ PASS
+ PASS
+ PASS
+ PASS
+ PASS
+ PASS
+ PASS
diff --git a/third_party/WebKit/LayoutTests/fast/css-intrinsic-dimensions/fit-content-container-with-replaced-child.html b/third_party/WebKit/LayoutTests/fast/css-intrinsic-dimensions/fit-content-container-with-replaced-child.html
new file mode 100644
index 0000000..8ba73c5f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css-intrinsic-dimensions/fit-content-container-with-replaced-child.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<style>
+.container {
+    border: 5px solid blue;
+}
+.child {
+    background-color: lime;
+}
+body {
+    width: 500px;
+}
+</style>
+
+Tests that intrinsic width values on replaced element with fit-content container work.
+
+<!-- The 300px expected values are the 300px intrinsic width of a canvas. -->
+
+<!-- width tests with fit-content container -->
+<div class="container" style="width: fit-content;">
+    <canvas class="child" style="width: max-content;" data-expected-width="300"></canvas>
+</div>
+
+<div class="container" style="width: fit-content;">
+    <canvas class="child" style="width: min-content;" data-expected-width="300"></canvas>
+</div>
+
+<div class="container" style="width: fit-content;">
+    <canvas class="child" style="width: fit-content;" data-expected-width="300"></canvas>
+</div>
+
+<div class="container" style="width: fit-content;">
+    <canvas class="child" style="width: -webkit-fill-available;" data-expected-width="300"></canvas>
+</div>
+
+<!-- width tests with fill-available container -->
+<div class="container" style="width: -webkit-fill-available;">
+    <canvas class="child" style="width: max-content;" data-expected-width="300"></canvas>
+</div>
+
+<div class="container" style="width: -webkit-fill-available;">
+    <canvas class="child" style="width: min-content;" data-expected-width="300"></canvas>
+</div>
+
+<div class="container" style="width: -webkit-fill-available;">
+    <canvas class="child" style="width: fit-content;" data-expected-width="300"></canvas>
+</div>
+
+<div class="container" style="width: -webkit-fill-available;">
+    <canvas class="child" style="width: -webkit-fill-available;" data-expected-width="490"></canvas>
+</div>
+
+<script src="../../resources/check-layout.js"></script>
+<script>
+checkLayout(".container");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/box-shadow-and-border-radius-expected.png b/third_party/WebKit/LayoutTests/fast/css/box-shadow-and-border-radius-expected.png
index 777ef11..55d444d 100644
--- a/third_party/WebKit/LayoutTests/fast/css/box-shadow-and-border-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/css/box-shadow-and-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/dom/HTMLMeterElement/meter-styles-changing-pseudo.html b/third_party/WebKit/LayoutTests/fast/dom/HTMLMeterElement/meter-styles-changing-pseudo.html
index 1cbb9aa..3cb3cbf 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/HTMLMeterElement/meter-styles-changing-pseudo.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/HTMLMeterElement/meter-styles-changing-pseudo.html
@@ -17,7 +17,7 @@
   meter.styled { -webkit-appearance: none; }
   meter.styled::-webkit-meter-bar { background: gray; }
   meter.styled::-webkit-meter-optimum-value { background: green; }
-  meter.styled::-webkit-meter-suboptimal-value { background: yellow; }
+  meter.styled::-webkit-meter-suboptimum-value { background: yellow; }
   meter.styled::-webkit-meter-even-less-good-value { background: red; }
 </style>
 </head>
diff --git a/third_party/WebKit/LayoutTests/fast/events/mouse-down-on-resizable.html b/third_party/WebKit/LayoutTests/fast/events/mouse-down-on-resizable.html
deleted file mode 100644
index b0a889be..0000000
--- a/third_party/WebKit/LayoutTests/fast/events/mouse-down-on-resizable.html
+++ /dev/null
@@ -1,69 +0,0 @@
-<!DOCTYPE HTML>
-<script src="../../resources/js-test.js"></script>
-
-<style>
-textarea {
-  width: 100px;
-  height: 100px;
-  margin: 10px;
-}
-</style>
-
-<textarea id="target"></textarea>
-
-<div id="console"></div>
-
-<script>
-description("Verifies that correct mouse events are fired and when resizing an element");
-
-var testEventList = ['focus', 'mousedown', 'mouseup', 'pointerdown', 'pointerup'];
-var eventToPreventDefault = '';
-
-var seqNo = 0;
-
-function init() {
-  var targetDiv = document.getElementById("target");
-
-  testEventList.forEach(function(eventName) {
-    targetDiv.addEventListener(eventName, function(event) {
-      if (event.type == eventToPreventDefault) {
-        event.preventDefault();
-      }
-      debug(++seqNo + " Received " + event.type);
-    });
-  });
-}
-
-function runTests() {
-  var rect = document.getElementById("target").getBoundingClientRect();
-  var x = rect.right - 5;
-  var y = rect.bottom - 5;
-
-  debug("--- mousedown preventDefault ---");
-  eventToPreventDefault = 'mousedown';
-  debug("--- move mouse into target ---");
-  eventSender.mouseMoveTo(x, y);
-  debug("--- start resizing ---");
-  eventSender.mouseDown();
-  eventSender.mouseMoveTo(x + 30, y + 30);
-  debug("--- mouse released ---");
-  eventSender.mouseUp();
-
-  debug("--- No preventDefault ---");
-  eventToPreventDefault = '';
-  debug("--- move mouse into target ---");
-  eventSender.mouseMoveTo(x, y);
-  debug("--- start resizing ---");
-  eventSender.mouseDown();
-  eventSender.mouseMoveTo(x + 30, y + 30);
-  debug("--- mouse released ---");
-  eventSender.mouseUp();
-}
-
-init();
-if (window.eventSender)
-  runTests();
-else
-  debug("This test requires eventSender");
-
-</script>
diff --git a/third_party/WebKit/LayoutTests/fast/events/mouse-down-on-resizable-expected.txt b/third_party/WebKit/LayoutTests/fast/events/mouse-events-on-textarea-resize-expected.txt
similarity index 69%
rename from third_party/WebKit/LayoutTests/fast/events/mouse-down-on-resizable-expected.txt
rename to third_party/WebKit/LayoutTests/fast/events/mouse-events-on-textarea-resize-expected.txt
index 1faca03..cadd2772 100644
--- a/third_party/WebKit/LayoutTests/fast/events/mouse-down-on-resizable-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/mouse-events-on-textarea-resize-expected.txt
@@ -4,17 +4,20 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
---- mousedown preventDefault ---
+--- test with preventDefault on 'mousedown' ---
 --- move mouse into target ---
 --- start resizing ---
-1 Received mousedown
+Received mousedown
 --- mouse released ---
---- No preventDefault ---
+
+--- test with preventDefault on '' ---
 --- move mouse into target ---
 --- start resizing ---
-2 Received mousedown
+Received mousedown
 --- mouse released ---
-3 Received mouseup
+Received mouseup
+Received click
+
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/events/mouse-events-on-textarea-resize.html b/third_party/WebKit/LayoutTests/fast/events/mouse-events-on-textarea-resize.html
new file mode 100644
index 0000000..8a24269e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/mouse-events-on-textarea-resize.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<script src="../../resources/js-test.js"></script>
+
+<style>
+textarea {
+  width: 100px;
+  height: 100px;
+  margin: 10px;
+}
+</style>
+
+<textarea id="target"></textarea>
+
+<div id="console"></div>
+
+<script>
+description("Verifies that correct mouse events are fired and when resizing an element");
+
+var testEventList = ['focus', 'mousedown', 'mouseup', 'click'];
+var preventDefaultList = ['mousedown', ''];
+var eventToPreventDefault = '';
+
+function init() {
+  var targetDiv = document.getElementById("target");
+
+  testEventList.forEach(function(eventName) {
+    targetDiv.addEventListener(eventName, function(event) {
+      if (event.type == eventToPreventDefault) {
+        event.preventDefault();
+      }
+      debug("Received " + event.type);
+    });
+  });
+}
+
+function runTests() {
+  var rect = document.getElementById("target").getBoundingClientRect();
+  var x = rect.right - 5;
+  var y = rect.bottom - 5;
+
+
+  preventDefaultList.forEach(function(eventName) {
+    eventToPreventDefault = eventName;
+
+    debug("--- test with preventDefault on '" + eventName + "' ---");
+    debug("--- move mouse into target ---");
+    eventSender.mouseMoveTo(x, y);
+    debug("--- start resizing ---");
+    eventSender.mouseDown();
+    eventSender.mouseMoveTo(x + 30, y + 30);
+    debug("--- mouse released ---");
+    eventSender.mouseUp();
+    debug("");
+  });
+}
+
+init();
+if (window.eventSender)
+  runTests();
+else
+  debug("This test requires eventSender");
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/fake-mouse-event-pointer-types-expected.txt b/third_party/WebKit/LayoutTests/fast/events/pointerevents/fake-mouse-event-pointer-types-expected.txt
new file mode 100644
index 0000000..7a4ceea
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/fake-mouse-event-pointer-types-expected.txt
@@ -0,0 +1,14 @@
+mousemove
+mousemove
+Verifies that fake mouse events have correct pointer type for pointer events.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+--- move mouse into target ---
+1 Received mousemove
+2 Received mousemove
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/fake-mouse-event-pointer-types.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/fake-mouse-event-pointer-types.html
new file mode 100644
index 0000000..eba96f6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/fake-mouse-event-pointer-types.html
@@ -0,0 +1,70 @@
+<!DOCTYPE HTML>
+<script src="../../../resources/js-test.js"></script>
+
+<style>
+#target {
+  width: 100px;
+  height: 100px;
+  border: 5px black solid;
+  overflow-y: scroll;
+}
+#spacer {
+  height: 200px;
+}
+
+</style>
+
+<div id="target">
+<div id="spacer"></div>
+</div>
+
+<div id="console"></div>
+
+<script>
+description("Verifies that fake mouse events have correct pointer type for pointer events.");
+window.jsTestIsAsync = true;
+
+var testEventList = ['mousemove', 'pointermove'];
+var seqNo = 0;
+var targetDiv = document.getElementById('target');
+var eventCnt = 0;
+
+function init() {
+  targetDiv.scrollTop = targetDiv.scrollHeight;
+  testEventList.forEach(function(eventName) {
+    targetDiv.addEventListener(eventName, function(event) {
+      targetDiv.innerHTML += event.type + "<br/>";
+      targetDiv.scrollTop = targetDiv.scrollHeight;
+      if (event.type == 'pointermove' ) {
+        debug(++seqNo + " Received " + event.type + " " + event.pointerType);
+      } else {
+        debug(++seqNo + " Received " + event.type);
+        if (++eventCnt == 2) {
+          // The second mouse move is the synthetic mouse move event
+          finishJSTest();
+        }
+      }
+    });
+  });
+}
+
+function runTests() {
+  var rect = targetDiv.getBoundingClientRect();
+  var x = rect.left + 5;
+  var y = rect.bottom - 5;
+  debug("--- move mouse into target ---");
+  eventSender.mouseMoveTo(x, y);
+
+  // Just a hard limit to finish the test in this time as we should've got at least one synthetic event in this time
+  setTimeout(function() {
+    finishJSTest();
+  }, 400);
+}
+
+init();
+if (window.eventSender)
+  runTests();
+else
+  debug("This test requires eventSender");
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/frames/location-observe-callback-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/frames/location-observe-callback-crash-expected.txt
deleted file mode 100644
index 36a97a52..0000000
--- a/third_party/WebKit/LayoutTests/fast/frames/location-observe-callback-crash-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Accessing the Location object from a V8-triggered callback should not crash
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS Did not crash
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/frames/location-observe-callback-crash.html b/third_party/WebKit/LayoutTests/fast/frames/location-observe-callback-crash.html
deleted file mode 100644
index 03d1e7bd..0000000
--- a/third_party/WebKit/LayoutTests/fast/frames/location-observe-callback-crash.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE html>
-<script src="../../resources/js-test.js"></script>
-<script>
-description("Accessing the Location object from a V8-triggered callback should not crash");
-jsTestIsAsync = true;
-
-var obj = {};
-Object.observe(obj, function() {
-    window.location.hash = 'foo';
-    testPassed("Did not crash");
-    finishJSTest();
-});
-obj.foo = 1;
-</script>
diff --git a/third_party/WebKit/LayoutTests/fast/inline/inline-split-percent-height-object-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/inline/inline-split-percent-height-object-crash-expected.txt
new file mode 100644
index 0000000..7e24c80
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/inline/inline-split-percent-height-object-crash-expected.txt
@@ -0,0 +1,3 @@
+Test passes if it does not crash.
+
+
diff --git a/third_party/WebKit/LayoutTests/fast/inline/inline-split-percent-height-object-crash.html b/third_party/WebKit/LayoutTests/fast/inline/inline-split-percent-height-object-crash.html
new file mode 100644
index 0000000..0d3a00f1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/inline/inline-split-percent-height-object-crash.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<style>
+.CLASS8 {
+    display: inline-block;
+    max-height: 3.5%;
+}
+</style>
+<p>Test passes if it does not crash.</p>
+<span><div id="inner" style="display:none"></div></span>
+<div class="CLASS8"></div>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+
+document.documentElement.offsetTop;
+document.getElementById("inner").style.display = "";
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/js/observe/observe-globals-expected.txt b/third_party/WebKit/LayoutTests/fast/js/observe/observe-globals-expected.txt
deleted file mode 100644
index cf658de..0000000
--- a/third_party/WebKit/LayoutTests/fast/js/observe/observe-globals-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-Calling Object.observe on the global object should throw
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS Object.observe(window) threw exception TypeError: observe cannot be called on the global proxy object.
-PASS Object.observe(this) threw exception TypeError: observe cannot be called on the global proxy object.
-PASS Object.observe(frames[0]) threw exception TypeError: observe cannot be called on the global proxy object.
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/js/observe/observe-globals.html b/third_party/WebKit/LayoutTests/fast/js/observe/observe-globals.html
deleted file mode 100644
index 29c13f3..0000000
--- a/third_party/WebKit/LayoutTests/fast/js/observe/observe-globals.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<script src="../../../resources/js-test.js"></script>
-<script>
-jsTestIsAsync = true;
-description("Calling Object.observe on the global object should throw");
-function runTest() {
-    shouldThrow("Object.observe(window)");
-    shouldThrow("Object.observe(this)");
-    shouldThrow("Object.observe(frames[0])");
-    finishJSTest();
-}
-</script>
-<iframe onload="runTest()"></iframe>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-block-start-in-early-row-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-block-start-in-early-row-crash-expected.txt
new file mode 100644
index 0000000..065c337
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-block-start-in-early-row-crash-expected.txt
@@ -0,0 +1,7 @@
+When balancing the last row (fragmentainer group), be sure to skip past things that don't occur in that row, such as pagination struts in preceding rows.
+
+PASS if no crash or assertion failure.
+
+
+
+
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-block-start-in-early-row-crash.html b/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-block-start-in-early-row-crash.html
new file mode 100644
index 0000000..133154c5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-block-start-in-early-row-crash.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<script>
+    if (window.testRunner)
+        testRunner.dumpAsText();
+</script>
+<p>When balancing the last row (fragmentainer group), be sure to skip past things that don't occur
+    in that row, such as pagination struts in preceding rows.</p>
+<p>PASS if no crash or assertion failure.</p>
+<div style="-webkit-column-count:2; line-height:30px; height:30px; column-fill:auto;">
+    <div style="-webkit-column-count:2;">
+        <div style="height:20px;"></div>
+        <div> <!-- Has a pagination strut in the first column of the first row. Border box top
+                   pushed to the top of the second column of the first row. Ends in the first column
+                   of the second row. -->
+            <br> <!-- In the second column of the first row. -->
+            <br> <!-- In the first column of the second row. -->
+        </div>
+    </div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-line-at-exact-top-expected.txt b/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-line-at-exact-top-expected.txt
new file mode 100644
index 0000000..495ff6c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-line-at-exact-top-expected.txt
@@ -0,0 +1,9 @@
+The word BOMBINATE should be seen below.
+
+
+
+
+
+
+BOMBINATE
+PASS
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-line-at-exact-top.html b/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-line-at-exact-top.html
new file mode 100644
index 0000000..efd28125
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-line-at-exact-top.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<script src="../../resources/check-layout.js"></script>
+<p>The word BOMBINATE should be seen below.</p>
+<div id="outer" style="position:relative; overflow:hidden; -webkit-column-count:2; -webkit-column-gap:0; column-fill:auto; width:500px; height:70px; line-height:20px;">
+    <div data-expected-height="110" style="-webkit-column-count:2; -webkit-column-gap:0;">
+        <div style="height:120px;"></div>
+        <br> <!-- last line in second column in first row. Exactly no space left after this. -->
+        <br> <!-- first line in first column in second row. -->
+        <br> <!-- second line in first column in second row. -->
+        <br> <!-- first line in second column in second row. -->
+        <br> <!-- second line in second column in second row. -->
+    </div>
+    <!-- There should be exactly 30px left in the second outer column. -->
+    <div data-offset-x="250" data-offset-y="40" style="line-height:30px;">BOMBINATE</div>
+</div>
+<script>
+    checkLayout("#outer");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-lines-and-space-left-in-previous-row-expected.txt b/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-lines-and-space-left-in-previous-row-expected.txt
new file mode 100644
index 0000000..495ff6c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-lines-and-space-left-in-previous-row-expected.txt
@@ -0,0 +1,9 @@
+The word BOMBINATE should be seen below.
+
+
+
+
+
+
+BOMBINATE
+PASS
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-lines-and-space-left-in-previous-row.html b/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-lines-and-space-left-in-previous-row.html
new file mode 100644
index 0000000..0bd281c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/nested-balancing-with-lines-and-space-left-in-previous-row.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<script src="../../resources/check-layout.js"></script>
+<p>The word BOMBINATE should be seen below.</p>
+<div id="outer" style="position:relative; overflow:hidden; -webkit-column-count:2; -webkit-column-gap:0; column-fill:auto; width:500px; height:70px; line-height:20px;">
+    <div data-expected-height="110" style="-webkit-column-count:2; -webkit-column-gap:0;">
+        <div style="height:115px;"></div>
+        <br> <!-- last line in second column in first row. 5px of unusable space left after this. -->
+        <br> <!-- first line in first column in second row. -->
+        <br> <!-- second line in first column in second row. -->
+        <br> <!-- first line in second column in second row. -->
+        <br> <!-- second line in second column in second row. -->
+    </div>
+    <!-- There should be exactly 30px left in the second outer column. -->
+    <div data-offset-x="250" data-offset-y="40" style="line-height:30px;">BOMBINATE</div>
+</div>
+<script>
+    checkLayout("#outer");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/nested-with-forced-breaks-in-eariler-rows-expected.txt b/third_party/WebKit/LayoutTests/fast/multicol/nested-with-forced-breaks-in-eariler-rows-expected.txt
new file mode 100644
index 0000000..8a339323
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/nested-with-forced-breaks-in-eariler-rows-expected.txt
@@ -0,0 +1,13 @@
+Test that forced breaks in earlier rows don't confuse the column balancer.
+
+There should be a blue square below.
+
+
+
+
+
+
+
+
+
+PASS
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/nested-with-forced-breaks-in-eariler-rows.html b/third_party/WebKit/LayoutTests/fast/multicol/nested-with-forced-breaks-in-eariler-rows.html
new file mode 100644
index 0000000..7558bf7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/nested-with-forced-breaks-in-eariler-rows.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<script src="../../resources/check-layout.js"></script>
+<p>Test that forced breaks in earlier rows don't confuse the column balancer.</p>
+<p>There should be a blue square below.</p>
+<div id="outer" style="position:relative; -webkit-column-count:2; -webkit-column-gap:0; width:64px; line-height:32px; height:140px; column-fill:auto;">
+    <div style="-webkit-column-count:4; -webkit-column-gap:0;">
+        <br>
+        <div style="-webkit-column-break-before:always;">
+            <br>
+            <div style="-webkit-column-break-before:always;"><br></div>
+            <div style="-webkit-column-break-before:always;"><br></div>
+            <div style="-webkit-column-break-before:always; background:blue;" data-expected-height="128">
+                <div data-offset-y="0" data-expected-width="8" data-expected-height="32"><br></div>
+                <div data-offset-y="0" data-expected-width="8" data-expected-height="32"><br></div>
+                <div data-offset-y="0" data-expected-width="8" data-expected-height="32"><br></div>
+                <div data-offset-y="0" data-expected-width="8" data-expected-height="32"><br></div>
+            </div>
+        </div>
+    </div>
+</div>
+<script>
+    checkLayout("#outer");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/paged-in-multicol-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/multicol/paged-in-multicol-crash-expected.txt
new file mode 100644
index 0000000..7bf8ef7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/paged-in-multicol-crash-expected.txt
@@ -0,0 +1,4 @@
+PASS if no crash or assertion failure.
+
+
+
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/paged-in-multicol-crash.html b/third_party/WebKit/LayoutTests/fast/multicol/paged-in-multicol-crash.html
new file mode 100644
index 0000000..80b30e16
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/paged-in-multicol-crash.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<script>
+    if (window.testRunner)
+        testRunner.dumpAsText();
+</script>
+<p>PASS if no crash or assertion failure.</p>
+<div style="-webkit-columns:2;">
+    <div style="overflow-y:-webkit-paged-x;">
+        <div style="height:72vh;"></div>
+        <br>
+    </div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/pagination/multicol-expected.txt b/third_party/WebKit/LayoutTests/fast/pagination/multicol-expected.txt
new file mode 100644
index 0000000..aaa16ad
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/pagination/multicol-expected.txt
@@ -0,0 +1,12 @@
+Test that a multicol container inside a paged container is fragmented correctly.
+
+Below there should be a blue square above a papayawhip square above some spacing above a horizontal scrollbar. There should be no red.
+
+
+
+
+
+X
+X
+X
+PASS
diff --git a/third_party/WebKit/LayoutTests/fast/pagination/multicol.html b/third_party/WebKit/LayoutTests/fast/pagination/multicol.html
new file mode 100644
index 0000000..e47cac4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/pagination/multicol.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<script src="../../resources/check-layout.js"></script>
+<p>Test that a multicol container inside a paged container is fragmented correctly.</p>
+<p>Below there should be a blue square above a papayawhip square above some spacing above a horizontal scrollbar.
+    There should be no red.</p>
+<div id="pagedContainer" style="position:relative; overflow-y:-webkit-paged-x;  -webkit-column-gap:0; line-height:50px; width:50px; height:140px;">
+    <div style="-webkit-columns:2; -webkit-column-gap:0;">
+        <div data-offset-x="0" data-offset-y="0" style="background:blue;"><br></div>
+        <div data-offset-x="0" data-offset-y="50" style="background:papayawhip;"><br></div>
+        <div data-offset-x="25" data-offset-y="0" style="background:blue;"><br></div>
+        <div data-offset-x="25" data-offset-y="50" style="background:papayawhip;"><br></div>
+        <div data-offset-x="50" data-offset-y="0" style="background:red;">
+            X<br>
+            X<br>
+            X<br>
+        </div>
+    </div>
+</div>
+<script>
+    checkLayout("#pagedContainer");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/destroy-composited-scrollbar-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/destroy-composited-scrollbar-expected.txt
new file mode 100644
index 0000000..1116b05
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/repaint/destroy-composited-scrollbar-expected.txt
@@ -0,0 +1,28 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "children": [
+        {
+          "position": [0, 100],
+          "bounds": [200, 200],
+          "contentsOpaque": true,
+          "drawsContent": true,
+          "backgroundColor": "#0000FF",
+          "repaintRects": [
+            [185, 0, 15, 200],
+            [0, 0, 200, 200]
+          ],
+          "paintInvalidationClients": [
+            "##ALL##",
+            "LayoutBlockFlow (positioned) DIV"
+          ]
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/destroy-composited-scrollbar.html b/third_party/WebKit/LayoutTests/fast/repaint/destroy-composited-scrollbar.html
new file mode 100644
index 0000000..1cf579d2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/repaint/destroy-composited-scrollbar.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<script src="resources/text-based-repaint.js"></script>
+<script>
+if (window.internals)
+  internals.settings.setPreferCompositingToLCDTextEnabled(true);
+function repaintTest() {
+  document.getElementById('content').style.height = '100px';
+}
+onload = runRepaintTest;
+</script>
+Tests invalidation when a composited scrollbar is destroyed. Passes if there is no scrollbar.
+<div style="position: absolute; top: 100px; left: 0; width: 200px; height: 200px; overflow: auto; background-color: blue; will-change: transform">
+  <div id="content" style="width: 100px; height: 400px"></div>
+</div>
+
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/destroy-overlay-scrollbar-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/destroy-overlay-scrollbar-expected.txt
new file mode 100644
index 0000000..0731b2fb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/repaint/destroy-overlay-scrollbar-expected.txt
@@ -0,0 +1,19 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [193, 100, 7, 200],
+        [0, 200, 100, 100]
+      ],
+      "paintInvalidationClients": [
+        "VerticalScrollbar",
+        "LayoutBlockFlow DIV id='content'"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/destroy-overlay-scrollbar.html b/third_party/WebKit/LayoutTests/fast/repaint/destroy-overlay-scrollbar.html
new file mode 100644
index 0000000..64dce5c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/repaint/destroy-overlay-scrollbar.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<script src="resources/text-based-repaint.js"></script>
+<script>
+if (window.internals) {
+  internals.settings.setOverlayScrollbarsEnabled(true);
+  internals.settings.setMockScrollbarsEnabled(true);
+}
+function repaintTest() {
+  document.getElementById('content').style.height = '100px';
+}
+onload = runRepaintTest;
+</script>
+Tests invalidation when an overlay scrollbar is destroyed. Passes if there is no scrollbar.
+<div style="position: absolute; top: 100px; left: 0; width: 200px; height: 200px; overflow: auto">
+  <div id="content" style="width: 100px; height: 400px"></div>
+</div>
+
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/destroy-scrollbar-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/destroy-scrollbar-expected.txt
index 011d03cf..9ae8990 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/destroy-scrollbar-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/repaint/destroy-scrollbar-expected.txt
@@ -6,12 +6,10 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [185, 100, 15, 200],
-        [0, 100, 200, 200]
+        [185, 100, 15, 200]
       ],
       "paintInvalidationClients": [
         "VerticalScrollbar",
-        "LayoutBlockFlow (positioned) DIV",
         "LayoutBlockFlow (positioned) DIV"
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/layout-state-only-positioned-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/layout-state-only-positioned-expected.txt
index afd819cb..0fb1fe7c 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/layout-state-only-positioned-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/repaint/layout-state-only-positioned-expected.txt
@@ -10,8 +10,8 @@
         [3, 103, 10, 53]
       ],
       "paintInvalidationClients": [
-        "VerticalScrollbar",
         "LayoutBlockFlow (positioned) DIV",
+        "VerticalScrollbar",
         "LayoutBlockFlow (positioned) DIV id='q'"
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/overflow-move-after-scroll-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/overflow-move-after-scroll-expected.txt
index 67397b3a..8197a75f 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/overflow-move-after-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/repaint/overflow-move-after-scroll-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [10, 60],
           "bounds": [700, 400],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [300, 100, 120, 50],
@@ -17,10 +18,10 @@
           "children": [
             {
               "bounds": [685, 385],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [685, 600],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [300, 200, 120, 50],
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/overflow-scroll-after-move-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/overflow-scroll-after-move-expected.txt
index d4e783d..7a74da9 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/overflow-scroll-after-move-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/repaint/overflow-scroll-after-move-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [10, 60],
           "bounds": [300, 400],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [50, 160, 200, 50],
@@ -17,10 +18,10 @@
           "children": [
             {
               "bounds": [285, 385],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 900],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [50, 310, 200, 50],
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/overflow-scroll-body-appear-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/overflow-scroll-body-appear-expected.txt
index d62068de..cdd6904 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/overflow-scroll-body-appear-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/repaint/overflow-scroll-body-appear-expected.txt
@@ -7,11 +7,13 @@
       "drawsContent": true,
       "repaintRects": [
         [785, 585, 15, 15],
+        [785, 0, 15, 585],
         [8, 50, 784, 18],
         [8, 50, 769, 18],
         [8, 16, 2000, 2068],
         [8, 16, 784, 18],
         [8, 16, 769, 18],
+        [0, 585, 785, 15],
         [0, 0, 2008, 2092],
         [0, 0, 785, 585]
       ],
@@ -27,8 +29,8 @@
         "LayoutBlockFlow BODY",
         "LayoutBlockFlow P",
         "LayoutBlockFlow P",
-        "HorizontalScrollbar",
-        "VerticalScrollbar"
+        "LayoutView #document",
+        "LayoutView #document"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/resize-scrollable-div-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/resize-scrollable-div-expected.txt
index de13bc9..0bd5648e 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/resize-scrollable-div-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/repaint/resize-scrollable-div-expected.txt
@@ -17,9 +17,10 @@
       ],
       "paintInvalidationClients": [
         "LayoutBlockFlow DIV id='div'",
+        "LayoutBlockFlow DIV id='div'",
         "HorizontalScrollbar",
-        "VerticalScrollbar",
-        "LayoutBlockFlow DIV id='div'"
+        "LayoutBlockFlow DIV id='div'",
+        "VerticalScrollbar"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/scroll-absolute-layer-with-reflection-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/scroll-absolute-layer-with-reflection-expected.txt
index 0cc8d882b..4c28d2f 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/scroll-absolute-layer-with-reflection-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/repaint/scroll-absolute-layer-with-reflection-expected.txt
@@ -9,12 +9,14 @@
         [250, 230, 100, 100],
         [250, 230, 100, 100],
         [250, 230, 100, 100],
+        [250, 230, 100, 100],
         [250, 230, 100, 100]
       ],
       "paintInvalidationClients": [
         "LayoutBlockFlow (positioned) DIV id='moveMe' class='absolute clipped'",
         "LayoutBlockFlow (relative positioned) DIV class='relative reflected'",
         "LayoutBlockFlow DIV class='green'",
+        "LayoutReplica (anonymous)",
         "LayoutBlockFlow (positioned) DIV class='absolute red'"
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/scroll-fixed-layer-with-reflection-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/scroll-fixed-layer-with-reflection-expected.txt
index 20c3907e..080d1e0 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/scroll-fixed-layer-with-reflection-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/repaint/scroll-fixed-layer-with-reflection-expected.txt
@@ -8,11 +8,13 @@
       "repaintRects": [
         [250, 280, 100, 100],
         [250, 280, 100, 100],
+        [250, 280, 100, 100],
         [250, 280, 100, 100]
       ],
       "paintInvalidationClients": [
         "LayoutBlockFlow (positioned) DIV id='moveMe' class='fixed clipped'",
         "LayoutBlockFlow (positioned) DIV class='absolute green reflected'",
+        "LayoutReplica (anonymous)",
         "LayoutBlockFlow (positioned) DIV class='absolute red'"
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/scrollbar-invalidation-on-resize-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/scrollbar-invalidation-on-resize-expected.txt
index 88b08278..c65f1db 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/scrollbar-invalidation-on-resize-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/repaint/scrollbar-invalidation-on-resize-expected.txt
@@ -17,9 +17,9 @@
       ],
       "paintInvalidationClients": [
         "LayoutBlockFlow (positioned) DIV id='scrollable'",
+        "LayoutBlockFlow (positioned) DIV id='scrollable'",
         "HorizontalScrollbar",
-        "VerticalScrollbar",
-        "LayoutBlockFlow (positioned) DIV id='scrollable'"
+        "VerticalScrollbar"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/scrollbar-invalidation-on-resize-with-border-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/scrollbar-invalidation-on-resize-with-border-expected.txt
index 6295919..94cbb0f 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/scrollbar-invalidation-on-resize-with-border-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/repaint/scrollbar-invalidation-on-resize-with-border-expected.txt
@@ -17,9 +17,9 @@
       ],
       "paintInvalidationClients": [
         "LayoutBlockFlow (positioned) DIV id='scrollable'",
+        "LayoutBlockFlow (positioned) DIV id='scrollable'",
         "HorizontalScrollbar",
-        "VerticalScrollbar",
-        "LayoutBlockFlow (positioned) DIV id='scrollable'"
+        "VerticalScrollbar"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/fast/table/table-split-percent-height-expected.html b/third_party/WebKit/LayoutTests/fast/table/table-split-percent-height-expected.html
new file mode 100644
index 0000000..d3c2bc1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/table/table-split-percent-height-expected.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<p>There should be a blue square below.</p>
+<div style="display:table; height:450px;">
+    <div style="display:table-row-group;">
+        <div></div>
+        <div id="splitter" style="display: table-row;"></div>
+        <div style="width:75px; height:50%; background:blue;"></div>
+    </div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/table/table-split-percent-height.html b/third_party/WebKit/LayoutTests/fast/table/table-split-percent-height.html
new file mode 100644
index 0000000..cd826a6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/table/table-split-percent-height.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<p>There should be a blue square below.</p>
+<div style="display:table; height:450px;">
+    <div style="display:table-row-group;">
+        <div></div>
+        <div id="splitter" style="display:none;"></div>
+        <div style="width:75px; height:50%; background:blue;"></div>
+    </div>
+</div>
+<script>
+    document.body.offsetTop;
+    document.getElementById("splitter").style.display = "table-row";
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-hittest-expected.txt b/third_party/WebKit/LayoutTests/hittesting/border-hittest-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/fast/borders/border-hittest-expected.txt
rename to third_party/WebKit/LayoutTests/hittesting/border-hittest-expected.txt
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-hittest-inlineFlowBox-expected.txt b/third_party/WebKit/LayoutTests/hittesting/border-hittest-inlineFlowBox-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/fast/borders/border-hittest-inlineFlowBox-expected.txt
rename to third_party/WebKit/LayoutTests/hittesting/border-hittest-inlineFlowBox-expected.txt
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-hittest-inlineFlowBox.html b/third_party/WebKit/LayoutTests/hittesting/border-hittest-inlineFlowBox.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/fast/borders/border-hittest-inlineFlowBox.html
rename to third_party/WebKit/LayoutTests/hittesting/border-hittest-inlineFlowBox.html
index cbca48d..75e64e2 100644
--- a/third_party/WebKit/LayoutTests/fast/borders/border-hittest-inlineFlowBox.html
+++ b/third_party/WebKit/LayoutTests/hittesting/border-hittest-inlineFlowBox.html
@@ -1,7 +1,7 @@
 <!doctype html>
 <html>
 <head>
-<script src="../../resources/js-test.js"></script>
+<script src="../resources/js-test.js"></script>
 <style>
 span {
     background-color: lightgray;
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-hittest.html b/third_party/WebKit/LayoutTests/hittesting/border-hittest.html
similarity index 72%
rename from third_party/WebKit/LayoutTests/fast/borders/border-hittest.html
rename to third_party/WebKit/LayoutTests/hittesting/border-hittest.html
index e8fdae96..63a1f19 100644
--- a/third_party/WebKit/LayoutTests/fast/borders/border-hittest.html
+++ b/third_party/WebKit/LayoutTests/hittesting/border-hittest.html
@@ -1,7 +1,7 @@
 <!doctype html>
 <html>
 <head>
-<script src="../../resources/js-test.js"></script>
+<script src="../resources/js-test.js"></script>
 <style>
 img{
     background-color:red;
@@ -10,7 +10,7 @@
 </style>
 </head>
 <body>
-<img src="./resources/mask.png" width="100px" height="100px" />
+<img src="../fast/borders/resources/mask.png" width="100px" height="100px" />
 <div id="console"></div>
 </body>
 <script>
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-radius-hittest-expected.txt b/third_party/WebKit/LayoutTests/hittesting/border-radius-hittest-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/fast/borders/border-radius-hittest-expected.txt
rename to third_party/WebKit/LayoutTests/hittesting/border-radius-hittest-expected.txt
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-radius-hittest.html b/third_party/WebKit/LayoutTests/hittesting/border-radius-hittest.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/fast/borders/border-radius-hittest.html
rename to third_party/WebKit/LayoutTests/hittesting/border-radius-hittest.html
index eb0db98f..79c0b66 100644
--- a/third_party/WebKit/LayoutTests/fast/borders/border-radius-hittest.html
+++ b/third_party/WebKit/LayoutTests/hittesting/border-radius-hittest.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<script src="../../resources/js-test.js"></script>
+<script src="../resources/js-test.js"></script>
 <script>
 var x, y;
 
diff --git a/third_party/WebKit/LayoutTests/hittesting/inner-border-radius-hittest-expected.txt b/third_party/WebKit/LayoutTests/hittesting/inner-border-radius-hittest-expected.txt
new file mode 100644
index 0000000..c247cecc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/hittesting/inner-border-radius-hittest-expected.txt
@@ -0,0 +1,24 @@
+The inner border radius clip should be respected for hit testing.
+
+ 
+ PASS successfullyParsed is true
+
+TEST COMPLETE
+PASS document.elementFromPoint(x + 20, y + 20).id is 'container'
+PASS document.elementFromPoint(x + 35, y + 35).id is 'roundedBoxWithoutScrollbars'
+PASS document.elementFromPoint(x + 60, y + 60).id is 'roundedBoxWithoutScrollbars'
+PASS document.elementFromPoint(x + 68, y + 68).id is 'roundedBoxChildWithoutScrollbars'
+PASS document.elementFromPoint(x + 80, y + 80).id is 'roundedBoxChildWithoutScrollbars'
+PASS document.elementFromPoint(x + 230, y + 230).id is 'roundedBoxChildWithoutScrollbars'
+PASS document.elementFromPoint(x + 240, y + 240).id is 'roundedBoxWithoutScrollbars'
+PASS document.elementFromPoint(x + 265, y + 265).id is 'roundedBoxWithoutScrollbars'
+PASS document.elementFromPoint(x + 275, y + 275).id is 'container'
+PASS document.elementFromPoint(x + 20, y + 20).id is 'container'
+PASS document.elementFromPoint(x + 35, y + 35).id is 'roundedBoxWithScrollbars'
+PASS document.elementFromPoint(x + 60, y + 60).id is 'roundedBoxWithScrollbars'
+PASS document.elementFromPoint(x + 68, y + 68).id is 'roundedBoxWithScrollbarsChild'
+PASS document.elementFromPoint(x + 80, y + 80).id is 'roundedBoxWithScrollbarsChild'
+PASS document.elementFromPoint(x + 230, y + 230).id is 'roundedBoxWithScrollbarsChild'
+PASS document.elementFromPoint(x + 265, y + 265).id is 'roundedBoxWithScrollbars'
+PASS document.elementFromPoint(x + 275, y + 275).id is 'container'
+
diff --git a/third_party/WebKit/LayoutTests/hittesting/inner-border-radius-hittest.html b/third_party/WebKit/LayoutTests/hittesting/inner-border-radius-hittest.html
new file mode 100644
index 0000000..1ab0440
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/hittesting/inner-border-radius-hittest.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<script src="../resources/js-test.js"></script>
+<script>
+var x, y;
+function test() {
+    var rectWithoutScrollbars = roundedBoxWithoutScrollbars.getBoundingClientRect();
+    x = rectWithoutScrollbars.left;
+    y = rectWithoutScrollbars.top;
+    // At top-left corner, outside the outer border radius.
+    shouldBe("document.elementFromPoint(x + 20, y + 20).id", "'container'");
+    // At top-left corner, inside outer border radius.
+    shouldBe("document.elementFromPoint(x + 35, y + 35).id", "'roundedBoxWithoutScrollbars'");
+    shouldBe("document.elementFromPoint(x + 60, y + 60).id", "'roundedBoxWithoutScrollbars'");
+    // At top-left corner, insider inner border radius.
+    shouldBe("document.elementFromPoint(x + 68, y + 68).id", "'roundedBoxChildWithoutScrollbars'");
+    // At top-left corner, fully inside border.
+    shouldBe("document.elementFromPoint(x + 80, y + 80).id", "'roundedBoxChildWithoutScrollbars'");
+    // At bottom-right corner, inside inner border radius.
+    shouldBe("document.elementFromPoint(x + 230, y + 230).id", "'roundedBoxChildWithoutScrollbars'");
+    // At bottom-right corner, insider inner border radius.
+    shouldBe("document.elementFromPoint(x + 240, y + 240).id", "'roundedBoxWithoutScrollbars'");
+    shouldBe("document.elementFromPoint(x + 265, y + 265).id", "'roundedBoxWithoutScrollbars'");
+    // At bottom-right corner, outside the outer border radius.
+    shouldBe("document.elementFromPoint(x + 275, y + 275).id", "'container'");
+
+    var rectWithScrollbars = roundedBoxWithScrollbars.getBoundingClientRect();
+    x = rectWithScrollbars.left;
+    y = rectWithScrollbars.top;
+    // At top-left corner with scrollbars, outside the outer border radius.
+    shouldBe("document.elementFromPoint(x + 20, y + 20).id", "'container'");
+    // At top-left corner with scrollbars, inside outer border radius.
+    shouldBe("document.elementFromPoint(x + 35, y + 35).id", "'roundedBoxWithScrollbars'");
+    shouldBe("document.elementFromPoint(x + 60, y + 60).id", "'roundedBoxWithScrollbars'");
+    // At top-left corner with scrollbars, insider inner border radius.
+    shouldBe("document.elementFromPoint(x + 68, y + 68).id", "'roundedBoxWithScrollbarsChild'");
+    // At top-left corner with scrollbars, fully inside border.
+    shouldBe("document.elementFromPoint(x + 80, y + 80).id", "'roundedBoxWithScrollbarsChild'");
+    // At bottom-right corner with scrollbars, inside inner border radius.
+    shouldBe("document.elementFromPoint(x + 230, y + 230).id", "'roundedBoxWithScrollbarsChild'");
+    // At bottom-right corner with scrollbars, insider inner border radius.
+    shouldBe("document.elementFromPoint(x + 265, y + 265).id", "'roundedBoxWithScrollbars'");
+    // At bottom-right corner with scrollbars, outside the outer border radius.
+    shouldBe("document.elementFromPoint(x + 275, y + 275).id", "'container'");
+}
+</script>
+<style>
+    #container {
+        display: inline-block;
+        background-color: black;
+    }
+    .roundedBox {
+        width: 200px;
+        height: 200px;
+        border-radius: 100px;
+        background-color: red;
+        border: 50px solid green;
+        display: inline-block;
+    }
+    .roundedBox:hover {
+        border-color: red;
+    }
+    .roundedBoxChild {
+        width: 200px;
+        height: 200px;
+        background-color: orange;
+    }
+    .roundedBoxChild:hover {
+        background-color: blue;
+    }
+    #roundedBoxWithoutScrollbars {
+        overflow: auto;
+    }
+    #roundedBoxWithScrollbars {
+        overflow: scroll;
+    }
+</style>
+<body onload="test()">
+    <p>The inner border radius clip should be respected for hit testing.</p>
+    <div id="container">
+        <div id="roundedBoxWithoutScrollbars" class="roundedBox">
+            <div id="roundedBoxChildWithoutScrollbars" class="roundedBoxChild"></div>
+        </div>
+        <div id="roundedBoxWithScrollbars" class="roundedBox">
+            <div id="roundedBoxWithScrollbarsChild" class="roundedBoxChild"></div>
+        </div>
+    </div>
+    <div id="console"></div>
+</body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/history/push-state-in-new-frame-expected.txt b/third_party/WebKit/LayoutTests/http/tests/history/push-state-in-new-frame-expected.txt
index 226e00e3..b8e91e0 100644
--- a/third_party/WebKit/LayoutTests/http/tests/history/push-state-in-new-frame-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/history/push-state-in-new-frame-expected.txt
@@ -1,3 +1,4 @@
+CONSOLE ERROR: line 11: Uncaught SecurityError: Failed to execute 'pushState' on 'History': A history state object with URL 'http://127.0.0.1:8000/pushState.html' cannot be created in a document with origin 'http://127.0.0.1:8000' and URL 'about:blank'.
 
 
 ============== Back Forward List ==============
diff --git a/third_party/WebKit/LayoutTests/http/tests/loading/state-object-security-exception-expected.txt b/third_party/WebKit/LayoutTests/http/tests/loading/state-object-security-exception-expected.txt
index de6f7d2..f9d6d56 100644
--- a/third_party/WebKit/LayoutTests/http/tests/loading/state-object-security-exception-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/loading/state-object-security-exception-expected.txt
@@ -5,28 +5,28 @@
 main frame - didFinishLoadForFrame
 This test makes sure that calls to pushState() and replaceState() with URLs that violate the security origin check fail as expected.
 
-Trying to pushState() with url http://localhost/test.html failed with exception SecurityError: Failed to execute 'pushState' on 'History': A history state object with URL 'http://localhost/test.html' cannot be created in a document with origin 'http://127.0.0.1:8000'.
+Trying to pushState() with url http://localhost/test.html failed with exception SecurityError: Failed to execute 'pushState' on 'History': A history state object with URL 'http://localhost/test.html' cannot be created in a document with origin 'http://127.0.0.1:8000' and URL 'http://127.0.0.1:8000/loading/state-object-security-exception.html'.
 History length is 1
-Trying to replaceState() with url http://localhost/test.html failed with exception SecurityError: Failed to execute 'replaceState' on 'History': A history state object with URL 'http://localhost/test.html' cannot be created in a document with origin 'http://127.0.0.1:8000'.
+Trying to replaceState() with url http://localhost/test.html failed with exception SecurityError: Failed to execute 'replaceState' on 'History': A history state object with URL 'http://localhost/test.html' cannot be created in a document with origin 'http://127.0.0.1:8000' and URL 'http://127.0.0.1:8000/loading/state-object-security-exception.html'.
 History length is 1
-Trying to pushState() with url http://localhost:8001/test.html failed with exception SecurityError: Failed to execute 'pushState' on 'History': A history state object with URL 'http://localhost:8001/test.html' cannot be created in a document with origin 'http://127.0.0.1:8000'.
+Trying to pushState() with url http://localhost:8001/test.html failed with exception SecurityError: Failed to execute 'pushState' on 'History': A history state object with URL 'http://localhost:8001/test.html' cannot be created in a document with origin 'http://127.0.0.1:8000' and URL 'http://127.0.0.1:8000/loading/state-object-security-exception.html'.
 History length is 1
-Trying to replaceState() with url http://localhost:8001/test.html failed with exception SecurityError: Failed to execute 'replaceState' on 'History': A history state object with URL 'http://localhost:8001/test.html' cannot be created in a document with origin 'http://127.0.0.1:8000'.
+Trying to replaceState() with url http://localhost:8001/test.html failed with exception SecurityError: Failed to execute 'replaceState' on 'History': A history state object with URL 'http://localhost:8001/test.html' cannot be created in a document with origin 'http://127.0.0.1:8000' and URL 'http://127.0.0.1:8000/loading/state-object-security-exception.html'.
 History length is 1
-Trying to pushState() with url http://www.webkit.org/test.html failed with exception SecurityError: Failed to execute 'pushState' on 'History': A history state object with URL 'http://www.webkit.org/test.html' cannot be created in a document with origin 'http://127.0.0.1:8000'.
+Trying to pushState() with url http://www.webkit.org/test.html failed with exception SecurityError: Failed to execute 'pushState' on 'History': A history state object with URL 'http://www.webkit.org/test.html' cannot be created in a document with origin 'http://127.0.0.1:8000' and URL 'http://127.0.0.1:8000/loading/state-object-security-exception.html'.
 History length is 1
-Trying to replaceState() with url http://www.webkit.org/test.html failed with exception SecurityError: Failed to execute 'replaceState' on 'History': A history state object with URL 'http://www.webkit.org/test.html' cannot be created in a document with origin 'http://127.0.0.1:8000'.
+Trying to replaceState() with url http://www.webkit.org/test.html failed with exception SecurityError: Failed to execute 'replaceState' on 'History': A history state object with URL 'http://www.webkit.org/test.html' cannot be created in a document with origin 'http://127.0.0.1:8000' and URL 'http://127.0.0.1:8000/loading/state-object-security-exception.html'.
 History length is 1
-Trying to pushState() with url http://www.webkit.org/ failed with exception SecurityError: Failed to execute 'pushState' on 'History': A history state object with URL 'http://www.webkit.org/' cannot be created in a document with origin 'http://127.0.0.1:8000'.
+Trying to pushState() with url http://www.webkit.org/ failed with exception SecurityError: Failed to execute 'pushState' on 'History': A history state object with URL 'http://www.webkit.org/' cannot be created in a document with origin 'http://127.0.0.1:8000' and URL 'http://127.0.0.1:8000/loading/state-object-security-exception.html'.
 History length is 1
-Trying to replaceState() with url http://www.webkit.org/ failed with exception SecurityError: Failed to execute 'replaceState' on 'History': A history state object with URL 'http://www.webkit.org/' cannot be created in a document with origin 'http://127.0.0.1:8000'.
+Trying to replaceState() with url http://www.webkit.org/ failed with exception SecurityError: Failed to execute 'replaceState' on 'History': A history state object with URL 'http://www.webkit.org/' cannot be created in a document with origin 'http://127.0.0.1:8000' and URL 'http://127.0.0.1:8000/loading/state-object-security-exception.html'.
 History length is 1
-Trying to pushState() with url ftp://www.webkit.org/ failed with exception SecurityError: Failed to execute 'pushState' on 'History': A history state object with URL 'ftp://www.webkit.org/' cannot be created in a document with origin 'http://127.0.0.1:8000'.
+Trying to pushState() with url ftp://www.webkit.org/ failed with exception SecurityError: Failed to execute 'pushState' on 'History': A history state object with URL 'ftp://www.webkit.org/' cannot be created in a document with origin 'http://127.0.0.1:8000' and URL 'http://127.0.0.1:8000/loading/state-object-security-exception.html'.
 History length is 1
-Trying to replaceState() with url ftp://www.webkit.org/ failed with exception SecurityError: Failed to execute 'replaceState' on 'History': A history state object with URL 'ftp://www.webkit.org/' cannot be created in a document with origin 'http://127.0.0.1:8000'.
+Trying to replaceState() with url ftp://www.webkit.org/ failed with exception SecurityError: Failed to execute 'replaceState' on 'History': A history state object with URL 'ftp://www.webkit.org/' cannot be created in a document with origin 'http://127.0.0.1:8000' and URL 'http://127.0.0.1:8000/loading/state-object-security-exception.html'.
 History length is 1
-Trying to pushState() with url file://anyfile.html/ failed with exception SecurityError: Failed to execute 'pushState' on 'History': A history state object with URL 'file://anyfile.html/' cannot be created in a document with origin 'http://127.0.0.1:8000'.
+Trying to pushState() with url file://anyfile.html/ failed with exception SecurityError: Failed to execute 'pushState' on 'History': A history state object with URL 'file://anyfile.html/' cannot be created in a document with origin 'http://127.0.0.1:8000' and URL 'http://127.0.0.1:8000/loading/state-object-security-exception.html'.
 History length is 1
-Trying to replaceState() with url file://anyfile.html/ failed with exception SecurityError: Failed to execute 'replaceState' on 'History': A history state object with URL 'file://anyfile.html/' cannot be created in a document with origin 'http://127.0.0.1:8000'.
+Trying to replaceState() with url file://anyfile.html/ failed with exception SecurityError: Failed to execute 'replaceState' on 'History': A history state object with URL 'file://anyfile.html/' cannot be created in a document with origin 'http://127.0.0.1:8000' and URL 'http://127.0.0.1:8000/loading/state-object-security-exception.html'.
 History length is 1
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/mime/javascript-mimetype-usecounters-expected.txt b/third_party/WebKit/LayoutTests/http/tests/mime/javascript-mimetype-usecounters-expected.txt
new file mode 100644
index 0000000..55b878b7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/mime/javascript-mimetype-usecounters-expected.txt
@@ -0,0 +1,17 @@
+ALERT: Correct
+ALERT: Correct
+ALERT: Correct
+ALERT: Correct
+CONSOLE ERROR: Refused to execute script from 'http://127.0.0.1:8000/mime/resources/javascript-mimetype.php?mimetype=image/foo' because its MIME type ('image/foo') is not executable.
+CONSOLE ERROR: Refused to execute script from 'http://localhost:8000/mime/resources/javascript-mimetype.php?mimetype=image/bar' because its MIME type ('image/bar') is not executable.
+ALERT: Correct
+ALERT: Correct
+ALERT: Correct
+ALERT: Correct
+ALERT: Correct
+ALERT: Correct
+ALERT: Correct
+ALERT: Correct
+ALERT: Correct
+ALERT: Correct
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/mime/javascript-mimetype-usecounters.html b/third_party/WebKit/LayoutTests/http/tests/mime/javascript-mimetype-usecounters.html
new file mode 100644
index 0000000..0bff814
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/mime/javascript-mimetype-usecounters.html
@@ -0,0 +1,93 @@
+<body>
+<script src="../../../resources/testharness.js"></script>
+<script>
+testRunner.dumpAsText();
+function runScript(name, callback) {
+  var script = document.createElement("script");
+  script.src = name;
+  script.onload = callback;
+  document.head.appendChild(script);
+}
+var increment = 0;
+var SameOriginTextScript = 1066,
+    SameOriginApplicationScript = 1067,
+    SameOriginOtherScript = 1068,
+    CrossOriginTextScript = 1069,
+    CrossOriginApplicationScript = 1070,
+    CrossOriginOtherScript = 1071;
+var counters = [SameOriginTextScript,
+                SameOriginApplicationScript,
+                SameOriginOtherScript,
+                CrossOriginTextScript,
+                CrossOriginApplicationScript,
+                CrossOriginOtherScript];
+function getUseCounters() {
+  return counters.map(counter => window.internals.isUseCounted(document, counter));
+}
+function testCase(test, callback) {
+  var previousCounters = getUseCounters();
+  var previousIncrement = increment;
+  var url = (test.crossOrigin ? "http://localhost:8000" : "") +
+            "/mime/resources/javascript-mimetype.php?mimetype=" + test.mimetype;
+  runScript(url, function() {
+    assert_false(test.expectFailure === true);
+    assert_equals(previousIncrement + 1, increment, "should have run the script");
+    var newCounters = getUseCounters();
+    for (var counter in counters) {
+      if (counters[counter] === test.useCounter) {
+        assert_equals(previousCounters[counter], !!test.secondTime);
+        assert_equals(newCounters[counter], true);
+      } else {
+        assert_equals(previousCounters[counter], newCounters[counter]);
+      }
+    }
+    alert("Correct");
+    callback();
+  });
+  if (test.expectFailure) callback();
+}
+function nextCase(cases, i) {
+  if (i >= cases.length)
+    return function() {};
+  else return function() {
+    testCase(cases[i], nextCase(cases, i + 1));
+  }
+}
+function runTestCases(cases) {
+  nextCase(cases, 0)();
+}
+
+var initialCounters = getUseCounters();
+for (var initialCounter of initialCounters) {
+  assert_false(initialCounter);
+}
+runTestCases([
+  // JS mimetypes don't increment any usecounters
+  { mimetype: 'text/livescript', crossOrigin: false, useCounter: -1 },
+  { mimetype: 'text/jscript', crossOrigin: true, useCounter: -1 },
+  { mimetype: 'application/ecmascript', crossOrigin: false, useCounter: -1 },
+  { mimetype: 'text/ecmascript', crossOrigin: true, useCounter: -1 },
+
+  // Counters are not incremented on invalid use of images
+  { mimetype: 'image/foo', crossOrigin: false, useCounter: -1, expectFailure: true },
+  { mimetype: 'image/bar', crossOrigin: true, useCounter: -1, expectFailure: true },
+
+  // Text mimetypes are registered separately
+  { mimetype: 'text/html', crossOrigin: false, useCounter: SameOriginTextScript },
+  { mimetype: 'text/csv', crossOrigin: false, useCounter: SameOriginTextScript, secondTime: true },
+
+  { mimetype: 'text/html', crossOrigin: true, useCounter: CrossOriginTextScript },
+  { mimetype: 'text/csv', crossOrigin: true, useCounter: CrossOriginTextScript , secondTime: true },
+
+  { mimetype: 'foo/html', crossOrigin: false, useCounter: SameOriginOtherScript },
+  { mimetype: 'foo/csv', crossOrigin: false, useCounter: SameOriginOtherScript, secondTime: true },
+
+  { mimetype: 'foo/html', crossOrigin: true, useCounter: CrossOriginOtherScript },
+  { mimetype: 'foo/csv', crossOrigin: true, useCounter: CrossOriginOtherScript, secondTime: true },
+
+  { mimetype: 'application/csv', crossOrigin: false, useCounter: SameOriginApplicationScript },
+
+  { mimetype: 'application/csv', crossOrigin: true, useCounter: CrossOriginApplicationScript },
+]);
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/mime/resources/javascript-mimetype.php b/third_party/WebKit/LayoutTests/http/tests/mime/resources/javascript-mimetype.php
new file mode 100644
index 0000000..98b8968
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/mime/resources/javascript-mimetype.php
@@ -0,0 +1,5 @@
+<?php
+$mimetype = strtolower($_GET["mimetype"]);
+header("Content-Type: $mimetype");
+?>
+increment++;
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-at-unique-origin-denied.html b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-at-unique-origin-denied.html
new file mode 100644
index 0000000..a3f01890
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-at-unique-origin-denied.html
@@ -0,0 +1,10 @@
+<meta http-equiv="Content-Security-Policy" content="sandbox allow-scripts">
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+test(function () {
+    assert_throws('SecurityError', function () {
+        history.pushState(null, null, document.URL);
+    });
+}, 'pushState at unique origin should fail with SecurityError');
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-auth-denied.html b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-auth-denied.html
new file mode 100644
index 0000000..13cf0f3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-auth-denied.html
@@ -0,0 +1,15 @@
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+test(function () {
+    // http://username@password:localhost:8000/... should be blocked.
+    var originWithAuth = new URL(document.URL);
+    originWithAuth.username += 'username';
+    originWithAuth.password += 'password';
+    originWithAuth = originWithAuth.href;
+
+    assert_throws('SecurityError', function () {
+        history.pushState(null, null, originWithAuth);
+    });
+}, 'pushState that changes credentials should fail with SecurityError');
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-in-blob-denied.html b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-in-blob-denied.html
new file mode 100644
index 0000000..c23372a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-in-blob-denied.html
@@ -0,0 +1,10 @@
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+test(function () {
+    var blobUrl = URL.createObjectURL(new Blob());
+    assert_throws('SecurityError', function () {
+        history.pushState(null, null, blobUrl);
+    });
+}, 'pushState to blob:-URL should fail with SecurityError');
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-at-blob-denied-expected.txt b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-at-blob-denied-expected.txt
new file mode 100644
index 0000000..ad5bff7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-at-blob-denied-expected.txt
@@ -0,0 +1 @@
+PASS: pushState from blob:-URL was blocked.
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-at-blob-denied.html b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-at-blob-denied.html
new file mode 100644
index 0000000..48960d8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-at-blob-denied.html
@@ -0,0 +1,22 @@
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+    testRunner.addOriginAccessWhitelistEntry(location.origin, location.protocol, '', false);
+}
+
+var blobUrl = URL.createObjectURL(new Blob([
+    "<script>" +
+    "try {" +
+    "    history.pushState(null, null, " + JSON.stringify(document.URL) + ");" +
+    "    document.write('FAIL: pushState from blob:-URL succeeded.');" +
+    "} catch(e) {" +
+    "    document.write('PASS: pushState from blob:-URL was blocked.');" +
+    "}" +
+    "if (window.testRunner)" +
+    "    testRunner.notifyDone();" +
+    "<\/script>"
+], {type:"text/html"}));
+
+location.href = blobUrl;
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-at-unique-origin-denied.html b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-at-unique-origin-denied.html
new file mode 100644
index 0000000..c89da592
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-at-unique-origin-denied.html
@@ -0,0 +1,14 @@
+<meta http-equiv="Content-Security-Policy" content="sandbox allow-scripts">
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+test(function () {
+    testRunner.addOriginAccessWhitelistEntry(location.origin, location.protocol, '', false);
+}, 'testRunner.addOriginAccessWhitelistEntry is required for this test');
+
+test(function () {
+    assert_throws('SecurityError', function () {
+        history.pushState(null, null, document.URL);
+    });
+}, 'pushState at unique origin should fail with SecurityError (even with whitelisted origins)');
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-auth-denied.html b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-auth-denied.html
new file mode 100644
index 0000000..a1c46f8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-auth-denied.html
@@ -0,0 +1,19 @@
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+test(function () {
+    testRunner.addOriginAccessWhitelistEntry(location.origin, location.protocol, '', false);
+}, 'testRunner.addOriginAccessWhitelistEntry is required for this test');
+
+test(function () {
+    // http://username@password:localhost:8000/... should be blocked.
+    var originWithAuth = new URL(document.URL);
+    originWithAuth.username += 'username';
+    originWithAuth.password += 'password';
+    originWithAuth = originWithAuth.href;
+
+    assert_throws('SecurityError', function () {
+        history.pushState(null, null, originWithAuth);
+    });
+}, 'pushState that changes credentials should fail with SecurityError (even with whitelisted origins)');
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-denied.html b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-denied.html
new file mode 100644
index 0000000..ad2f707b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-denied.html
@@ -0,0 +1,18 @@
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+test(function () {
+    testRunner.addOriginAccessWhitelistEntry(location.origin, location.protocol, '', false);
+}, 'testRunner.addOriginAccessWhitelistEntry is required for this test');
+
+test(function () {
+    // http://username@password:localhost:8000/... should be blocked.
+    var otherOrigin = new URL(document.URL);
+    otherOrigin.port = otherOrigin.port ? otherOrigin.port ^ 0xFFFF : 1337;
+    otherOrigin = otherOrigin.href;
+
+    assert_throws('SecurityError', function () {
+        history.pushState(null, null, otherOrigin);
+    });
+}, 'pushState to origin with different port should fail with SecurityError (even with whitelisted origins)');
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-in-blob-denied.html b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-in-blob-denied.html
new file mode 100644
index 0000000..db5ae2de
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-in-blob-denied.html
@@ -0,0 +1,15 @@
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+test(function () {
+    testRunner.addOriginAccessWhitelistEntry(location.origin, location.protocol, '', false);
+    testRunner.addOriginAccessWhitelistEntry(location.origin, 'blob', '', false);
+}, 'testRunner.addOriginAccessWhitelistEntry is required for this test');
+
+test(function () {
+    var blobUrl = URL.createObjectURL(new Blob());
+    assert_throws('SecurityError', function () {
+        history.pushState(null, null, blobUrl);
+    });
+}, 'pushState to blob:-URL should fail with SecurityError (even with whitelisted origins)');
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/clients-openwindow.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/clients-openwindow.html
index 9b54a26..b9aaeb4 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/clients-openwindow.html
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/clients-openwindow.html
@@ -46,8 +46,9 @@
                     'openWindow() can not open an invalid url',
                     'openWindow() error is: TypeError',
                     'openWindow() can not open view-source scheme',
+                    'openWindow() error is: TypeError',
                     'openWindow() can not open file scheme',
-                    'openWindow() error is: SecurityError',
+                    'openWindow() error is: TypeError',
                     ];
 
     // LayoutTests on Mac do not open focused windows.
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/clients-openwindow.js b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/clients-openwindow.js
index 7671ba6..0db803c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/clients-openwindow.js
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/clients-openwindow.js
@@ -76,8 +76,9 @@
 
     function testOpenViewSource() {
         synthesizeNotificationClick().then(function(e) {
-            clients.openWindow('view-source://http://test.com').catch(function(c) {
+            clients.openWindow('view-source://http://test.com').catch(function(error) {
                 self.postMessage('openWindow() can not open view-source scheme');
+                self.postMessage('openWindow() error is: ' + error.name);
             }).then(runNextTestOrQuit);
         });
     },
diff --git a/third_party/WebKit/LayoutTests/http/tests/workers/resources/load-worker-in-iframe.html b/third_party/WebKit/LayoutTests/http/tests/workers/resources/load-worker-in-iframe.html
new file mode 100644
index 0000000..8f0d8c74
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/workers/resources/load-worker-in-iframe.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script>
+    // get-host-info.js, loaded below, is considered active mixed
+    // content when this page is loaded over HTTP in an iframe inside an
+    // HTTPS page. Allow active mixed content here so that
+    // get-host-info.js runs.
+    if (window.testRunner) {
+       testRunner.overridePreference("WebKitAllowRunningInsecureContent", true);
+       testRunner.setAllowRunningOfInsecureContent(true);
+    }
+    </script>
+
+    <script src="/resources/get-host-info.js"></script>
+    <script>
+    window.onmessage = function (event) {
+        window.parent.postMessage(event.data, "*");
+    }
+
+    window.onload = function () {
+        var iframe = document.createElement("iframe");
+        iframe.src = get_host_info().HTTPS_ORIGIN + "/workers/resources/load-worker.html";
+        document.body.appendChild(iframe);
+    }
+    </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/workers/resources/load-worker.html b/third_party/WebKit/LayoutTests/http/tests/workers/resources/load-worker.html
new file mode 100644
index 0000000..ecc53e1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/workers/resources/load-worker.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/resources/get-host-info.js"></script>
+    <script>
+        try {
+            var worker = new SharedWorker(get_host_info().HTTPS_ORIGIN + "/workers/resources/worker-util.js", "worker");
+        } catch (e) {
+            window.parent.postMessage({ error: e.toString() }, "*");
+        }
+    </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/workers/shared-worker-secure-context.https.html b/third_party/WebKit/LayoutTests/http/tests/workers/shared-worker-secure-context.https.html
new file mode 100644
index 0000000..d5c9055
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/workers/shared-worker-secure-context.https.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/resources/get-host-info.js"></script>
+</head>
+<body>
+</body>
+<script>
+    if (window.testRunner) {
+       testRunner.setAllowRunningOfInsecureContent(true);
+    }
+
+    window.onload = function() {
+        var test = async_test("Shared workers secure context");
+
+        window.onmessage = test.step_func(function (event) {
+            assert_equals("SecurityError: Failed to construct 'SharedWorker': The SharedWorker named 'worker' was created from a secure context and this context is not secure.", event.data.error);
+            test.done();
+        });
+
+        test.step(function () {
+            var worker = new SharedWorker("resources/worker-util.js", "worker");
+            var iframe = document.createElement("iframe");
+            iframe.src = get_host_info().UNAUTHENTICATED_ORIGIN + "/workers/resources/load-worker-in-iframe.html";
+            document.body.appendChild(iframe);
+        });
+    };
+</script>
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/CONTRIBUTING.md b/third_party/WebKit/LayoutTests/imported/csswg-test/CONTRIBUTING.md
index 8f8b391..6bc5443 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/CONTRIBUTING.md
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/CONTRIBUTING.md
@@ -1,33 +1,33 @@
 Grant of License
 ----------------
 
-By contributing to this repository, you and the company you 
-represent, if the company holds any copyrights in the contribution, 
+By contributing to this repository, you and the company you
+represent, if the company holds any copyrights in the contribution,
 grant to the W3C a perpetual, non-exclusive, royalty-free, world-
-wide right and license under all of your copyrights in this 
-contribution to copy, publish, use, and modify the contribution and 
+wide right and license under all of your copyrights in this
+contribution to copy, publish, use, and modify the contribution and
 to distribute the contribution under a BSD License or one with
-more restrictive terms, as well as a right and license of the same 
-scope to any derivative works prepared by the W3C and based on or 
-incorporating all or part of the contribution. You further agree 
-that any derivative works of this contribution prepared by the W3C 
+more restrictive terms, as well as a right and license of the same
+scope to any derivative works prepared by the W3C and based on or
+incorporating all or part of the contribution. You further agree
+that any derivative works of this contribution prepared by the W3C
 shall be solely owned by the W3C.
 
-You state, to the best of your knowledge, that you, or the company 
+You state, to the best of your knowledge, that you, or the company
 you represent, have all rights necessary to contribute the materials.
 
-W3C will retain attribution of initial authorship to you. The W3C 
+W3C will retain attribution of initial authorship to you. The W3C
 makes no a-priori commitment to support or distribute contributions.
 
 Disclaimer
 ----------
 
 All content from this repository is provided as is, and W3C makes no
-representations or warranties, express or implied, including, but 
-not limited to, warranties of merchantability, fitness for a 
-particular purpose, non-infringement, or title; nor that the 
-contents of this repository are suitable for any purpose. We make no 
-representations, express or implied, that the content of this 
-repository or the use thereof indicates conformance to a 
-specification. All content is provided as-is to help reach 
-interoperability.
\ No newline at end of file
+representations or warranties, express or implied, including, but
+not limited to, warranties of merchantability, fitness for a
+particular purpose, non-infringement, or title; nor that the
+contents of this repository are suitable for any purpose. We make no
+representations, express or implied, that the content of this
+repository or the use thereof indicates conformance to a
+specification. All content is provided as-is to help reach
+interoperability.
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/README.md b/third_party/WebKit/LayoutTests/imported/csswg-test/README.md
index 6f6dbe7..e703d1a 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/README.md
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/README.md
@@ -1,6 +1,6 @@
 W3C CSS Test Suite Repository
 -----------------------------
- 
+
 This repository contains top level directories for all of CSS specs for
 which we currently have tests. Place tests in the appropriate directory based
 on the first rel="help" link in the test. If you are writing tests for a spec
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-001-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-001-expected.html
deleted file mode 100644
index af8d322..0000000
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-001-expected.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!doctype html>
-<html>
-<head>
-	<meta charset="utf-8"> 
-	<title>CSS Reference File</title>
-	<link rel="author" title="Florian Rivoal" href="mailto:florian@rivoal.net">
-	<style>
-	div {
-		font-size: 50px;
-		position: absolute;
-		left: 30px;
-		top: 50px;
-	}
-	div span {
-		color: green;
-		background: green;
-		float: left;
-	}
-	</style>
-</head>
-<body>
-	<p>Test passes if there is a <strong>filled green rectangle</strong> and <strong>no red</strong>.</p>
-	<div><span>a</span></div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-001.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-001.html
deleted file mode 100644
index aaa76e04..0000000
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-001.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<!doctype html>
-<html>
-<head>
-	<meta charset="utf-8">
-	<title>CSS Test: ::first-letter formatting</title>
-	<link rel="author" title="Florian Rivoal" href="mailto:florian@rivoal.net">
-	<link rel="match" href="first-letter-001-ref.html">
-	<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#first-letter-styling">
-	<meta name="flags" content="">
-	<meta name="assert" content="Test checks that a floated ::first-letter follows the usual formating rules for floats.">
-	<style>
-	div {
-		font-size: 50px;
-		position: absolute;
-		left: 30px;
-		top: 50px;
-		background: red;
-	}
-	span {
-		background : white;
-	}
-	div::first-letter {
-		color: green;
-		background: green;
-		float: left;
-	}
-	</style>
-</head>
-<body>
-	<p>Test passes if there is a <strong>filled green rectangle</strong> and <strong>no red</strong>.</p>
-	<div>a<span>&nbsp;</span></div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-002-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-002-expected.html
deleted file mode 100644
index af8d322..0000000
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-002-expected.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!doctype html>
-<html>
-<head>
-	<meta charset="utf-8"> 
-	<title>CSS Reference File</title>
-	<link rel="author" title="Florian Rivoal" href="mailto:florian@rivoal.net">
-	<style>
-	div {
-		font-size: 50px;
-		position: absolute;
-		left: 30px;
-		top: 50px;
-	}
-	div span {
-		color: green;
-		background: green;
-		float: left;
-	}
-	</style>
-</head>
-<body>
-	<p>Test passes if there is a <strong>filled green rectangle</strong> and <strong>no red</strong>.</p>
-	<div><span>a</span></div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-002.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-002.html
deleted file mode 100644
index c8209d0a0..0000000
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-002.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!doctype html>
-<html>
-<head>
-	<meta charset="utf-8"> 
-	<title>CSS Test: ::first-letter formatting</title>
-	<link rel="author" title="Florian Rivoal" href="mailto:florian@rivoal.net">
-	<link rel="match" href="first-letter-001-ref.html">
-	<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#first-letter-styling">
-	<meta name="flags" content="">
-	<meta name="assert" content="Test checks that a floated ::first-letter is formatted identically to a floated non-pseudo element with the same content.">
-	<style>
-	div {
-		font-size: 50px;
-		position: absolute;
-		left: 30px;
-		top: 50px;
-	}
-	#d1 span {
-		color: red;
-		background: red;
-		float: left;
-	}
-	#d2::first-letter {
-		color: green;
-		background: green;
-		float: left;
-	}
-	</style>
-</head>
-<body>
-	<p>Test passes if there is a <strong>filled green rectangle</strong> and <strong>no red</strong>.</p>
-	<div id="d1"><span>a</span></div>
-	<div id="d2">a</div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-003-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-003-expected.html
deleted file mode 100644
index af8d322..0000000
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-003-expected.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!doctype html>
-<html>
-<head>
-	<meta charset="utf-8"> 
-	<title>CSS Reference File</title>
-	<link rel="author" title="Florian Rivoal" href="mailto:florian@rivoal.net">
-	<style>
-	div {
-		font-size: 50px;
-		position: absolute;
-		left: 30px;
-		top: 50px;
-	}
-	div span {
-		color: green;
-		background: green;
-		float: left;
-	}
-	</style>
-</head>
-<body>
-	<p>Test passes if there is a <strong>filled green rectangle</strong> and <strong>no red</strong>.</p>
-	<div><span>a</span></div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-003.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-003.html
deleted file mode 100644
index 731b24f..0000000
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-pseudo-4/first-letter-003.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!doctype html>
-<html>
-<head>
-	<meta charset="utf-8"> 
-	<title>CSS Test: ::first-letter formatting</title>
-	<link rel="author" title="Florian Rivoal" href="mailto:florian@rivoal.net">
-	<link rel="match" href="first-letter-001-ref.html">
-	<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#first-letter-styling">
-	<meta name="flags" content="">
-	<meta name="assert" content="Test checks that a floated ::first-letter is formatted identically to a floated non-pseudo element with the same content.">
-	<style>
-	div {
-		font-size: 50px;
-		position: absolute;
-		left: 30px;
-		top: 50px;
-	}
-	#d1::first-letter {
-		color: red;
-		background: red;
-		float: left;
-	}
-	#d2 span {
-		color: green;
-		background: green;
-		float: left;
-	}
-	</style>
-</head>
-<body>
-	<p>Test passes if there is a <strong>filled green rectangle</strong> and <strong>no red</strong>.</p>
-	<div id="d1">a</div>
-	<div id="d2"><span>a</span></div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-006-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-006-expected.html
index e1a1f57..d7ff373b 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-006-expected.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-006-expected.html
@@ -12,12 +12,12 @@
             top: 70px;
         }
         .left-rect {
-            left: 10px; 
+            left: 10px;
         }
         .right-rect {
             width: 50px;
             height: 100px;
-            left: 70px; 
+            left: 70px;
             background: rgb(0,100,0);
         }
         .blue {
@@ -41,4 +41,4 @@
     <div class="blue left-line"></div>
     <div class="blue right-line"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-006.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-006.html
index 2bf4d5c..99436617b 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-006.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-006.html
@@ -8,7 +8,7 @@
     <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-margin-property"/>
     <link rel="match" href="reference/shape-image-006-ref.html"/>
     <meta name="flags" content="ahem"/>
-    <meta name="assert" content="This test verifies that content wraps around all the image pixels 
+    <meta name="assert" content="This test verifies that content wraps around all the image pixels
                                  + the shape-margin when shape-outside is given a png file."/>
     <style type="text/css">
         body {
@@ -61,4 +61,4 @@
     <div class="blue right-line"></div>
     <div class="failure"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-007-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-007-expected.html
index 4217c0e..1049a10 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-007-expected.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-007-expected.html
@@ -14,7 +14,7 @@
         }
         .left-rect { left: 10px; }
         .right-rect { left: 70px; }
-        
+
         .blue {
             width: 2px;
             height: 100px;
@@ -39,4 +39,4 @@
     <div class="blue left-line"></div>
     <div class="blue right-line"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-007.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-007.html
index 02feda98..bb67d79 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-007.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-007.html
@@ -8,7 +8,7 @@
     <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-margin-property"/>
     <link rel="match" href="reference/shape-image-007-ref.html"/>
     <meta name="flags" content="ahem"/>
-    <meta name="assert" content="This test verifies that content wraps around all the image pixels 
+    <meta name="assert" content="This test verifies that content wraps around all the image pixels
                                  + the shape-margin when shape-outside is given an svg file."/>
     <style type="text/css">
         body {
@@ -61,4 +61,4 @@
     <div class="blue right-line"></div>
     <div class="failure"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-008.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-008.html
index 49695ee..c98fddb 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-008.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-008.html
@@ -8,7 +8,7 @@
     <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-margin-property"/>
     <link rel="match" href="reference/shape-image-008-ref.html"/>
     <meta name="flags" content="ahem"/>
-    <meta name="assert" content="This test verifies that content wraps around all the image pixels 
+    <meta name="assert" content="This test verifies that content wraps around all the image pixels
                                  + the shape-margin as a percentage when shape-outside is given an jpg data uri."/>
     <style type="text/css">
         body {
@@ -66,4 +66,4 @@
     <div class="blue line-right"></div>
     <div class="failure"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-009-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-009-expected.html
index e1a1f57..d7ff373b 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-009-expected.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-009-expected.html
@@ -12,12 +12,12 @@
             top: 70px;
         }
         .left-rect {
-            left: 10px; 
+            left: 10px;
         }
         .right-rect {
             width: 50px;
             height: 100px;
-            left: 70px; 
+            left: 70px;
             background: rgb(0,100,0);
         }
         .blue {
@@ -41,4 +41,4 @@
     <div class="blue left-line"></div>
     <div class="blue right-line"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-010-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-010-expected.html
index e1a1f57..d7ff373b 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-010-expected.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-010-expected.html
@@ -12,12 +12,12 @@
             top: 70px;
         }
         .left-rect {
-            left: 10px; 
+            left: 10px;
         }
         .right-rect {
             width: 50px;
             height: 100px;
-            left: 70px; 
+            left: 70px;
             background: rgb(0,100,0);
         }
         .blue {
@@ -41,4 +41,4 @@
     <div class="blue left-line"></div>
     <div class="blue right-line"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-010.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-010.html
index 7bb41e0..bd06085 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-010.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-010.html
@@ -10,7 +10,7 @@
     <link rel="match" href="reference/shape-image-006-ref.html"/>
     <meta name="flags" content="ahem"/>
     <meta name="assert" content="This test verifies that content wraps around the image pixels extracted from
-                                 a shape-outside png file with shape-image-threshold set + the shape-margin as 
+                                 a shape-outside png file with shape-image-threshold set + the shape-margin as
                                  a percentage."/>
     <style type="text/css">
         body { margin: 0; }
@@ -75,4 +75,4 @@
     <div class="blue right-line"></div>
     <div class="failure"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-011-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-011-expected.html
index 4217c0e..1049a10 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-011-expected.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-011-expected.html
@@ -14,7 +14,7 @@
         }
         .left-rect { left: 10px; }
         .right-rect { left: 70px; }
-        
+
         .blue {
             width: 2px;
             height: 100px;
@@ -39,4 +39,4 @@
     <div class="blue left-line"></div>
     <div class="blue right-line"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-024-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-024-expected.html
index ec6d6af..255d56c 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-024-expected.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-024-expected.html
@@ -14,7 +14,7 @@
         }
         .left-rect { left: 10px; }
         .right-rect { left: 120px; }
-        
+
         .blue {
             width: 2px;
             height: 200px;
@@ -39,4 +39,4 @@
     <div class="blue left-line"></div>
     <div class="blue right-line"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-024.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-024.html
index 61b9221..c646ec6 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-024.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-024.html
@@ -7,7 +7,7 @@
     <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
     <link rel="match" href="reference/shape-image-024-ref.html"/>
     <meta name="flags" content="ahem"/>
-    <meta name="assert" content="This test verifies that content wraps around all the image pixels 
+    <meta name="assert" content="This test verifies that content wraps around all the image pixels
                                  calculated from the size of the img element, which is different
                                  than the size of the image itself."/>
     <style type="text/css">
@@ -63,4 +63,4 @@
     <div class="blue right-line"></div>
     <div class="failure"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-025.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-025.html
index 6cd0211..a2d9d2d 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-025.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-025.html
@@ -32,7 +32,7 @@
             width: 50px;
             height: 50px;
         }
-        .green { 
+        .green {
             left: 10px;
             background-color: rgb(0,100,0);
         }
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-013.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-013.html
index c4119a3..ec1d643 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-013.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-013.html
@@ -10,7 +10,7 @@
         <meta name="flags" content="ahem" />
         <meta name="assert" content="The test verifies that text wraps around a
                                      left float with a shape-outside defined as
-                                     a circle from the margin box and positioned 
+                                     a circle from the margin box and positioned
                                      in px units.">
     </head>
     <style>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-021.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-021.html
index 367891c6..1234145 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-021.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-021.html
@@ -12,7 +12,7 @@
         <meta name="flags" content="ahem" />
         <meta name="assert" content="The test verifies that text wraps around a
                                      left float with a shape-outside defined as
-                                     a circle with a farthest-side radius from the 
+                                     a circle with a farthest-side radius from the
                                      padding box with a shape-margin.">
     </head>
     <style>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-027.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-027.html
index 5ad06709..2141c12 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-027.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-027.html
@@ -11,7 +11,7 @@
         <meta name="flags" content="ahem" />
         <meta name="assert" content="The test verifies that text wraps around a
                                      right float with a shape-outside defined as
-                                     a circle positioned from the margin box with a 
+                                     a circle positioned from the margin box with a
                                      shape-margin.">
     </head>
     <style>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-028.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-028.html
index 9f72da90..0143259 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-028.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-028.html
@@ -12,7 +12,7 @@
         <meta name="flags" content="ahem" />
         <meta name="assert" content="The test verifies that text wraps around a
                                      right float with a shape-outside defined as
-                                     a circle positioned from the border box with a 
+                                     a circle positioned from the border box with a
                                      shape-margin.">
     </head>
     <style>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-029.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-029.html
index 4b698c788..39f156c 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-029.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-029.html
@@ -11,7 +11,7 @@
         <meta name="flags" content="ahem" />
         <meta name="assert" content="The test verifies that text wraps around a
                                      right float with a shape-outside defined as
-                                     a circle positioned center right from the padding 
+                                     a circle positioned center right from the padding
                                      box with a shape-margin.">
     </head>
     <style>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-030-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-030-expected.html
index 5c778b4ac..9fc0ca7 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-030-expected.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-030-expected.html
@@ -51,7 +51,7 @@
         X<br/>
         X
         </div>
-        
+
         <script src="../support/rounded-rectangle.js"></script>
         <script src="../support/subpixel-utils.js"></script>
         <script>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-031-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-031-expected.html
index 5c778b4ac..9fc0ca7 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-031-expected.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-031-expected.html
@@ -51,7 +51,7 @@
         X<br/>
         X
         </div>
-        
+
         <script src="../support/rounded-rectangle.js"></script>
         <script src="../support/subpixel-utils.js"></script>
         <script>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-015.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-015.html
index 74cb222..3502f8b 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-015.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-015.html
@@ -11,7 +11,7 @@
         <meta name="flags" content="ahem" />
         <meta name="assert" content="The test verifies that text wraps around a
                                      left float with a shape-outside defined as an
-                                     ellipse with the radii explicitly set as closest-side 
+                                     ellipse with the radii explicitly set as closest-side
                                      from the padding box.">
     </head>
     <style>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-025.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-025.html
index 98b053a..c7e9a144 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-025.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-025.html
@@ -11,8 +11,8 @@
         <meta name="flags" content="ahem" />
         <meta name="assert" content="The test verifies that text wraps around a
                                      right float with a shape-outside defined as
-                                     a ellipse with the radii in percentage units 
-                                     positioned at center right from the margin box 
+                                     a ellipse with the radii in percentage units
+                                     positioned at center right from the margin box
                                      with a shape-margin.">
     </head>
     <style>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-030-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-030-expected.html
index 530e380..bf30aaec2 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-030-expected.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-030-expected.html
@@ -47,7 +47,7 @@
         X<br/>
         X
         </div>
-        
+
         <script src="../support/rounded-rectangle.js"></script>
         <script src="../support/subpixel-utils.js"></script>
         <script>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-031-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-031-expected.html
index 530e380..bf30aaec2 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-031-expected.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-031-expected.html
@@ -47,7 +47,7 @@
         X<br/>
         X
         </div>
-        
+
         <script src="../support/rounded-rectangle.js"></script>
         <script src="../support/subpixel-utils.js"></script>
         <script>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/polygon/shape-outside-polygon-016.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/polygon/shape-outside-polygon-016.html
index 64768a82..2a09681 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/polygon/shape-outside-polygon-016.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/polygon/shape-outside-polygon-016.html
@@ -8,7 +8,7 @@
         <link rel="match" href="reference/shape-outside-polygon-010-ref.html">
         <meta name="flags" content="ahem" />
         <meta name="assert" content="The test verifies that evenodd behaves the
-                                     same as nonzero for shape-outside and that text 
+                                     same as nonzero for shape-outside and that text
                                      will wraps around the outer edge of a polygon.">
     </head>
     <style>
@@ -57,4 +57,4 @@
     <div id="ref-2" class="ref-shape"></div>
     </div>
     </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-circle-003.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-circle-003.html
index 1f7b90e3..c35d3b4f 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-circle-003.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-circle-003.html
@@ -8,7 +8,7 @@
         <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#funcdef-circle">
         <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property">
         <meta name="assert" content="Valid circle position argument list are in the form of:
-                                     [ percentage|length left|center|right ] 
+                                     [ percentage|length left|center|right ]
                                 or   [ percentage|length left|center|right ] [ percentage|length top|center|bottom  ]
                                 or   [ left|center|right ]
                                 or   [ left|center|right top|center|bottom ]
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-circle-007.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-circle-007.html
index de29fa0..7cd52fe5 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-circle-007.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-circle-007.html
@@ -34,7 +34,7 @@
                 {"name": "circle(closest-side farthest-side)"},
                 {"name": "circle(farthest-side closest-side)"}
             ];
-            generate_tests(ParsingUtils.testInlineStyle, 
+            generate_tests(ParsingUtils.testInlineStyle,
                            ParsingUtils.buildTestCases(invalid_circle_radiii_tests) );
         </script>
     </body>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-circle-011.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-circle-011.html
index 22a8c124..1e89463a 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-circle-011.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-circle-011.html
@@ -19,7 +19,7 @@
         <script type="text/javascript">
             var circle_position_calc_tests = [];
             ParsingUtils.calcTestValues.forEach(function(value) {
-                testCase = ['circle(at '+ value[0] +')', 
+                testCase = ['circle(at '+ value[0] +')',
                             'circle(at '+ value[1] +' 50%)'];
                 if(Object.prototype.toString.call( value[2] ) === '[object Array]' && value[2].length == 2) {
                     testCase.push([ 'circle(at '+ value[2][0] +' 50%)',
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-ellipse-003.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-ellipse-003.html
index f50a508b..c4d2e58 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-ellipse-003.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-ellipse-003.html
@@ -8,7 +8,7 @@
         <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#funcdef-ellipse">
         <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property">
         <meta name="assert" content="Valid ellipse position argument list are in the form of:
-                                     [ percentage|length left|center|right ] 
+                                     [ percentage|length left|center|right ]
                                 or   [ percentage|length left|center|right ] [ percentage|length top|center|bottom  ]
                                 or   [ left|center|right ]
                                 or   [ left|center|right top|center|bottom ]
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-ellipse-010.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-ellipse-010.html
index 0f9dcc4..a0f91ae 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-ellipse-010.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-ellipse-010.html
@@ -20,7 +20,7 @@
             var ellipse_calc_tests = [];
             var defaultPosition = ' at 50% 50%';
             ParsingUtils.calcTestValues.forEach(function(value) {
-                testCase = ['ellipse('+ value[0] +')', 
+                testCase = ['ellipse('+ value[0] +')',
                             'ellipse('+ value[1] + defaultPosition +')'];
                 if(Object.prototype.toString.call( value[2] ) === '[object Array]' && value[2].length == 2) {
                     testCase.push([
@@ -33,7 +33,7 @@
                 ellipse_calc_tests.push(testCase);
             });
             ParsingUtils.calcTestValues.forEach(function(value) {
-                testCase = ['ellipse(farthest-side '+ value[0] +')', 
+                testCase = ['ellipse(farthest-side '+ value[0] +')',
                             'ellipse(farthest-side '+ value[1] + defaultPosition +')'];
                 if(Object.prototype.toString.call( value[2] ) === '[object Array]' && value[2].length == 2) {
                     testCase.push([
@@ -46,7 +46,7 @@
                 ellipse_calc_tests.push(testCase);
             });
             ParsingUtils.calcTestValues.forEach(function(value) {
-                testCase = ['ellipse('+ value[0] +' '+ value[0] +')', 
+                testCase = ['ellipse('+ value[0] +' '+ value[0] +')',
                             'ellipse('+ value[1] +' '+ value[1] + defaultPosition +')'];
                 if(Object.prototype.toString.call( value[2] ) === '[object Array]' && value[2].length == 2) {
                     testCase.push([
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-ellipse-011.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-ellipse-011.html
index a5de44c..60b7dcd 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-ellipse-011.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-ellipse-011.html
@@ -19,7 +19,7 @@
         <script type="text/javascript">
             var ellipse_position_calc_tests = [];
             ParsingUtils.calcTestValues.forEach(function(value) {
-                testCase = ['ellipse(at '+ value[0] +' 50%)', 
+                testCase = ['ellipse(at '+ value[0] +' 50%)',
                             'ellipse(at '+ value[1] +' 50%)'];
                 if(Object.prototype.toString.call( value[2] ) === '[object Array]' && value[2].length == 2) {
                     testCase.push([
@@ -45,7 +45,7 @@
                 ellipse_position_calc_tests.push(testCase);
             });
             ParsingUtils.calcTestValues.forEach(function(value) {
-                testCase = ['ellipse(closest-side farthest-side at '+ value[0] +' '+ value[0] +')', 
+                testCase = ['ellipse(closest-side farthest-side at '+ value[0] +' '+ value[0] +')',
                             'ellipse(closest-side farthest-side at '+ value[1] +' '+ value[1] +')'];
                 if(Object.prototype.toString.call( value[2] ) === '[object Array]' && value[2].length == 2) {
                     testCase.push([
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-inset-004.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-inset-004.html
index 1e767cd..dfe429f 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-inset-004.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-inset-004.html
@@ -7,7 +7,7 @@
         <link rel="reviewer" title="Alan Stearns" href="mailto:stearns@adobe.com"> <!--  2014-03-04  -->
         <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#funcdef-inset">
         <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property">
-        <meta name="assert" content="These tests verify that shape-outside inset() arguments can be numbers that are signed in 
+        <meta name="assert" content="These tests verify that shape-outside inset() arguments can be numbers that are signed in
                                      positive and negative and/or decimal/non-decimal form.">
         <meta name="flags" content="dom">
         <script src="../../../../../resources/testharness.js"></script>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-inset-006.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-inset-006.html
index fcc3093..29a5114 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-inset-006.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/shape-outside/values/shape-outside-inset-006.html
@@ -7,7 +7,7 @@
         <link rel="reviewer" title="Alan Stearns" href="mailto:stearns@adobe.com"> <!--  2014-03-04  -->
         <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#funcdef-inset">
         <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property">
-        <meta name="assert" content="These tests verify that shape-outside inset() radial component can be numbers that are in 
+        <meta name="assert" content="These tests verify that shape-outside inset() radial component can be numbers that are in
                                      signed positive and/or decimal/non-decimal form. Negative values are not allowed">
         <meta name="flags" content="dom">
         <script src="../../../../../resources/testharness.js"></script>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-001-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-001-expected.html
index 2298360..b175d550 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-001-expected.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-001-expected.html
@@ -59,7 +59,7 @@
     <p>
         The test passes if the green shape does not intersect either of the triangles and
         there is one green horizontal bar beneath the triangles. There should be no red.
-    </p>    
+    </p>
     <div id="container">
         <div id="level-1">
            XXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXX XXXXXXXXXXX
@@ -81,4 +81,4 @@
     <div id="left-triangle"></div>
     <div id="right-triangle"></div>
  </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-001.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-001.html
index 3a51609a..1795c58 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-001.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-001.html
@@ -8,7 +8,7 @@
     <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
     <link rel="match" href="reference/shape-outside-001-ref.html"/>
     <meta name="flags" content="ahem"/>
-    <meta name="assert" content="This test verifies that left floats with a shape-outside 
+    <meta name="assert" content="This test verifies that left floats with a shape-outside
      only allow content wrapping on the right side, and right floats only allow wrapping on
      the left."/>
     <!--  This test is derived from Example 1 in this version of the spec:
@@ -74,7 +74,7 @@
     <p>
         The test passes if the green shape does not intersect either of the triangles and
         there is one green horizontal bar beneath the triangles. There should be no red.
-    </p>    
+    </p>
     <div id="test" class="container">
         <div id="test-float-left"></div>
         <div id="test-float-right"></div>
@@ -97,4 +97,4 @@
     <div id="left-triangle"></div>
     <div id="right-triangle"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-002-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-002-expected.html
index 2298360..b175d550 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-002-expected.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-002-expected.html
@@ -59,7 +59,7 @@
     <p>
         The test passes if the green shape does not intersect either of the triangles and
         there is one green horizontal bar beneath the triangles. There should be no red.
-    </p>    
+    </p>
     <div id="container">
         <div id="level-1">
            XXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXX XXXXXXXXXXX
@@ -81,4 +81,4 @@
     <div id="left-triangle"></div>
     <div id="right-triangle"></div>
  </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-002.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-002.html
index 892ae10..b3d79f2 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-002.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-002.html
@@ -8,9 +8,9 @@
     <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
     <link rel="match" href="reference/shape-outside-001-ref.html"/>
     <meta name="flags" content="ahem"/>
-    <meta name="assert" content="This test verifies that left floats with a shape-outside 
+    <meta name="assert" content="This test verifies that left floats with a shape-outside
      only allow content wrapping on the right side, and right floats only allow wrapping on
-     the left and that the left float shape is clipped to the float’s margin box"/>
+     the left and that the left float shape is clipped to the float's margin box"/>
     <!--  This test is derived from Example 2 in this version of the spec:
          http://www.w3.org/TR/2013/WD-css-shapes-1-20131203/  -->
     <style type="text/css">
@@ -74,7 +74,7 @@
     <p>
         The test passes if the green shape does not intersect either of the triangles and
         there is one green horizontal bar beneath the triangles. There should be no red.
-    </p>    
+    </p>
     <div id="test" class="container">
         <div id="test-float-left"></div>
         <div id="test-float-right"></div>
@@ -97,4 +97,4 @@
     <div id="left-triangle"></div>
     <div id="right-triangle"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-003-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-003-expected.html
index 2298360..b175d550 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-003-expected.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-003-expected.html
@@ -59,7 +59,7 @@
     <p>
         The test passes if the green shape does not intersect either of the triangles and
         there is one green horizontal bar beneath the triangles. There should be no red.
-    </p>    
+    </p>
     <div id="container">
         <div id="level-1">
            XXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXX XXXXXXXXXXX
@@ -81,4 +81,4 @@
     <div id="left-triangle"></div>
     <div id="right-triangle"></div>
  </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-003.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-003.html
index c32e02b..f5bd535e 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-003.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-003.html
@@ -8,9 +8,9 @@
     <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
     <link rel="match" href="reference/shape-outside-001-ref.html"/>
     <meta name="flags" content="ahem"/>
-    <meta name="assert" content="This test verifies that left floats with a shape-outside 
+    <meta name="assert" content="This test verifies that left floats with a shape-outside
      only allow content wrapping on the right side, and right floats only allow wrapping on
-     the left and that the right float shape is clipped to the float’s margin box"/>
+     the left and that the right float shape is clipped to the float's margin box"/>
      <!--  This test is derived from Example 2 in this version of the spec:
           http://www.w3.org/TR/2013/WD-css-shapes-1-20131203/  -->
     <style type="text/css">
@@ -74,7 +74,7 @@
     <p>
         The test passes if the green shape does not intersect either of the triangles and
         there is one green horizontal bar beneath the triangles. There should be no red.
-    </p>    
+    </p>
     <div id="test" class="container">
         <div id="test-float-left"></div>
         <div id="test-float-right"></div>
@@ -97,4 +97,4 @@
     <div id="left-triangle"></div>
     <div id="right-triangle"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-004-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-004-expected.html
index 449e76f..0a62f3b 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-004-expected.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-004-expected.html
@@ -21,7 +21,7 @@
             border: 1px solid black;
             z-index: 10;
         }
-        
+
     </style>
 </head>
 <body>
@@ -29,16 +29,16 @@
         The test passes if there are two columns of six green horizontal bars of the same
         size inside the square and two columns of six matching green bars outside and to the
         right of the square. There should be no red.
-    </p>    
+    </p>
     <div id="container">
-          XXXX XXXX XXXX XXXX 
           XXXX XXXX XXXX XXXX
-          XXXX XXXX XXXX XXXX 
+          XXXX XXXX XXXX XXXX
+          XXXX XXXX XXXX XXXX
           XXXX XXXX XXXX XXXX
           XXXX XXXX XXXX XXXX
           XXXX XXXX XXXX XXXX
     </div>
     <div id="square"></div>
-    
+
  </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-004.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-004.html
index 6060c2d8..1b25caa 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-004.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-004.html
@@ -9,7 +9,7 @@
     <link rel="match" href="reference/shape-outside-004-ref.html"/>
     <meta name="flags" content="ahem"/>
     <meta name="assert" content="This test verifies that a shape with no extent allow inline
-                                 content to flow through all of the float’s box."/>
+                                 content to flow through all of the float's box."/>
      <!--  This test is derived from Example 3 in this version of the spec:
           http://www.w3.org/TR/2013/WD-css-shapes-1-20131203/  -->
     <style type="text/css">
@@ -26,7 +26,7 @@
           shape-outside: inset(50% 50% 50% 50%);
           float: left;
           width: 200px;
-          height: 200px; 
+          height: 200px;
         }
         #failure {
             color: red;
@@ -51,26 +51,26 @@
         The test passes if there are two columns of six green horizontal bars of the same
         size inside the square and two columns of six matching green bars outside and to the
         right of the square. There should be no red.
-    </p>    
+    </p>
     <div id="test" class="container">
         <div id="test-float-left"></div>
         XXXX XXXX
         XXXX XXXX
         XXXX XXXX
-        XXXX XXXX 
+        XXXX XXXX
         XXXX XXXX XXXX XXXX
         XXXX XXXX XXXX XXXX
         XXXX XXXX XXXX XXXX
         XXXX XXXX XXXX XXXX
     </div>
     <div id="failure" class="container">
-          XXXX XXXX XXXX XXXX 
           XXXX XXXX XXXX XXXX
-          XXXX XXXX XXXX XXXX 
+          XXXX XXXX XXXX XXXX
+          XXXX XXXX XXXX XXXX
           XXXX XXXX XXXX XXXX
           XXXX XXXX XXXX XXXX
           XXXX XXXX XXXX XXXX
     </div>
     <div id="square"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-005-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-005-expected.html
index 449e76f..0a62f3b 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-005-expected.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-005-expected.html
@@ -21,7 +21,7 @@
             border: 1px solid black;
             z-index: 10;
         }
-        
+
     </style>
 </head>
 <body>
@@ -29,16 +29,16 @@
         The test passes if there are two columns of six green horizontal bars of the same
         size inside the square and two columns of six matching green bars outside and to the
         right of the square. There should be no red.
-    </p>    
+    </p>
     <div id="container">
-          XXXX XXXX XXXX XXXX 
           XXXX XXXX XXXX XXXX
-          XXXX XXXX XXXX XXXX 
+          XXXX XXXX XXXX XXXX
+          XXXX XXXX XXXX XXXX
           XXXX XXXX XXXX XXXX
           XXXX XXXX XXXX XXXX
           XXXX XXXX XXXX XXXX
     </div>
     <div id="square"></div>
-    
+
  </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-005.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-005.html
index df87ee87..1aed470 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-005.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-005.html
@@ -9,7 +9,7 @@
     <link rel="match" href="reference/shape-outside-004-ref.html"/>
     <meta name="flags" content="ahem"/>
     <meta name="assert" content="This test verifies that a shape with no extent allow inline
-                                 content to flow through all of the float’s box."/>
+                                 content to flow through all of the float's box."/>
      <!--  This test is derived from Example 3 in this version of the spec:
           http://www.w3.org/TR/2013/WD-css-shapes-1-20131203/  -->
     <style type="text/css">
@@ -26,7 +26,7 @@
           shape-outside: inset(150% 150% 0% 0%);
           float: left;
           width: 200px;
-          height: 200px; 
+          height: 200px;
         }
         #failure {
             color: red;
@@ -51,26 +51,26 @@
         The test passes if there are two columns of six green horizontal bars of the same
         size inside the square and two columns of six matching green bars outside and to the
         right of the square. There should be no red.
-    </p>    
+    </p>
     <div id="test" class="container">
         <div id="test-float-left"></div>
         XXXX XXXX
         XXXX XXXX
         XXXX XXXX
-        XXXX XXXX 
+        XXXX XXXX
         XXXX XXXX XXXX XXXX
         XXXX XXXX XXXX XXXX
         XXXX XXXX XXXX XXXX
         XXXX XXXX XXXX XXXX
     </div>
     <div id="failure" class="container">
-          XXXX XXXX XXXX XXXX 
           XXXX XXXX XXXX XXXX
-          XXXX XXXX XXXX XXXX 
+          XXXX XXXX XXXX XXXX
+          XXXX XXXX XXXX XXXX
           XXXX XXXX XXXX XXXX
           XXXX XXXX XXXX XXXX
           XXXX XXXX XXXX XXXX
     </div>
     <div id="square"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-006.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-006.html
index 0a79326e..019fb17 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-006.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-006.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
-    <title>CSS Test: shape-outside with open areas on both the left & right of 
+    <title>CSS Test: shape-outside with open areas on both the left & right of
            the float area</title>
     <link rel="author" title="Rebecca Hauck" href="mailto:rhauck@adobe.com"/>
     <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#relation-to-box-model-and-float-behavior"/>
@@ -9,7 +9,7 @@
     <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
     <link rel="match" href="reference/shape-outside-006-ref.html"/>
     <meta name="flags" content="ahem"/>
-    <meta name="assert" content="This test verifies that content wraps only on one side of 
+    <meta name="assert" content="This test verifies that content wraps only on one side of
                                  the float even though there is open area on both the left
                                  and right sides of the float."/>
      <!--  This test is derived from Example 4 in this version of the spec:
@@ -67,7 +67,7 @@
             background-color: lightblue;
             clip-path: polygon(50px 0px, 100px 100px, 0px 100px);
         }
-        
+
     </style>
 </head>
 <body>
@@ -87,4 +87,4 @@
     </div>
     <div id="triangle"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-007.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-007.html
index f89136e..0e0d93e 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-007.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-007.html
@@ -76,7 +76,7 @@
             background-color: lightblue;
             margin-left: 2px;
             clip-path: polygon(0% 50%, 50% 100%, 0 100%);;
-            
+
         }
     </style>
 </head>
@@ -84,7 +84,7 @@
     <p>
         The test passes if one green bar is inside the top rectangle, three green bars
         are in the bottom rectangle, and none intersect the triangle. There should be no red.
-    </p>   
+    </p>
     <div id="test" class="container">
         <div id="test-float-left"></div>
         XXXXXXXXXXXX XXXXXXXXXXXX XXXXXXXXXXX XXXXXXXXXX
@@ -98,4 +98,4 @@
     </div>
     <div id="triangle"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-008-expected.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-008-expected.html
index 50f9aa7..cfa7932 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-008-expected.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-008-expected.html
@@ -12,7 +12,7 @@
           border: 1px solid black;
         }
         #failure-container {
-            
+
         }
         #margin-line {
             position: absolute;
@@ -74,7 +74,7 @@
         The test passes if one green bar is inside the top rectangle, four green bars
         are in the bottom rectangle, and none intersect the triangles. There should be no
         red.
-    </p>   
+    </p>
     <div id="container">
         <div id="bar-1" class="fail"></div>
         <div id="bar-2" class="fail"></div>
@@ -86,4 +86,4 @@
     <div id="triangle-1" class="triangle"></div>
     <div id="triangle-2" class="triangle"></div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-008.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-008.html
index f28b249..b0760817 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-008.html
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-shapes-1/spec-examples/shape-outside-008.html
@@ -8,7 +8,7 @@
     <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
     <link rel="match" href="reference/shape-outside-008-ref.html"/>
     <meta name="flags" content="ahem"/>
-    <meta name="assert" content="This test verifies that inline content only wraps around the      
+    <meta name="assert" content="This test verifies that inline content only wraps around the
                                  shapes, and otherwise overlays the rest of the float margin
                                  boxes when two floats are stacked next to each other."/>
      <!--  This test is derived from Example 5 in this version of the spec:
@@ -96,7 +96,7 @@
           The test passes if one green bar is inside the top rectangle, four green bars
           are in the bottom rectangle, and none intersect the triangles. There should be no
           red.
-      </p>   
+      </p>
       <div id="test" class="container">
           <div class="test-float-left"></div>
           XXXXXXXXXXXXXXXXX
@@ -117,4 +117,4 @@
       <div id="triangle-1" class="triangle"></div>
       <div id="triangle-2" class="triangle"></div>
   </body>
-  </html>
\ No newline at end of file
+  </html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-transitions-2/transitioncancel-001.html b/third_party/WebKit/LayoutTests/imported/csswg-test/css-transitions-2/transitioncancel-001.html
deleted file mode 100644
index f8de3a8..0000000
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-transitions-2/transitioncancel-001.html
+++ /dev/null
@@ -1,64 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <meta charset="utf-8">
-    <title>CSS Transitions Test: display:none causes transitioncancel</title>
-    <link rel="author" title="Chris Rebert" href="http://chrisrebert.com">
-    <link rel="help" href="https://drafts.csswg.org/css-transitions-2/#dom-transitionevent-transitioncancel">
-    <link rel="help" href="https://lists.w3.org/Archives/Public/www-style/2015Apr/0405.html" title="[CSSWG] Minutes Telecon 2015-04-29" data-section-title="AnimationEnd events and display: none">
-    <meta name="flags" content="dom">
-    <meta name="assert" content="Making an element display:none; while it has a transition in progress should fire a transitioncancel event.">
-    <script src="../../../resources/testharness.js"></script>
-    <script src="../../../resources/testharnessreport.js"></script>
-    <style>
-#a {
-    height: 100px;
-    width: 100px;
-    transition: background-color 2s;
-}
-.red {
-    background-color: red;
-}
-.blue {
-    background-color: blue;
-}
-.hidden {
-    display: none !important;
-}
-    </style>
-    <script>
-async_test(function (t) {
-    window.addEventListener('load', function () {
-        var div = document.getElementById('a');
-        var canceled = false;
-        var after = false;
-        div.addEventListener('transitioncancel', function () {
-            canceled = true;
-            t.step(function () {
-                assert_true(true, "transitioncancel event did fire");
-            });
-        }, false);
-
-        div.className = 'blue';// initiate transition
-        window.setTimeout(function () {
-            t.step(function () {
-                assert_false(canceled, "transitioncancel did not fire before hiding callback ran");
-                assert_false(after, "hiding callback ran before the end of the test");
-            });
-            div.className += ' hidden';// force display:none during the transition
-        }, 1000);// halfway into the transition
-        window.setTimeout(function () {
-            after = true;
-            t.step(function () {
-                assert_true(canceled, "transitioncancel event did fire");
-                t.done();
-            });
-        }, 2100);// after the transition would have ended
-    }, false);
-}, "transitioncancel should be fired if the element is made display:none during the transition");
-    </script>
-</head>
-<body>
-    <div id="a" class="red"></div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/support/adobe-fonts/README.md b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/support/adobe-fonts/README.md
index 686cb0c..50f82b61 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/support/adobe-fonts/README.md
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/support/adobe-fonts/README.md
@@ -3,7 +3,7 @@
 
 Overview
 ----
-CSS Orientation Test are special-purpose OpenType fonts. This open source project provides all of the source files 
+CSS Orientation Test are special-purpose OpenType fonts. This open source project provides all of the source files
 that were used to build these OpenType fonts by using the AFDKO *makeotf* tool.
 
 Getting Involved
@@ -15,7 +15,7 @@
 
 Pre-built font binaries
 ----
-The installable font resources (font binaries) are not part of the source files. 
+The installable font resources (font binaries) are not part of the source files.
 They are available at  https://github.com/adobe-fonts/css-orientation-test/
 The latest version of the font binaries is 1.005 (October 2015).
 
@@ -23,17 +23,17 @@
 Requirements
 ----
 
-For building binary font files from source, installation of the 
-[Adobe Font Development Kit for OpenType](http://www.adobe.com/devnet/opentype/afdko.html) (AFDKO) 
+For building binary font files from source, installation of the
+[Adobe Font Development Kit for OpenType](http://www.adobe.com/devnet/opentype/afdko.html) (AFDKO)
 is necessary. The AFDKO tools are widely used for font development today, and are part of most font editor applications.
 
 Building the fonts
 ----
 
-The key to building OpenType fonts is *makeotf*, which is part of AFDKO. Information and usage instructions can be found 
+The key to building OpenType fonts is *makeotf*, which is part of AFDKO. Information and usage instructions can be found
 by executing *makeotf -h*.
 
-In this repository, all necessary files are in place for building the OpenType fonts. For example, build a binary OTF font 
+In this repository, all necessary files are in place for building the OpenType fonts. For example, build a binary OTF font
 for the full-width version like this, which also includes a post-process for inserting a "stub" 'DSIG' table:
 
     % makeotf -f cidfont.ps -r -ch UnicodeAll-UTF32-H
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/text-orientation-014-expected.xht b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/text-orientation-014-expected.xht
index b1e5056..8e96cc6 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/text-orientation-014-expected.xht
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/text-orientation-014-expected.xht
@@ -5,7 +5,7 @@
 		<title>CSS Reftest Reference</title>
 		<!--  reftest for text-orientation-014.xht  -->
 		<link rel="author" title="Taka Oshiyama" href="mailto:takaoshiyama@gmail.com" />
-		<meta http-equiv="content-language" content="en" />		
+		<meta http-equiv="content-language" content="en" />
 		<style type="text/css">
 				.view_ahem
 				{
@@ -14,7 +14,7 @@
 					color: blue;
 					font: 20px/1 "Ahem";
 					height: 3em;
-					margin: 10px;        
+					margin: 10px;
 					width: 3em;
 					white-space: pre;
 				}
@@ -22,7 +22,7 @@
 				{
 					writing-mode: horizontal-tb;
 				}
-				.view 
+				.view
 				{
 					border: 1px solid gray;
 					font-size: 1.5em;
@@ -31,7 +31,7 @@
 					width: 3em;
 					writing-mode: vertical-rl;
 				}
-				.control 
+				.control
 				{
 					text-combine-upright: none;
 				}
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-lr-002-expected.xht b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-lr-002-expected.xht
index 1112f776a..28c2805 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-lr-002-expected.xht
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-lr-002-expected.xht
@@ -21,15 +21,15 @@
     <p>The upper block is identical to the lower block including each character positions.</p>
 <div>adhjns
   i  t
-be ko 
+be ko
 c  lqu
  f m v
  g  r</div>
 <div>adhjns
   i  t
-be ko 
+be ko
 c  lqu
  f m v
  g  r</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-lr-002.xht b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-lr-002.xht
index 90489cb..8086296 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-lr-002.xht
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-lr-002.xht
@@ -20,7 +20,7 @@
             white-space: pre;
             width: 6em;
         }
-        
+
         #test
         {
             writing-mode: vertical-lr;
@@ -37,7 +37,7 @@
 st uv</div>
 <div id="control">adhjns
   i  t
-be ko 
+be ko
 c  lqu
  f m v
  g  r</div>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-001-expected.xht b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-001-expected.xht
index 215abd5..19d9dc6 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-001-expected.xht
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-001-expected.xht
@@ -21,15 +21,15 @@
     <p>The upper block is identical to the lower block including each character positions.</p>
 <div>tomiea
   n  b
-uq jf 
+uq jf
 v  kgc
  r l d
  s  h</div>
 <div>tomiea
   n  b
-uq jf 
+uq jf
 v  kgc
  r l d
  s  h</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-001.xht b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-001.xht
index 8fc5b79..0a7839c 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-001.xht
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-001.xht
@@ -20,7 +20,7 @@
             white-space: pre;
             width: 6em;
         }
-        
+
         #test
         {
             writing-mode: vertical-rl;
@@ -29,7 +29,7 @@
 </head>
 <body>
     <p>The upper block is identical to the lower block including each character positions.</p>
-    <div id="test">ab cd 
+    <div id="test">ab cd
 e fg h
 i jkl
 mn
@@ -37,7 +37,7 @@
 t uv</div>
 <div id="control">tomiea
   n  b
-uq jf 
+uq jf
 v  kgc
  r l d
  s  h</div>
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-002.xht b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-002.xht
index c2d4a9d1..f2d3ab0 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-002.xht
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-002.xht
@@ -4,7 +4,7 @@
 <head>
     <title>CSS Test: writing-mode: vertical-rl - basic inline case</title>
     <link rel="author" title="Yoshifumi Kawai" href="mailto:kawai@est.co.jp" />
-    <link rel="reviewer" title="Elika J. Etemad" href="http://fantasai.inkedblade.net/contact"/> 
+    <link rel="reviewer" title="Elika J. Etemad" href="http://fantasai.inkedblade.net/contact"/>
     <link rel="help" title="CSS3 Writing modes: 3.1. Block Flow Direction: the 'writing-mode' property" href="http://www.w3.org/TR/css-writing-modes-3/#propdef-writing-mode" />
     <link rel="match" href="reftest/writing-mode-vertical-rl-002-ref.xht"/>
     <meta name="flags" content="ahem" />
@@ -19,7 +19,7 @@
             margin: 10px;
             width: 6em;
         }
-        
+
         #test
         {
             writing-mode: vertical-rl;
@@ -28,7 +28,7 @@
 </head>
 <body>
     <p>The upper block is identical to the lower block including each character positions.</p>
-    <div id="test">ab cd 
+    <div id="test">ab cd
 e fg h
 i jkl
 mn o q
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-003-expected.htm b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-003-expected.htm
index 9cb9eeb..966c756 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-003-expected.htm
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-003-expected.htm
@@ -27,7 +27,7 @@
     <p>Upper three blocks are identical to the lower three blocks including each character positions.</p>
 
     <div>
-        <p>ab cd 
+        <p>ab cd
 e fg h
 i jkl
 mn
@@ -39,7 +39,7 @@
  fj qu
 b  n
 aeimot</p>
-        <p>ab cd 
+        <p>ab cd
 e fg h
 i jkl
 mn
@@ -48,7 +48,7 @@
     </div>
 
     <div>
-        <p>ab cd 
+        <p>ab cd
 e fg h
 i jkl
 mn
@@ -60,7 +60,7 @@
  fj qu
 b  n
 aeimot</p>
-        <p>ab cd 
+        <p>ab cd
 e fg h
 i jkl
 mn
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-003.htm b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-003.htm
index f2d1190..af0cc15 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-003.htm
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-003.htm
@@ -38,19 +38,19 @@
     <p>Upper three blocks are identical to the lower three blocks including each character positions.</p>
 
     <div>
-        <p>ab cd 
+        <p>ab cd
 e fg h
 i jkl
 mn
 o q rs
 t uv</p>
-        <p id="test">ab cd 
+        <p id="test">ab cd
 e fg h
 i jkl
 mn
 o q rs
 t uv</p>
-        <p>ab cd 
+        <p>ab cd
 e fg h
 i jkl
 mn
@@ -59,7 +59,7 @@
     </div>
 
     <div>
-        <p>ab cd 
+        <p>ab cd
 e fg h
 i jkl
 mn
@@ -71,7 +71,7 @@
  fj qu
 b  n
 aeimot</p>
-        <p>ab cd 
+        <p>ab cd
 e fg h
 i jkl
 mn
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-case.xhtml b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-case-xhtml.xhtml
similarity index 100%
rename from third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-case.xhtml
rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-case-xhtml.xhtml
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-id.xhtml b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-id-xhtml.xhtml
similarity index 100%
rename from third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-id.xhtml
rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-id-xhtml.xhtml
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-namespace-xhtml-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-namespace-xhtml-expected.txt
new file mode 100644
index 0000000..e42e5a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-namespace-xhtml-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL getElementsByName and foreign namespaces assert_equals: expected 1 but got 2
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-namespace.xhtml b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-namespace-xhtml.xhtml
similarity index 100%
rename from third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-namespace.xhtml
rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-namespace-xhtml.xhtml
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-newelements.xhtml b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-newelements-xhtml.xhtml
similarity index 100%
rename from third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-newelements.xhtml
rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-newelements-xhtml.xhtml
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-null-undef.xhtml b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-null-undef-xhtml.xhtml
similarity index 100%
rename from third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-null-undef.xhtml
rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-null-undef-xhtml.xhtml
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-param.xhtml b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-param-xhtml.xhtml
similarity index 100%
rename from third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-param.xhtml
rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-param-xhtml.xhtml
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/obsolete/requirements-for-implementations/other-elements-attributes-and-apis/document-color-02.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/obsolete/requirements-for-implementations/other-elements-attributes-and-apis/document-color-02.html
index 8f605d4..c657227f5 100644
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/obsolete/requirements-for-implementations/other-elements-attributes-and-apis/document-color-02.html
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/obsolete/requirements-for-implementations/other-elements-attributes-and-apis/document-color-02.html
@@ -15,6 +15,12 @@
   assert_equals(document.alinkColor, document.body.aLink);
 })
 test(function() {
+  document.fgColor = null;
+  assert_equals(document.fgColor, "");
+  assert_equals(document.body.text, "");
+  assert_equals(document.body.getAttribute("text"), "");
+})
+test(function() {
   document.fgColor = "blue";
   assert_equals(document.fgColor, "blue");
   assert_equals(document.body.text, "blue");
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/obsolete/requirements-for-implementations/other-elements-attributes-and-apis/document-color-03.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/obsolete/requirements-for-implementations/other-elements-attributes-and-apis/document-color-03.html
index 23d19d9..7e727e0 100644
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/obsolete/requirements-for-implementations/other-elements-attributes-and-apis/document-color-03.html
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/obsolete/requirements-for-implementations/other-elements-attributes-and-apis/document-color-03.html
@@ -15,6 +15,12 @@
   assert_equals(document.alinkColor, document.body.aLink);
 })
 test(function() {
+  document.body.text = null;
+  assert_equals(document.fgColor, "");
+  assert_equals(document.body.text, "");
+  assert_equals(document.body.getAttribute("text"), "");
+})
+test(function() {
   document.body.text = "blue";
   assert_equals(document.fgColor, "blue");
   assert_equals(document.body.text, "blue");
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/forms/the-input-element/maxlength-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/forms/the-input-element/maxlength-expected.txt
new file mode 100644
index 0000000..a7faa6c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/forms/the-input-element/maxlength-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+FAIL Unset maxlength is -1 assert_equals: expected -1 but got 524288
+FAIL Negative maxlength is always -1 assert_equals: expected -1 but got 524288
+FAIL Non-numeric maxlength is -1 assert_equals: expected -1 but got 524288
+PASS Assigning negative integer throws IndexSizeError 
+PASS Assigning non-numeric to maxlength sets maxlength to 0 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/forms/the-input-element/maxlength.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/forms/the-input-element/maxlength.html
new file mode 100644
index 0000000..75fc982
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/forms/the-input-element/maxlength.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>input max length</title>
+    <link rel="author" title="Sam Gibson" href="mailto:sam@ifdown.net">
+    <link rel=help href="https://html.spec.whatwg.org/multipage/forms.html#the-maxlength-and-minlength-attributes">
+    <script src="../../../../../../resources/testharness.js"></script>
+    <script src="../../../../../../resources/testharnessreport.js"></script>
+  </head>
+
+  <body>
+    <h1>Text input element</h1>
+
+    <div style="display: none">
+      <input id="none" />
+      <input id="negative" type="-5" />
+      <input id="non-numeric" type="not-a-number" />
+      <input id="assign-negative" />
+      <input id="assign-non-numeric" />
+    </div>
+
+    <div id="log"></div>
+
+    <script type="text/javascript">
+      test(
+        function() {
+          assert_equals(document.getElementById("none").maxLength, -1);
+        }, "Unset maxlength is -1");
+
+      test(
+        function() {
+          assert_equals(document.getElementById("negative").maxLength, -1);
+        }, "Negative maxlength is always -1");
+
+      test(
+        function() {
+          assert_equals(document.getElementById("non-numeric").maxLength, -1);
+        }, "Non-numeric maxlength is -1");
+
+      test(
+          function() {
+            assert_throws("INDEX_SIZE_ERR", function() {
+              document.getElementById("assign-negative").maxLength = -5;
+            });
+          }, "Assigning negative integer throws IndexSizeError");
+
+      test(
+          function() {
+            document.getElementById("assign-non-numeric").maxLength = "not-a-number";
+            assert_equals(document.getElementById("assign-non-numeric").maxLength, 0);
+          }, "Assigning non-numeric to maxlength sets maxlength to 0");
+    </script>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/scripting-1/the-script-element/script-for-event.xhtml b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/scripting-1/the-script-element/script-for-event-xhtml.xhtml
similarity index 100%
rename from third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/scripting-1/the-script-element/script-for-event.xhtml
rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/scripting-1/the-script-element/script-for-event-xhtml.xhtml
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/scripting-1/the-script-element/script-text.xhtml b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/scripting-1/the-script-element/script-text-xhtml.xhtml
similarity index 100%
rename from third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/scripting-1/the-script-element/script-text.xhtml
rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/scripting-1/the-script-element/script-text-xhtml.xhtml
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/resources/idlharness.js b/third_party/WebKit/LayoutTests/imported/web-platform-tests/resources/idlharness.js
index 9f324e0..02304ca 100644
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/resources/idlharness.js
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/resources/idlharness.js
@@ -772,6 +772,30 @@
         }.bind(this), this.name + " interface object length");
     }
 
+    if (!this.is_callback() || this.has_constants()) {
+        test(function() {
+            // This function tests WebIDL as of 2015-11-17.
+            // https://heycam.github.io/webidl/#interface-object
+
+            assert_own_property(self, this.name,
+                                "self does not have own property " + format_value(this.name));
+
+            // "All interface objects must have a property named “name” with
+            // attributes { [[Writable]]: false, [[Enumerable]]: false,
+            // [[Configurable]]: true } whose value is the identifier of the
+            // corresponding interface."
+
+            assert_own_property(self[this.name], "name");
+            var desc = Object.getOwnPropertyDescriptor(self[this.name], "name");
+            assert_false("get" in desc, this.name + ".name has getter");
+            assert_false("set" in desc, this.name + ".name has setter");
+            assert_false(desc.writable, this.name + ".name is writable");
+            assert_false(desc.enumerable, this.name + ".name is enumerable");
+            assert_true(desc.configurable, this.name + ".name is not configurable");
+            assert_equals(self[this.name].name, this.name, "wrong value for " + this.name + ".name");
+        }.bind(this), this.name + " interface object name");
+    }
+
     // TODO: Test named constructors if I find any interfaces that have them.
 
     test(function()
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-big-array-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-big-array-expected.txt
index d497160..7b9c20d 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-big-array-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-big-array-expected.txt
@@ -216,5 +216,5 @@
     [64000000 … 64160002]
         [64000000 … 64159999]
         [64160000 … 64160002]
-    __proto__: Uint8Array
+    __proto__: Object
 
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-dir-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-dir-expected.txt
index 78bec65..b2cbc68 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-dir-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-dir-expected.txt
@@ -18,11 +18,11 @@
 console-dir.html:5 NodeList[1]
     0: html
     length: 1
-    __proto__: NodeList
+    __proto__: Object
 console-dir.html:6 XPathResult
     invalidIteratorState: false
     resultType: 4
-    __proto__: XPathResult
+    __proto__: Object
 console-dir.html:16 Object
     "": ""
     "  ": "  "
@@ -42,7 +42,7 @@
     <function scope>
         Global: Window
 console-dir.html:23 outer.inner
-    __proto__: outer.inner
+    __proto__: Object
 console-dir.html:26 Object
     No Properties
 console-dir.html:27 Object
@@ -62,5 +62,5 @@
     [100000000 … 199999999]
     [200000000 … 299999999]
     [300000000 … 399999999]
-    __proto__: Uint8Array
+    __proto__: Object
 
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-format-array-prototype-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-format-array-prototype-expected.txt
index d153dd65..e3a5df0 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-format-array-prototype-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-format-array-prototype-expected.txt
@@ -8,6 +8,7 @@
 CONSOLE MESSAGE: line 9: ,,,4,,,,,,,,,,,
 CONSOLE MESSAGE: line 9: 0,1,2,3,4,5,6,7,8,9
 CONSOLE MESSAGE: line 9: ,1,2,3,4,,6,7,8,9,
+CONSOLE MESSAGE: line 9: [object Object]
 Tests that console logging dumps array values defined on Array.prototype[].
 
 a0
@@ -40,4 +41,7 @@
 a9
 [undefined × 1, 1, 2, 3, 4, undefined × 1, 6, 7, 8, 9, undefined × 1]
 console-format-array-prototype.html:4 [1: 1, 2: 2, 3: 3, 4: 4, 6: 6, 7: 7, 8: 8, 9: 9, foo: "bar"]
+a10
+Array {}
+console-format-array-prototype.html:4 Array {}
 
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-format-array-prototype.html b/third_party/WebKit/LayoutTests/inspector/console/console-format-array-prototype.html
index 0887c63..443c726e 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-format-array-prototype.html
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-format-array-prototype.html
@@ -29,13 +29,14 @@
 }
 a9.length = 11;
 a9.foo = "bar";
+a10 = Object.create([1,2]);
 //# sourceURL=console-format-array-prototype.html
 </script>
 
 <script>
 function test()
 {
-    loopOverGlobals(0, 10);
+    loopOverGlobals(0, 11);
 
     function loopOverGlobals(current, total)
     {
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-format-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-format-expected.txt
index ee67357..2d2bd42e 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-format-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-format-expected.txt
@@ -432,7 +432,7 @@
     [200 … 299]
     [300 … 399]
     foo: "bar"
-    __proto__: Uint8Array
+    __proto__: Object
 console-format.html:8 [Uint8Array[400]]
     0: Uint8Array[400]
     length: 1
@@ -444,13 +444,13 @@
     [200 … 299]
     [300 … 399]
     foo: "bar"
-    __proto__: Uint8Array
+    __proto__: Object
 console-format.html:7 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…]
     [0 … 99999999]
     [100000000 … 199999999]
     [200000000 … 299999999]
     [300000000 … 399999999]
-    __proto__: Uint8Array
+    __proto__: Object
 console-format.html:8 [Uint8Array[400000000]]
     0: Uint8Array[400000000]
     length: 1
@@ -461,5 +461,5 @@
     [100000000 … 199999999]
     [200000000 … 299999999]
     [300000000 … 399999999]
-    __proto__: Uint8Array
+    __proto__: Object
 
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-2/media-emulation-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/styles-2/media-emulation-expected.txt
index c99ece23d..3129e9e6 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/styles-2/media-emulation-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-2/media-emulation-expected.txt
@@ -29,11 +29,6 @@
 div { (user agent stylesheet)
     display: block;
 
-[expanded] 
-* { (user agent stylesheet)
-    -webkit-column-width: auto;
-    -webkit-column-count: auto;
-
 tty media emulated:
 [expanded] 
 element.style { ()
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/stylesheet-source-url-comment-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/stylesheet-source-url-comment-expected.txt
index 1d9df9f..41fe5f0 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/stylesheet-source-url-comment-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/stylesheet-source-url-comment-expected.txt
@@ -9,3 +9,9 @@
 Running: testNonRelativeURL
 body { color: red; }
 
+Running: testMultiple
+
+/*# sourceURL=1.css */
+body { color: red; }
+/*# sourceURL=2.css*/
+
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/stylesheet-source-url-comment.html b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/stylesheet-source-url-comment.html
index c27ce9ec1..d094c48 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/stylesheet-source-url-comment.html
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/stylesheet-source-url-comment.html
@@ -24,6 +24,13 @@
     document.head.appendChild(styleElement);
 }
 
+function addInlineStyleSheetMultiple()
+{
+    var styleElement = document.createElement("style");
+    styleElement.textContent = "\n/*# sourceURL=1.css */\nbody { color: red; }\n/*# sourceURL=2.css*/\n/*# sourceURL=css/addedInlineStylesheetMultiple.css */";
+    document.head.appendChild(styleElement);
+}
+
 function test()
 {
     function forEachHeaderMatchingURL(url, handler)
@@ -81,6 +88,19 @@
                 forEachHeaderMatchingURL("nonRelativeInlineStyleSheet.css", checkHeaderHasSourceURL);
                 next();
             }
+        },
+
+        function testMultiple(next)
+        {
+            InspectorTest.showScriptSource("css/addedInlineStylesheetMultiple.css", didShowSource);
+            InspectorTest.evaluateInPage("setTimeout(addInlineStyleSheetMultiple, 0)");
+
+            function didShowSource(sourceFrame)
+            {
+                InspectorTest.addResult(sourceFrame.textEditor.text());
+                forEachHeaderMatchingURL("addInlineStyleSheetMultiple.css", checkHeaderHasSourceURL);
+                next();
+            }
         }
     ]);
 };
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/sass-test.js b/third_party/WebKit/LayoutTests/inspector/sass/sass-test.js
new file mode 100644
index 0000000..47a654fa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sass/sass-test.js
@@ -0,0 +1,90 @@
+var initialize_SassTest = function() {
+
+InspectorTest.preloadModule("sass");
+
+InspectorTest.dumpAST = function(ast)
+{
+    var lines = [String.sprintf("=== AST === %s", ast.document.url)];
+    for (var i = 0; i < ast.rules.length; ++i) {
+        var rule = ast.rules[i];
+        lines.push(String.sprintf("rule %d: \"%s\"", i, rule.selector));
+        var ruleLines = dumpRule(rule);
+        lines = lines.concat(indent(ruleLines));
+    }
+    lines.push("======");
+    InspectorTest.addResult(lines.join("\n"));
+    return ast;
+
+    function dumpRule(rule)
+    {
+        var lines = [];
+        for (var i = 0; i < rule.properties.length; ++i) {
+            var property = rule.properties[i];
+            lines.push("property " + i);
+            var propertyLines = dumpProperty(property);
+            lines = lines.concat(indent(propertyLines));
+        }
+        return lines;
+    }
+
+    function dumpProperty(property)
+    {
+        var lines = [];
+        lines.push(String.sprintf("name: \"%s\"", property.name.text));
+        lines = lines.concat(indent(dumpTextNode(property.name)));
+        lines.push(String.sprintf("value: \"%s\"", property.value.text));
+        lines = lines.concat(indent(dumpTextNode(property.value)));
+        lines.push(String.sprintf("range: %s", property.range.toString()));
+        lines.push(String.sprintf("disabled: %s", property.disabled));
+        return lines;
+    }
+
+    function dumpTextNode(textNode)
+    {
+        return [String.sprintf("range: %s", textNode.range.toString())];
+    }
+
+    function indent(lines)
+    {
+        return lines.map(line => "    " + line);
+    }
+}
+
+InspectorTest.validateASTRanges = function(ast)
+{
+    var invalidNodes = [];
+    for (var rule of ast.rules) {
+        for (var property of rule.properties) {
+            validate(property.name);
+            validate(property.value);
+        }
+    }
+    if (invalidNodes.length) {
+        InspectorTest.addResult("Bad ranges: " + invalidNodes.length);
+        for (var node of invalidNodes)
+            InspectorTest.addResult(String.sprintf("  - range: %s text: %s", node.range.toString(), node.text));
+    } else {
+        InspectorTest.addResult("Ranges OK.");
+    }
+    return ast;
+
+    function validate(textNode)
+    {
+        if (textNode.range.extract(textNode.document.text) !== textNode.text)
+            invalidNodes.push(textNode);
+    }
+}
+
+InspectorTest.parseSCSS = function(url, text)
+{
+    return self.runtime.instancePromise(WebInspector.TokenizerFactory)
+        .then(onTokenizer);
+
+    function onTokenizer(tokenizer)
+    {
+        return WebInspector.SASSSupport.parseSCSS(url, text, tokenizer);
+    }
+}
+
+}
+
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-1-expected.txt b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-1-expected.txt
new file mode 100644
index 0000000..bd9524e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-1-expected.txt
@@ -0,0 +1,97 @@
+Verifies SCSS AST in case of simple nesting and CSS properties.
+
+div {
+    /* display: flex; */
+    color: $my-color;
+    background-color: blue;
+    /* position: absolute; */
+
+    .className {
+        padding: 10px 0 0 10px;
+        /* font-family: "Times New Roman"; */
+        background-image: url(assets/no-image-set.png);
+
+        #test::before {
+            margin: 10px 10px;
+            content: "test me";
+            /* border: 1px solid black; */
+        }
+    }
+}
+=== AST === 
+rule 0: "variables"
+rule 1: "properties"
+    property 0
+        name: "display"
+            range: {"startLine":1,"startColumn":7,"endLine":1,"endColumn":14}
+        value: " flex"
+            range: {"startLine":1,"startColumn":15,"endLine":1,"endColumn":20}
+        range: {"startLine":1,"startColumn":4,"endLine":1,"endColumn":24}
+        disabled: true
+    property 1
+        name: "color"
+            range: {"startLine":2,"startColumn":4,"endLine":2,"endColumn":9}
+        value: " $my-color"
+            range: {"startLine":2,"startColumn":10,"endLine":2,"endColumn":20}
+        range: {"startLine":2,"startColumn":4,"endLine":2,"endColumn":21}
+        disabled: false
+    property 2
+        name: "background-color"
+            range: {"startLine":3,"startColumn":4,"endLine":3,"endColumn":20}
+        value: " blue"
+            range: {"startLine":3,"startColumn":21,"endLine":3,"endColumn":26}
+        range: {"startLine":3,"startColumn":4,"endLine":3,"endColumn":27}
+        disabled: false
+    property 3
+        name: "position"
+            range: {"startLine":4,"startColumn":7,"endLine":4,"endColumn":15}
+        value: " absolute"
+            range: {"startLine":4,"startColumn":16,"endLine":4,"endColumn":25}
+        range: {"startLine":4,"startColumn":4,"endLine":4,"endColumn":29}
+        disabled: true
+    property 4
+        name: "padding"
+            range: {"startLine":7,"startColumn":8,"endLine":7,"endColumn":15}
+        value: " 10px 0 0 10px"
+            range: {"startLine":7,"startColumn":16,"endLine":7,"endColumn":30}
+        range: {"startLine":7,"startColumn":8,"endLine":7,"endColumn":31}
+        disabled: false
+    property 5
+        name: "font-family"
+            range: {"startLine":8,"startColumn":11,"endLine":8,"endColumn":22}
+        value: " "Times New Roman""
+            range: {"startLine":8,"startColumn":23,"endLine":8,"endColumn":41}
+        range: {"startLine":8,"startColumn":8,"endLine":8,"endColumn":45}
+        disabled: true
+    property 6
+        name: "background-image"
+            range: {"startLine":9,"startColumn":8,"endLine":9,"endColumn":24}
+        value: " url(assets/no-image-set.png)"
+            range: {"startLine":9,"startColumn":25,"endLine":9,"endColumn":54}
+        range: {"startLine":9,"startColumn":8,"endLine":9,"endColumn":55}
+        disabled: false
+    property 7
+        name: "margin"
+            range: {"startLine":12,"startColumn":12,"endLine":12,"endColumn":18}
+        value: " 10px 10px"
+            range: {"startLine":12,"startColumn":19,"endLine":12,"endColumn":29}
+        range: {"startLine":12,"startColumn":12,"endLine":12,"endColumn":30}
+        disabled: false
+    property 8
+        name: "content"
+            range: {"startLine":13,"startColumn":12,"endLine":13,"endColumn":19}
+        value: " "test me""
+            range: {"startLine":13,"startColumn":20,"endLine":13,"endColumn":30}
+        range: {"startLine":13,"startColumn":12,"endLine":13,"endColumn":31}
+        disabled: false
+    property 9
+        name: "border"
+            range: {"startLine":14,"startColumn":15,"endLine":14,"endColumn":21}
+        value: " 1px solid black"
+            range: {"startLine":14,"startColumn":22,"endLine":14,"endColumn":38}
+        range: {"startLine":14,"startColumn":12,"endLine":14,"endColumn":42}
+        disabled: true
+rule 2: "mixins"
+======
+Ranges OK.
+
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-1.html b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-1.html
new file mode 100644
index 0000000..c918bae
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-1.html
@@ -0,0 +1,60 @@
+<html>
+<head>
+<script src="../../http/tests/inspector/inspector-test.js"></script>
+<script src="../../http/tests/inspector/elements-test.js"></script>
+<script src="./sass-test.js"></script>
+<style>
+pre {
+    font-family: monospace;
+}
+</style>
+<script>
+
+function test()
+{
+    InspectorTest.evaluateInPage("getSASS()", onSASS);
+
+    function onSASS(result)
+    {
+        InspectorTest.parseSCSS("", result.value)
+            .then(InspectorTest.dumpAST)
+            .then(InspectorTest.validateASTRanges)
+            .catch(console.error.bind(console))
+            .then(InspectorTest.completeTest);
+    }
+}
+
+function getSASS()
+{
+    return document.querySelector(".snippet").textContent;
+}
+
+</script>
+</head>
+
+<body onload="runTest()">
+<p>
+Verifies SCSS AST in case of simple nesting and CSS properties.
+</p>
+<pre class="snippet">
+div {
+    /* display: flex; */
+    color: $my-color;
+    background-color: blue;
+    /* position: absolute; */
+
+    .className {
+        padding: 10px 0 0 10px;
+        /* font-family: "Times New Roman"; */
+        background-image: url(assets/no-image-set.png);
+
+        #test::before {
+            margin: 10px 10px;
+            content: "test me";
+            /* border: 1px solid black; */
+        }
+    }
+}
+</pre>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-2-expected.txt b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-2-expected.txt
new file mode 100644
index 0000000..230b867
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-2-expected.txt
@@ -0,0 +1,63 @@
+Verifies SCSS AST in case of variables.
+
+$my-color: red;
+$my-font: Arial;
+$class-slug: box;
+
+@for $i from 1 through 3 {
+    .#{$class-slug}#{$i} {
+        background-color: $my-color;
+        font-family: $my-font;
+        /* color: $my-color; */
+    }
+}
+
+=== AST === 
+rule 0: "variables"
+    property 0
+        name: "$my-color"
+            range: {"startLine":0,"startColumn":0,"endLine":0,"endColumn":9}
+        value: " red"
+            range: {"startLine":0,"startColumn":10,"endLine":0,"endColumn":14}
+        range: {"startLine":0,"startColumn":0,"endLine":0,"endColumn":15}
+        disabled: false
+    property 1
+        name: "$my-font"
+            range: {"startLine":1,"startColumn":0,"endLine":1,"endColumn":8}
+        value: " Arial"
+            range: {"startLine":1,"startColumn":9,"endLine":1,"endColumn":15}
+        range: {"startLine":1,"startColumn":0,"endLine":1,"endColumn":16}
+        disabled: false
+    property 2
+        name: "$class-slug"
+            range: {"startLine":2,"startColumn":0,"endLine":2,"endColumn":11}
+        value: " box"
+            range: {"startLine":2,"startColumn":12,"endLine":2,"endColumn":16}
+        range: {"startLine":2,"startColumn":0,"endLine":2,"endColumn":17}
+        disabled: false
+rule 1: "properties"
+    property 0
+        name: "background-color"
+            range: {"startLine":6,"startColumn":8,"endLine":6,"endColumn":24}
+        value: " $my-color"
+            range: {"startLine":6,"startColumn":25,"endLine":6,"endColumn":35}
+        range: {"startLine":6,"startColumn":8,"endLine":6,"endColumn":36}
+        disabled: false
+    property 1
+        name: "font-family"
+            range: {"startLine":7,"startColumn":8,"endLine":7,"endColumn":19}
+        value: " $my-font"
+            range: {"startLine":7,"startColumn":20,"endLine":7,"endColumn":29}
+        range: {"startLine":7,"startColumn":8,"endLine":7,"endColumn":30}
+        disabled: false
+    property 2
+        name: "color"
+            range: {"startLine":8,"startColumn":11,"endLine":8,"endColumn":16}
+        value: " $my-color"
+            range: {"startLine":8,"startColumn":17,"endLine":8,"endColumn":27}
+        range: {"startLine":8,"startColumn":8,"endLine":8,"endColumn":31}
+        disabled: true
+rule 2: "mixins"
+======
+Ranges OK.
+
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-2.html b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-2.html
new file mode 100644
index 0000000..3d33b76
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-2.html
@@ -0,0 +1,54 @@
+<html>
+<head>
+<script src="../../http/tests/inspector/inspector-test.js"></script>
+<script src="../../http/tests/inspector/elements-test.js"></script>
+<script src="./sass-test.js"></script>
+<style>
+pre {
+    font-family: monospace;
+}
+</style>
+<script>
+
+function test()
+{
+    InspectorTest.evaluateInPage("getSASS()", onSASS);
+
+    function onSASS(result)
+    {
+        InspectorTest.parseSCSS("", result.value)
+            .then(InspectorTest.dumpAST)
+            .then(InspectorTest.validateASTRanges)
+            .catch(console.error.bind(console))
+            .then(InspectorTest.completeTest);
+    }
+}
+
+function getSASS()
+{
+    return document.querySelector(".snippet").textContent;
+}
+
+</script>
+</head>
+
+<body onload="runTest()">
+<p>
+Verifies SCSS AST in case of variables.
+</p>
+<pre class="snippet">
+$my-color: red;
+$my-font: Arial;
+$class-slug: box;
+
+@for $i from 1 through 3 {
+    .#{$class-slug}#{$i} {
+        background-color: $my-color;
+        font-family: $my-font;
+        /* color: $my-color; */
+    }
+}
+
+</pre>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-3-expected.txt b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-3-expected.txt
new file mode 100644
index 0000000..db0db39
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-3-expected.txt
@@ -0,0 +1,75 @@
+Verifies AST of SCSS with mixins.
+
+@mixin awesome {
+    width: 100%;
+    height: 100%;
+}
+
+@mixin border-radius($radius) {
+  -webkit-border-radius: $radius;
+     -moz-border-radius: $radius;
+      -ms-border-radius: $radius;
+          border-radius: $radius;
+}
+
+div {
+    @include border-radius(15px);
+    @include awesome;
+}
+
+=== AST === 
+rule 0: "variables"
+rule 1: "properties"
+    property 0
+        name: "width"
+            range: {"startLine":1,"startColumn":4,"endLine":1,"endColumn":9}
+        value: " 100%"
+            range: {"startLine":1,"startColumn":10,"endLine":1,"endColumn":15}
+        range: {"startLine":1,"startColumn":4,"endLine":1,"endColumn":16}
+        disabled: false
+    property 1
+        name: "height"
+            range: {"startLine":2,"startColumn":4,"endLine":2,"endColumn":10}
+        value: " 100%"
+            range: {"startLine":2,"startColumn":11,"endLine":2,"endColumn":16}
+        range: {"startLine":2,"startColumn":4,"endLine":2,"endColumn":17}
+        disabled: false
+    property 2
+        name: "-webkit-border-radius"
+            range: {"startLine":6,"startColumn":2,"endLine":6,"endColumn":23}
+        value: " $radius"
+            range: {"startLine":6,"startColumn":24,"endLine":6,"endColumn":32}
+        range: {"startLine":6,"startColumn":2,"endLine":6,"endColumn":33}
+        disabled: false
+    property 3
+        name: "-moz-border-radius"
+            range: {"startLine":7,"startColumn":5,"endLine":7,"endColumn":23}
+        value: " $radius"
+            range: {"startLine":7,"startColumn":24,"endLine":7,"endColumn":32}
+        range: {"startLine":7,"startColumn":5,"endLine":7,"endColumn":33}
+        disabled: false
+    property 4
+        name: "-ms-border-radius"
+            range: {"startLine":8,"startColumn":6,"endLine":8,"endColumn":23}
+        value: " $radius"
+            range: {"startLine":8,"startColumn":24,"endLine":8,"endColumn":32}
+        range: {"startLine":8,"startColumn":6,"endLine":8,"endColumn":33}
+        disabled: false
+    property 5
+        name: "border-radius"
+            range: {"startLine":9,"startColumn":10,"endLine":9,"endColumn":23}
+        value: " $radius"
+            range: {"startLine":9,"startColumn":24,"endLine":9,"endColumn":32}
+        range: {"startLine":9,"startColumn":10,"endLine":9,"endColumn":33}
+        disabled: false
+rule 2: "mixins"
+    property 0
+        name: "@include border-radius"
+            range: {"startLine":13,"startColumn":4,"endLine":13,"endColumn":26}
+        value: "15px"
+            range: {"startLine":13,"startColumn":27,"endLine":13,"endColumn":31}
+        range: {"startLine":13,"startColumn":4,"endLine":13,"endColumn":32}
+        disabled: false
+======
+Ranges OK.
+
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-3.html b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-3.html
new file mode 100644
index 0000000..d165f50
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-3.html
@@ -0,0 +1,59 @@
+<html>
+<head>
+<script src="../../http/tests/inspector/inspector-test.js"></script>
+<script src="../../http/tests/inspector/elements-test.js"></script>
+<script src="./sass-test.js"></script>
+<style>
+pre {
+    font-family: monospace;
+}
+</style>
+<script>
+
+function test()
+{
+    InspectorTest.evaluateInPage("getSASS()", onSASS);
+
+    function onSASS(result)
+    {
+        InspectorTest.parseSCSS("", result.value)
+            .then(InspectorTest.dumpAST)
+            .then(InspectorTest.validateASTRanges)
+            .catch(console.error.bind(console))
+            .then(InspectorTest.completeTest);
+    }
+}
+
+function getSASS()
+{
+    return document.querySelector(".snippet").textContent;
+}
+
+</script>
+</head>
+
+<body onload="runTest()">
+<p>
+Verifies AST of SCSS with mixins.
+</p>
+<pre class="snippet">
+@mixin awesome {
+    width: 100%;
+    height: 100%;
+}
+
+@mixin border-radius($radius) {
+  -webkit-border-radius: $radius;
+     -moz-border-radius: $radius;
+      -ms-border-radius: $radius;
+          border-radius: $radius;
+}
+
+div {
+    @include border-radius(15px);
+    @include awesome;
+}
+
+</pre>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-4-expected.txt b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-4-expected.txt
new file mode 100644
index 0000000..17051b5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-4-expected.txt
@@ -0,0 +1,46 @@
+Verifies AST of SCSS with media query.
+
+@media (min-device-width: 720px) {
+    body {
+        width: 720px;
+        /* padding-top: 5em; */
+        height: 100%;
+        margin: 0 auto;
+    }
+}
+
+=== AST === 
+rule 0: "variables"
+rule 1: "properties"
+    property 0
+        name: "width"
+            range: {"startLine":2,"startColumn":8,"endLine":2,"endColumn":13}
+        value: " 720px"
+            range: {"startLine":2,"startColumn":14,"endLine":2,"endColumn":20}
+        range: {"startLine":2,"startColumn":8,"endLine":2,"endColumn":21}
+        disabled: false
+    property 1
+        name: "padding-top"
+            range: {"startLine":3,"startColumn":11,"endLine":3,"endColumn":22}
+        value: " 5em"
+            range: {"startLine":3,"startColumn":23,"endLine":3,"endColumn":27}
+        range: {"startLine":3,"startColumn":8,"endLine":3,"endColumn":31}
+        disabled: true
+    property 2
+        name: "height"
+            range: {"startLine":4,"startColumn":8,"endLine":4,"endColumn":14}
+        value: " 100%"
+            range: {"startLine":4,"startColumn":15,"endLine":4,"endColumn":20}
+        range: {"startLine":4,"startColumn":8,"endLine":4,"endColumn":21}
+        disabled: false
+    property 3
+        name: "margin"
+            range: {"startLine":5,"startColumn":8,"endLine":5,"endColumn":14}
+        value: " 0 auto"
+            range: {"startLine":5,"startColumn":15,"endLine":5,"endColumn":22}
+        range: {"startLine":5,"startColumn":8,"endLine":5,"endColumn":23}
+        disabled: false
+rule 2: "mixins"
+======
+Ranges OK.
+
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-4.html b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-4.html
new file mode 100644
index 0000000..0c9fdd91
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-4.html
@@ -0,0 +1,51 @@
+<html>
+<head>
+<script src="../../http/tests/inspector/inspector-test.js"></script>
+<script src="../../http/tests/inspector/elements-test.js"></script>
+<script src="./sass-test.js"></script>
+<style>
+pre {
+    font-family: monospace;
+}
+</style>
+<script>
+
+function test()
+{
+    InspectorTest.evaluateInPage("getSASS()", onSASS);
+
+    function onSASS(result)
+    {
+        InspectorTest.parseSCSS("", result.value)
+            .then(InspectorTest.dumpAST)
+            .then(InspectorTest.validateASTRanges)
+            .catch(console.error.bind(console))
+            .then(InspectorTest.completeTest);
+    }
+}
+
+function getSASS()
+{
+    return document.querySelector(".snippet").textContent;
+}
+
+</script>
+</head>
+
+<body onload="runTest()">
+<p>
+Verifies AST of SCSS with media query.
+</p>
+<pre class="snippet">
+@media (min-device-width: 720px) {
+    body {
+        width: 720px;
+        /* padding-top: 5em; */
+        height: 100%;
+        margin: 0 auto;
+    }
+}
+
+</pre>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-5-expected.txt b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-5-expected.txt
new file mode 100644
index 0000000..6d025ca
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-5-expected.txt
@@ -0,0 +1,48 @@
+Verifies AST of SCSS with missing trailing semicolon after last property.
+
+body {
+    /* padding-top: 5em; */
+    margin: 0 auto
+}
+
+body {
+    color: red;
+    /* margin: 0 auto */
+}
+
+=== AST === 
+rule 0: "variables"
+rule 1: "properties"
+    property 0
+        name: "padding-top"
+            range: {"startLine":1,"startColumn":7,"endLine":1,"endColumn":18}
+        value: " 5em"
+            range: {"startLine":1,"startColumn":19,"endLine":1,"endColumn":23}
+        range: {"startLine":1,"startColumn":4,"endLine":1,"endColumn":27}
+        disabled: true
+    property 1
+        name: "margin"
+            range: {"startLine":2,"startColumn":4,"endLine":2,"endColumn":10}
+        value: " 0 auto
+"
+            range: {"startLine":2,"startColumn":11,"endLine":3,"endColumn":0}
+        range: {"startLine":2,"startColumn":4,"endLine":3,"endColumn":1}
+        disabled: false
+    property 2
+        name: "color"
+            range: {"startLine":6,"startColumn":4,"endLine":6,"endColumn":9}
+        value: " red"
+            range: {"startLine":6,"startColumn":10,"endLine":6,"endColumn":14}
+        range: {"startLine":6,"startColumn":4,"endLine":6,"endColumn":15}
+        disabled: false
+    property 3
+        name: "margin"
+            range: {"startLine":7,"startColumn":7,"endLine":7,"endColumn":13}
+        value: " 0 auto "
+            range: {"startLine":7,"startColumn":14,"endLine":7,"endColumn":22}
+        range: {"startLine":7,"startColumn":4,"endLine":7,"endColumn":24}
+        disabled: true
+rule 2: "mixins"
+======
+Ranges OK.
+
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-5.html b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-5.html
new file mode 100644
index 0000000..3fbb44ca
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sass/test-ast-scss-5.html
@@ -0,0 +1,52 @@
+<html>
+<head>
+<script src="../../http/tests/inspector/inspector-test.js"></script>
+<script src="../../http/tests/inspector/elements-test.js"></script>
+<script src="./sass-test.js"></script>
+<style>
+pre {
+    font-family: monospace;
+}
+</style>
+<script>
+
+function test()
+{
+    InspectorTest.evaluateInPage("getSASS()", onSASS);
+
+    function onSASS(result)
+    {
+        InspectorTest.parseSCSS("", result.value)
+            .then(InspectorTest.dumpAST)
+            .then(InspectorTest.validateASTRanges)
+            .catch(console.error.bind(console))
+            .then(InspectorTest.completeTest);
+    }
+}
+
+function getSASS()
+{
+    return document.querySelector(".snippet").textContent;
+}
+
+</script>
+</head>
+
+<body onload="runTest()">
+<p>
+Verifies AST of SCSS with missing trailing semicolon after last property.
+</p>
+<pre class="snippet">
+body {
+    /* padding-top: 5em; */
+    margin: 0 auto
+}
+
+body {
+    color: red;
+    /* margin: 0 auto */
+}
+
+</pre>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-object-observe-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-object-observe-expected.txt
deleted file mode 100644
index 609ff246..0000000
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-object-observe-expected.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-Tests asynchronous call stacks for Object.observe().
-
-Set timer for test function.
-Captured call stacks in no particular order:
-Call stack:
-    0) observer (async-callstack-object-observe.html:32)
-    [Object.observe]
-    0) addProperties (async-callstack-object-observe.html:26)
-    1) timeout2 (async-callstack-object-observe.html:21)
-    [setTimeout]
-    0) timeout1 (async-callstack-object-observe.html:16)
-    [setTimeout]
-    0) testFunction (async-callstack-object-observe.html:10)
-    [setTimeout]
-    0) scheduleTestFunction (debugger-test.js:3)
-    <... skipped remaining frames ...>
-
-
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-object-observe.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-object-observe.html
deleted file mode 100644
index 1e351460c..0000000
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-object-observe.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<html>
-<head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/debugger-test.js"></script>
-<script>
-var obj = {};
-
-function testFunction()
-{
-    setTimeout(timeout1, 0);
-}
-
-function timeout1()
-{
-    Object.observe(obj, observer);
-    setTimeout(timeout2, 0);
-}
-
-function timeout2()
-{
-    addProperties();
-}
-
-function addProperties()
-{
-    obj.foo = 1;
-    obj.bar = 2;
-}
-
-function observer()
-{
-    debugger;
-}
-
-var test = function()
-{
-    var totalDebuggerStatements = 1;
-    var maxAsyncCallStackDepth = 4;
-    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
-}
-
-</script>
-</head>
-
-<body onload="runTest()">
-<p>
-Tests asynchronous call stacks for Object.observe().
-</p>
-
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-async2-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-async2-expected.txt
index f70b63d..aa40b06 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-async2-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-async2-expected.txt
@@ -28,23 +28,9 @@
 Executing StepOver...
 Executing StepIntoAsync...
 Call stack:
-    0) callback9 (debugger-step-into-async2.html:46)
-    [Object.observe]
-    0) callback8 (debugger-step-into-async2.html:41)
-    [Promise.resolve]
-    0) callback7 (debugger-step-into-async2.html:21)
-    [setTimeout]
-    0) testFunction (debugger-step-into-async2.html:15)
-
-Executing Resume...
-Executing StepOver...
-Executing StepIntoAsync...
-Call stack:
     0) onMessageReceivedInFrame (post-message-listener.html:5)
     [postMessage]
-    0) callback9 (debugger-step-into-async2.html:52)
-    [Object.observe]
-    0) callback8 (debugger-step-into-async2.html:41)
+    0) callback8 (debugger-step-into-async2.html:42)
     [Promise.resolve]
     0) callback7 (debugger-step-into-async2.html:21)
     [setTimeout]
@@ -54,43 +40,43 @@
 Executing StepInto...
 Executing StepIntoAsync...
 Call stack:
-    0) inner1 (debugger-step-into-async2.html:64)
+    0) inner1 (debugger-step-into-async2.html:54)
     [Promise.resolve]
-    0) callback10 (debugger-step-into-async2.html:63)
+    0) callback9 (debugger-step-into-async2.html:53)
     [postMessage]
     0) postMessageToParent (post-message-listener.html:13)
     1) onMessageReceivedInFrame (post-message-listener.html:8)
     [postMessage]
-    0) callback9 (debugger-step-into-async2.html:52)
-    [Object.observe]
-    0) callback8 (debugger-step-into-async2.html:41)
+    0) callback8 (debugger-step-into-async2.html:42)
+    [Promise.resolve]
+    0) callback7 (debugger-step-into-async2.html:21)
 
 Executing StepIntoAsync...
 Call stack:
-    0) inner2 (debugger-step-into-async2.html:70)
+    0) inner2 (debugger-step-into-async2.html:60)
     [Promise.resolve]
-    0) callback10 (debugger-step-into-async2.html:63)
+    0) callback9 (debugger-step-into-async2.html:53)
     [postMessage]
     0) postMessageToParent (post-message-listener.html:13)
     1) onMessageReceivedInFrame (post-message-listener.html:8)
     [postMessage]
-    0) callback9 (debugger-step-into-async2.html:52)
-    [Object.observe]
-    0) callback8 (debugger-step-into-async2.html:41)
+    0) callback8 (debugger-step-into-async2.html:42)
+    [Promise.resolve]
+    0) callback7 (debugger-step-into-async2.html:21)
 
 Executing StepIntoAsync...
 Executing StepIntoAsync...
 Call stack:
-    0) callback11 (debugger-step-into-async2.html:82)
-    1) inner2 (debugger-step-into-async2.html:72)
+    0) callback10 (debugger-step-into-async2.html:72)
+    1) inner2 (debugger-step-into-async2.html:62)
     [Promise.resolve]
-    0) callback10 (debugger-step-into-async2.html:63)
+    0) callback9 (debugger-step-into-async2.html:53)
     [postMessage]
     0) postMessageToParent (post-message-listener.html:13)
     1) onMessageReceivedInFrame (post-message-listener.html:8)
     [postMessage]
-    0) callback9 (debugger-step-into-async2.html:52)
-    [Object.observe]
-    0) callback8 (debugger-step-into-async2.html:41)
+    0) callback8 (debugger-step-into-async2.html:42)
+    [Promise.resolve]
+    0) callback7 (debugger-step-into-async2.html:21)
 
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-async2.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-async2.html
index f0de1a4..987330a 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-async2.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-async2.html
@@ -35,19 +35,9 @@
 
 function callback8()
 {
-    var obj = {};
-    Object.observe(obj, callback9);
-    debugger;
-    obj.foo = 1; // <- StepIntoAsync
-    setTimeout(dummy);
-    return 8;
-}
-
-function callback9()
-{
     var iframe = document.getElementById("iframe");
     var win = iframe.contentWindow;
-    window.addEventListener("message", callback10, false);
+    window.addEventListener("message", callback9, false);
     debugger;
     win.postMessage("skip debugger", "*"); // <- StepIntoAsync
     setTimeout(dummy, 0);
@@ -55,9 +45,9 @@
     return 9;
 }
 
-function callback10()
+function callback9()
 {
-    window.removeEventListener("message", callback10, false);
+    window.removeEventListener("message", callback9, false);
     debugger;
     Promise.resolve({foo: 44}) // <- StepIntoAsync
         .then(
@@ -69,7 +59,7 @@
         .then(
             function inner2()
             {
-                return callback11();
+                return callback10();
             }
         )
         .then(dummy);
@@ -77,7 +67,7 @@
     return 10;
 }
 
-function callback11()
+function callback10()
 {
     return 11;
 }
@@ -107,13 +97,12 @@
             "StepIntoAsync", "Print", // at callback7
             "Resume", // now paused at debugger in inner()
             "StepOver", "StepOver", "StepIntoAsync", "Print", // at callback8
-            "Resume", "StepOver", "StepIntoAsync", "Print", // at callback9
             "Resume", "StepOver", "StepIntoAsync", "Print", // at onmessage handler in iframe
-            "Resume", // now paused at debugger in callback10
+            "Resume", // now paused at debugger in callback9
             "StepInto", "StepIntoAsync", "Print", // in inner1
             "StepIntoAsync", "Print", // in inner2
             // Test that StepIntoAsync is StepInto when there are no Async operations.
-            "StepIntoAsync", "StepIntoAsync", "Print", // in callback11
+            "StepIntoAsync", "StepIntoAsync", "Print", // in callback10
         ];
         InspectorTest.waitUntilPausedAndPerformSteppingActions(actions, step4);
     }
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-url-comment-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-url-comment-expected.txt
index 1c9755e..c30a149 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-url-comment-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-url-comment-expected.txt
@@ -27,3 +27,9 @@
 function relativeURLScript() {}
 hasSourceURL: true
 
+Running: testMultipleSourceURLComment
+
+//# sourceURL=evalURL2.js
+function keepAlive() {}
+hasSourceURL: true
+
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-url-comment.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-url-comment.html
index 62ff6392..2c80a20 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-url-comment.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-url-comment.html
@@ -30,6 +30,11 @@
     eval("function keepAlive() {}\n//# sourceMappingURL=sourceMappingURL.map\n//# sourceURL=sourceURL.js");
 }
 
+function doEvalWithMultipleSourceURL()
+{
+    eval("\n//# sourceURL=evalURL2.js\nfunction keepAlive() {}\n//# sourceURL=evalMultipleURL.js");
+}
+
 function addScriptWithURL()
 {
     var script = document.createElement("script");
@@ -162,6 +167,19 @@
                 forEachScriptMatchingURL("nonRelativeURL.js", checkScriptSourceURL);
                 next();
             }
+        },
+
+        function testMultipleSourceURLComment(next)
+        {
+            InspectorTest.showScriptSource("evalMultipleURL.js", didShowScriptSource);
+            InspectorTest.evaluateInPage("setTimeout(doEvalWithMultipleSourceURL, 0)");
+
+            function didShowScriptSource(sourceFrame)
+            {
+                InspectorTest.addResult(sourceFrame.textEditor.text());
+                forEachScriptMatchingURL("evalMultipleURL.js", checkScriptSourceURL);
+                next();
+            }
         }
     ]);
 
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-event-causes.html b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-event-causes.html
index 95e4f44..129820f 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-event-causes.html
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-event-causes.html
@@ -30,8 +30,8 @@
                 var linkifier = new WebInspector.Linkifier();
                 var record = InspectorTest.findFirstTimelineRecord("TimerFire");
                 InspectorTest.check(record, "Should receive a TimerFire record.");
-                var contentHelper = new WebInspector.TimelineDetailsContentHelper(InspectorTest.timelineModel().target(), linkifier, null, true);
-                WebInspector.TimelineUIUtils._generateCauses(record.traceEvent(), InspectorTest.timelineModel().target(), contentHelper);
+                var contentHelper = new WebInspector.TimelineDetailsContentHelper(InspectorTest.timelineModel().target(), linkifier, true);
+                WebInspector.TimelineUIUtils._generateCauses(record.traceEvent(), InspectorTest.timelineModel().target(), null, contentHelper);
                 var causes = contentHelper.element.deepTextContent();
                 InspectorTest.check(causes, "Should generate causes");
                 checkStringContains(causes, "Timer InstalledsetTimeoutFunction @ setTimeoutFunction.js:");
@@ -56,8 +56,8 @@
                 var linkifier = new WebInspector.Linkifier();
                 var record = InspectorTest.findFirstTimelineRecord("FireAnimationFrame");
                 InspectorTest.check(record, "Should receive a FireAnimationFrame record.");
-                var contentHelper = new WebInspector.TimelineDetailsContentHelper(InspectorTest.timelineModel().target(), linkifier, null, true);
-                WebInspector.TimelineUIUtils._generateCauses(record.traceEvent(), InspectorTest.timelineModel().target(), contentHelper);
+                var contentHelper = new WebInspector.TimelineDetailsContentHelper(InspectorTest.timelineModel().target(), linkifier, true);
+                WebInspector.TimelineUIUtils._generateCauses(record.traceEvent(), InspectorTest.timelineModel().target(), null, contentHelper);
                 var causes = contentHelper.element.deepTextContent();
                 InspectorTest.check(causes, "Should generate causes");
                 checkStringContains(causes, "Animation Frame RequestedrequestAnimationFrameFunction @ requestAnimationFrameFunction.js:");
@@ -84,8 +84,8 @@
                 var linkifier = new WebInspector.Linkifier();
                 var record = InspectorTest.findFirstTimelineRecord("UpdateLayoutTree");
                 InspectorTest.check(record, "Should receive a UpdateLayoutTree record.");
-                var contentHelper = new WebInspector.TimelineDetailsContentHelper(InspectorTest.timelineModel().target(), linkifier, null, true);
-                WebInspector.TimelineUIUtils._generateCauses(record.traceEvent(), InspectorTest.timelineModel().target(), contentHelper);
+                var contentHelper = new WebInspector.TimelineDetailsContentHelper(InspectorTest.timelineModel().target(), linkifier, true);
+                WebInspector.TimelineUIUtils._generateCauses(record.traceEvent(), InspectorTest.timelineModel().target(), null, contentHelper);
                 var causes = contentHelper.element.deepTextContent();
                 InspectorTest.check(causes, "Should generate causes");
                 checkStringContains(causes, "First InvalidatedstyleRecalcFunction @ styleRecalcFunction.js:");
@@ -112,8 +112,8 @@
                 var linkifier = new WebInspector.Linkifier();
                 var record = InspectorTest.findFirstTimelineRecord("Layout");
                 InspectorTest.check(record, "Should receive a Layout record.");
-                var contentHelper = new WebInspector.TimelineDetailsContentHelper(InspectorTest.timelineModel().target(), linkifier, null, true);
-                WebInspector.TimelineUIUtils._generateCauses(record.traceEvent(), InspectorTest.timelineModel().target(), contentHelper);
+                var contentHelper = new WebInspector.TimelineDetailsContentHelper(InspectorTest.timelineModel().target(), linkifier, true);
+                WebInspector.TimelineUIUtils._generateCauses(record.traceEvent(), InspectorTest.timelineModel().target(), null, contentHelper);
                 var causes = contentHelper.element.deepTextContent();
                 InspectorTest.check(causes, "Should generate causes");
                 checkStringContains(causes, "Layout ForcedlayoutFunction @ layoutFunction.js:");
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-grouped-invalidations.html b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-grouped-invalidations.html
index 72dc311..9ff0806 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-grouped-invalidations.html
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-grouped-invalidations.html
@@ -29,8 +29,8 @@
 
         var linkifier = new WebInspector.Linkifier();
         var target = InspectorTest.timelineModel().target();
-        var contentHelper = new WebInspector.TimelineDetailsContentHelper(target, linkifier, null, true);
-        WebInspector.TimelineUIUtils._generateCauses(record.traceEvent(), target, contentHelper);
+        var contentHelper = new WebInspector.TimelineDetailsContentHelper(target, linkifier, true);
+        WebInspector.TimelineUIUtils._generateCauses(record.traceEvent(), target, null, contentHelper);
         var invalidationsTree = contentHelper.element.getElementsByClassName("invalidations-tree")[0];
         var invalidations = invalidationsTree.shadowRoot.textContent;
         checkStringContains(invalidations, "Inline CSS style declaration was mutated for [ DIV class='testElement' ], [ DIV class='testElement' ], and 2 others. (anonymous function) @ timeline-grouped-invalidations.html:12");
diff --git a/third_party/WebKit/LayoutTests/media/media-audio-no-spurious-repaints.html b/third_party/WebKit/LayoutTests/media/media-audio-no-spurious-repaints.html
new file mode 100644
index 0000000..fdc8974
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/media/media-audio-no-spurious-repaints.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<title>Verifies there are no spurious repaints for audio in a video tag.</title>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<video></video>
+<script>
+async_test(function(t) {
+    var video = document.querySelector('video');
+
+    video.addEventListener('canplaythrough', t.step_func(function() {
+        internals.startTrackingRepaints(document);
+        video.play();
+    }), false);
+
+    video.addEventListener('ended', t.step_func(function() {
+        var layerTree = internals.layerTreeAsText(
+            document, internals.LAYER_TREE_INCLUDES_REPAINT_RECTS);
+        var repaintRects = JSON.parse(layerTree).children[0].repaintRects;
+        internals.stopTrackingRepaints(document);
+
+        // Manually verify the number of repaints instead of using a repaint
+        // test since media playback is asynchronous by nature and its threading
+        // will cause a variance in the number of repaints on test bots.
+        var minExpected = 3, maxExpected = 4, expectedRect = [8, 8, 300, 150];
+
+        t.add_cleanup(function() {
+            if (t.status == t.PASS)
+                return;
+            console.log('FAIL! An unexpected number of repaints occurred;' +
+                        ' expected ' + minExpected + ' to ' + maxExpected +
+                        ' with rects of [' + expectedRect.join(', ') + '].' +
+                        ' Actual layer tree: ' + layerTree);
+        });
+
+        assert_between_inclusive(repaintRects.length, minExpected, maxExpected);
+        for (var i = 0; i < repaintRects.length; ++i)
+            assert_array_equals(repaintRects[i], expectedRect);
+
+        t.done();
+    }), false);
+
+    video.src = 'content/silence.wav';
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-after-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-after-composited-scroll-expected.txt
index 7a475c6..c46d6c2 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-after-composited-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-after-composited-scroll-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [300, 300],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 50, 100, 100]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [185, 200],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 4900],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 2400, 100, 100]
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/culling/scrolled-within-boxshadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/compositing/culling/scrolled-within-boxshadow-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/compositing/culling/scrolled-within-boxshadow-expected.png
rename to third_party/WebKit/LayoutTests/platform/android/compositing/culling/scrolled-within-boxshadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/culling/translated-boxshadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/compositing/culling/translated-boxshadow-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/compositing/culling/translated-boxshadow-expected.png
rename to third_party/WebKit/LayoutTests/platform/android/compositing/culling/translated-boxshadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/culling/unscrolled-within-boxshadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/compositing/culling/unscrolled-within-boxshadow-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/compositing/culling/unscrolled-within-boxshadow-expected.png
rename to third_party/WebKit/LayoutTests/platform/android/compositing/culling/unscrolled-within-boxshadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/compositing/geometry/clipping-foreground-expected.png b/third_party/WebKit/LayoutTests/platform/android/compositing/geometry/clipping-foreground-expected.png
new file mode 100644
index 0000000..4a88862
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/compositing/geometry/clipping-foreground-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/foreground-layer-expected.png b/third_party/WebKit/LayoutTests/platform/android/compositing/geometry/foreground-layer-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/compositing/geometry/foreground-layer-expected.png
rename to third_party/WebKit/LayoutTests/platform/android/compositing/geometry/foreground-layer-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/compositing/iframes/composited-iframe-alignment-expected.png b/third_party/WebKit/LayoutTests/platform/android/compositing/iframes/composited-iframe-alignment-expected.png
new file mode 100644
index 0000000..313d91d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/compositing/iframes/composited-iframe-alignment-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/compositing/masks/masked-ancestor-expected.png b/third_party/WebKit/LayoutTests/platform/android/compositing/masks/masked-ancestor-expected.png
new file mode 100644
index 0000000..ce2c0e82
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/compositing/masks/masked-ancestor-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/compositing/shadows/shadow-drawing-expected.png b/third_party/WebKit/LayoutTests/platform/android/compositing/shadows/shadow-drawing-expected.png
new file mode 100644
index 0000000..1b746c7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/compositing/shadows/shadow-drawing-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/compositing/squashing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/android/compositing/squashing/iframe-inside-squashed-layer-expected.txt
new file mode 100644
index 0000000..66fecc6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/compositing/squashing/iframe-inside-squashed-layer-expected.txt
@@ -0,0 +1,52 @@
+{
+  "bounds": [785, 1016],
+  "children": [
+    {
+      "bounds": [785, 1016],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "children": [
+        {
+          "shouldFlattenTransform": false,
+          "children": [
+            {
+              "position": [8, 8],
+              "bounds": [200, 1000],
+              "contentsOpaque": true,
+              "drawsContent": true,
+              "backgroundColor": "#D3D3D3"
+            },
+            {
+              "position": [8, 0],
+              "bounds": [300, 654],
+              "drawsContent": true,
+              "repaintRects": [
+                [285, 500, 15, 150],
+                [8, 508, 284, 20],
+                [8, 508, 269, 142],
+                [0, 500, 300, 150],
+                [0, 500, 300, 36],
+                [0, 500, 285, 150],
+                [0, 500, 285, 150],
+                [0, 500, 285, 150]
+              ],
+              "paintInvalidationClients": [
+                "RootInlineBox",
+                "InlineTextBox 'test1'",
+                "RootInlineBox",
+                "InlineTextBox 'test1'",
+                "LayoutView #document",
+                "LayoutView #document",
+                "LayoutBlockFlow HTML",
+                "LayoutBlockFlow BODY",
+                "VerticalScrollbar",
+                "LayoutView #document"
+              ]
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/android/css2.1/20110323/background-intrinsic-004-expected.png b/third_party/WebKit/LayoutTests/platform/android/css2.1/20110323/background-intrinsic-004-expected.png
new file mode 100644
index 0000000..dea275b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/css2.1/20110323/background-intrinsic-004-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize08-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize08-expected.png
deleted file mode 100644
index fbef12c..0000000
--- a/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize08-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize10-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize10-expected.png
deleted file mode 100644
index f815211..0000000
--- a/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize10-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize11-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize11-expected.png
deleted file mode 100644
index 246e1e7..0000000
--- a/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize11-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize12-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize12-expected.png
deleted file mode 100644
index 9e543a02..0000000
--- a/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize12-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize18-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize18-expected.png
deleted file mode 100644
index 7d4d9751..0000000
--- a/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize18-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize19-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize19-expected.png
deleted file mode 100644
index 1f8dace1f..0000000
--- a/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize19-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize21-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize21-expected.png
deleted file mode 100644
index 7d4d9751..0000000
--- a/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize21-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize22-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize22-expected.png
deleted file mode 100644
index 49fe0fe..0000000
--- a/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/size/backgroundSize22-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-mask-canvas-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-mask-canvas-with-shadow-expected.png
new file mode 100644
index 0000000..9e2ab0ac
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-mask-canvas-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-mask-video-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-mask-video-shadow-expected.png
new file mode 100644
index 0000000..bdd2569
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-mask-video-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-split-inline-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-split-inline-expected.png
new file mode 100644
index 0000000..4b6f67e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-split-inline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-with-box-shadow-01-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-with-box-shadow-01-expected.png
new file mode 100644
index 0000000..db91c09
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-with-box-shadow-01-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-with-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-with-box-shadow-expected.png
new file mode 100644
index 0000000..ed0d2eb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-with-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/basic-shadows-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/basic-shadows-expected.png
new file mode 100644
index 0000000..8e3cc85a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/basic-shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/box-shadow-clipped-slices-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/box-shadow-clipped-slices-expected.png
new file mode 100644
index 0000000..ef4c6b6f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/box-shadow-clipped-slices-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/box-shadow-expected.png
new file mode 100644
index 0000000..443c124
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/box-shadow-radius-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/box-shadow-radius-expected.png
new file mode 100644
index 0000000..484579df
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/box-shadow-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/box-shadow-transformed-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/box-shadow-transformed-expected.png
new file mode 100644
index 0000000..688577c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/box-shadow-transformed-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/inset-box-shadow-radius-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/inset-box-shadow-radius-expected.png
new file mode 100644
index 0000000..4beed5fa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/inset-box-shadow-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/inset-box-shadows-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/inset-box-shadows-expected.png
new file mode 100644
index 0000000..1f611b8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/inset-box-shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/scaled-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/scaled-box-shadow-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/scaled-box-shadow-expected.png
rename to third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/scaled-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/shadow-buffer-partial-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/shadow-buffer-partial-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/shadow-buffer-partial-expected.png
rename to third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/shadow-buffer-partial-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/shadow-tiling-artifact-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/shadow-tiling-artifact-expected.png
new file mode 100644
index 0000000..2618d98
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/shadow-tiling-artifact-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/single-pixel-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/single-pixel-shadow-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/single-pixel-shadow-expected.png
rename to third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/single-pixel-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-composite-shadow-expected.png
new file mode 100644
index 0000000..ee46464
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-shadow-source-in-expected.png
new file mode 100644
index 0000000..7f82cd3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-shadow-source-in-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/css/box-shadow-and-border-radius-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/css/box-shadow-and-border-radius-expected.png
new file mode 100644
index 0000000..777ef11
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/css/box-shadow-and-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/css/color-correction-on-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/css/color-correction-on-box-shadow-expected.png
new file mode 100644
index 0000000..9a833997
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/css/color-correction-on-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/css/color-correction-on-text-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/css/color-correction-on-text-shadow-expected.png
new file mode 100644
index 0000000..741a8a1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/css/color-correction-on-text-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/css/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/css/shadow-multiple-expected.png
new file mode 100644
index 0000000..9d09dcb52c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/css/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
new file mode 100644
index 0000000..f7623c0b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/forms/checkbox/checkbox-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/forms/checkbox/checkbox-appearance-basic-expected.png
new file mode 100644
index 0000000..076c06a0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/forms/checkbox/checkbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-appearance-expected.png
new file mode 100644
index 0000000..27f93a02
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
new file mode 100644
index 0000000..5fc2c773
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
new file mode 100644
index 0000000..2c38100
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
new file mode 100644
index 0000000..33b29812
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
new file mode 100644
index 0000000..da67ab2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
new file mode 100644
index 0000000..b479a975
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/forms/radio/radio-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/forms/radio/radio-appearance-basic-expected.png
new file mode 100644
index 0000000..2b87326
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/forms/radio/radio-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/forms/range/range-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/forms/range/range-appearance-basic-expected.png
new file mode 100644
index 0000000..642bb7bc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/forms/range/range-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/repaint/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/repaint/shadow-multiple-expected.png
new file mode 100644
index 0000000..3cd0696e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/repaint/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/text/shadow-translucent-fill-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/text/shadow-translucent-fill-expected.png
new file mode 100644
index 0000000..c557021
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/text/shadow-translucent-fill-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/text/stroking-decorations-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/text/stroking-decorations-expected.png
new file mode 100644
index 0000000..7e4cb50b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/text/stroking-decorations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/text/stroking-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/text/stroking-expected.png
new file mode 100644
index 0000000..dced0ffd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/text/stroking-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/transforms/shadows-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/transforms/shadows-expected.png
new file mode 100644
index 0000000..ca38354
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/transforms/shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/writing-mode/english-lr-text-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/writing-mode/english-lr-text-expected.png
new file mode 100644
index 0000000..db30fdc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/writing-mode/english-lr-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/text/textshadow-001-expected.png b/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/text/textshadow-001-expected.png
new file mode 100644
index 0000000..a8eb36e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/text/textshadow-001-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/text/textshadow-002-expected.png b/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/text/textshadow-002-expected.png
new file mode 100644
index 0000000..a5aa8f6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/text/textshadow-002-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/text/textshadow-003-expected.png b/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/text/textshadow-003-expected.png
new file mode 100644
index 0000000..10a4cc6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/text/textshadow-003-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/text/textshadow-004-expected.png b/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/text/textshadow-004-expected.png
new file mode 100644
index 0000000..c3b29d4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/text/textshadow-004-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/text/textshadow-010-expected.png b/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/text/textshadow-010-expected.png
new file mode 100644
index 0000000..1674291
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/text/textshadow-010-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/paint/roundedrects/circle-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/paint/roundedrects/circle-with-shadow-expected.png
new file mode 100644
index 0000000..ca70c05
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/paint/roundedrects/circle-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
new file mode 100644
index 0000000..2f58da4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt b/third_party/WebKit/LayoutTests/platform/android/svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
new file mode 100644
index 0000000..9d685de1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
@@ -0,0 +1,59 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [285, 135, 15, 15],
+        [285, 0, 15, 135],
+        [211, 11, 180, 180],
+        [210, 10, 180, 180],
+        [11, 11, 380, 180],
+        [11, 11, 180, 180],
+        [10, 10, 380, 180],
+        [10, 10, 180, 180],
+        [1, 1, 400, 200],
+        [1, 1, 400, 200],
+        [1, 1, 400, 200],
+        [1, 1, 400, 200],
+        [1, 1, 400, 200],
+        [1, 1, 400, 200],
+        [0, 135, 285, 15],
+        [0, 0, 800, 202],
+        [0, 0, 402, 202],
+        [0, 0, 300, 150],
+        [0, 0, 285, 135],
+        [0, 0, 285, 135],
+        [0, 0, 285, 135],
+        [0, 0, 285, 135],
+        [0, 0, 285, 135]
+      ],
+      "paintInvalidationClients": [
+        "InlineBox",
+        "RootInlineBox",
+        "HorizontalScrollbar",
+        "VerticalScrollbar",
+        "RootInlineBox",
+        "InlineBox",
+        "RootInlineBox",
+        "InlineBox",
+        "LayoutBlockFlow BODY",
+        "LayoutEmbeddedObject OBJECT",
+        "LayoutView #document",
+        "LayoutView #document",
+        "LayoutBlockFlow HTML",
+        "LayoutBlockFlow BODY",
+        "LayoutEmbeddedObject OBJECT",
+        "LayoutView #document",
+        "LayoutSVGRoot svg",
+        "LayoutSVGRect rect",
+        "LayoutSVGRect rect",
+        "LayoutText #text",
+        "LayoutView #document"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt b/third_party/WebKit/LayoutTests/platform/android/svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
new file mode 100644
index 0000000..9d685de1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
@@ -0,0 +1,59 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [285, 135, 15, 15],
+        [285, 0, 15, 135],
+        [211, 11, 180, 180],
+        [210, 10, 180, 180],
+        [11, 11, 380, 180],
+        [11, 11, 180, 180],
+        [10, 10, 380, 180],
+        [10, 10, 180, 180],
+        [1, 1, 400, 200],
+        [1, 1, 400, 200],
+        [1, 1, 400, 200],
+        [1, 1, 400, 200],
+        [1, 1, 400, 200],
+        [1, 1, 400, 200],
+        [0, 135, 285, 15],
+        [0, 0, 800, 202],
+        [0, 0, 402, 202],
+        [0, 0, 300, 150],
+        [0, 0, 285, 135],
+        [0, 0, 285, 135],
+        [0, 0, 285, 135],
+        [0, 0, 285, 135],
+        [0, 0, 285, 135]
+      ],
+      "paintInvalidationClients": [
+        "InlineBox",
+        "RootInlineBox",
+        "HorizontalScrollbar",
+        "VerticalScrollbar",
+        "RootInlineBox",
+        "InlineBox",
+        "RootInlineBox",
+        "InlineBox",
+        "LayoutBlockFlow BODY",
+        "LayoutEmbeddedObject OBJECT",
+        "LayoutView #document",
+        "LayoutView #document",
+        "LayoutBlockFlow HTML",
+        "LayoutBlockFlow BODY",
+        "LayoutEmbeddedObject OBJECT",
+        "LayoutView #document",
+        "LayoutSVGRoot svg",
+        "LayoutSVGRect rect",
+        "LayoutSVGRect rect",
+        "LayoutText #text",
+        "LayoutView #document"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/css/text-shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/android/svg/css/text-shadow-multiple-expected.png
new file mode 100644
index 0000000..9a44e1d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/svg/css/text-shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/custom/repaint-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/svg/custom/repaint-shadow-expected.png
new file mode 100644
index 0000000..23c5cffe
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/svg/custom/repaint-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-defaults-expected.png b/third_party/WebKit/LayoutTests/platform/android/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-defaults-expected.png
index fe8c3e57..1193f7a6 100644
--- a/third_party/WebKit/LayoutTests/platform/android/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-defaults-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/android/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-defaults-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
new file mode 100644
index 0000000..ee46464
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/android/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png
new file mode 100644
index 0000000..7f82cd3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/virtual/gpu/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/virtual/gpu/fast/canvas/canvas-composite-shadow-expected.png
new file mode 100644
index 0000000..bc4b9f5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/virtual/gpu/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/virtual/gpu/fast/canvas/canvas-incremental-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/android/virtual/gpu/fast/canvas/canvas-incremental-repaint-expected.png
new file mode 100644
index 0000000..dd0b145
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/virtual/gpu/fast/canvas/canvas-incremental-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/virtual/gpu/fast/canvas/canvas-scale-strokePath-shadow-expected.txt b/third_party/WebKit/LayoutTests/platform/android/virtual/gpu/fast/canvas/canvas-scale-strokePath-shadow-expected.txt
new file mode 100644
index 0000000..aeb83637
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/virtual/gpu/fast/canvas/canvas-scale-strokePath-shadow-expected.txt
@@ -0,0 +1,57 @@
+Ensure correct behavior of canvas with path stroke + shadow after scaling. A blue and red checkered pattern should be displayed.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is 255
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is 255
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is 255
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 76
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 76
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 76
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 200
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 49
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 199
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 70
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 70
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 69
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/platform/android/virtual/gpu/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/android/virtual/gpu/fast/canvas/canvas-shadow-source-in-expected.png
new file mode 100644
index 0000000..fcac6ee
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/virtual/gpu/fast/canvas/canvas-shadow-source-in-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/virtual/spv2/paint/roundedrects/circle-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/virtual/spv2/paint/roundedrects/circle-with-shadow-expected.png
new file mode 100644
index 0000000..ca70c05
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/virtual/spv2/paint/roundedrects/circle-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/virtual/spv2/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/virtual/spv2/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
new file mode 100644
index 0000000..2f58da4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/virtual/spv2/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt
new file mode 100644
index 0000000..93de88a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt
@@ -0,0 +1,28 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [10, 75, 150, 16],
+        [8, 72, 784, 22],
+        [8, 72, 154, 22],
+        [8, 57, 11, 11]
+      ],
+      "paintInvalidationClients": [
+        "LayoutDetailsMarker DIV id='details-marker'",
+        "LayoutBlockFlow DIV id='details-content'",
+        "LayoutTextControl INPUT",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "HorizontalScrollbar",
+        "VerticalScrollbar",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "LayoutText #text"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/overflow-scroll-body-appear-expected.txt b/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/overflow-scroll-body-appear-expected.txt
new file mode 100644
index 0000000..72c6d6b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/overflow-scroll-body-appear-expected.txt
@@ -0,0 +1,36 @@
+{
+  "bounds": [2008, 2096],
+  "children": [
+    {
+      "bounds": [2008, 2096],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [785, 585, 15, 15],
+        [8, 52, 784, 20],
+        [8, 52, 769, 20],
+        [8, 16, 2000, 2072],
+        [8, 16, 784, 20],
+        [8, 16, 769, 20],
+        [0, 0, 2008, 2096],
+        [0, 0, 785, 585]
+      ],
+      "paintInvalidationClients": [
+        "RootInlineBox",
+        "InlineTextBox 'You should see both vertical and horizontal scrollbars.'",
+        "RootInlineBox",
+        "InlineTextBox 'This is the test for '",
+        "InlineTextBox 'Bug 36461 - No vertical scrollbar after the CSS class change'",
+        "InlineTextBox '.'",
+        "LayoutView #document",
+        "LayoutView #document",
+        "LayoutBlockFlow BODY",
+        "LayoutBlockFlow P",
+        "LayoutBlockFlow P",
+        "HorizontalScrollbar",
+        "VerticalScrollbar"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/resize-scrollable-iframe-expected.txt b/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/resize-scrollable-iframe-expected.txt
new file mode 100644
index 0000000..3949115
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/resize-scrollable-iframe-expected.txt
@@ -0,0 +1,38 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [293, 393, 15, 15],
+        [293, 108, 15, 285],
+        [108, 108, 200, 300],
+        [93, 193, 15, 15],
+        [93, 108, 200, 285],
+        [93, 108, 15, 85],
+        [8, 393, 285, 15],
+        [8, 213, 784, 200],
+        [8, 208, 300, 200],
+        [8, 193, 285, 200],
+        [8, 193, 85, 15],
+        [8, 108, 784, 304],
+        [8, 108, 285, 285]
+      ],
+      "paintInvalidationClients": [
+        "InlineBox",
+        "RootInlineBox",
+        "LayoutBlockFlow (anonymous)",
+        "LayoutBlockFlow (anonymous)",
+        "LayoutIFrame IFRAME id='iframe'",
+        "LayoutView #document",
+        "LayoutView #document",
+        "HorizontalScrollbar",
+        "VerticalScrollbar",
+        "LayoutView #document"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png
new file mode 100644
index 0000000..3cd0696e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/paint/roundedrects/circle-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/paint/roundedrects/circle-with-shadow-expected.png
new file mode 100644
index 0000000..ca70c05
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/paint/roundedrects/circle-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
new file mode 100644
index 0000000..2f58da4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/clipping-foreground-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/clipping-foreground-expected.png
index 4a88862..7793949 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/clipping-foreground-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/clipping-foreground-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png
index 95a87ac..aba98e5 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/iframes/composited-iframe-alignment-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/iframes/composited-iframe-alignment-expected.png
index 313d91d..472e8c1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/iframes/composited-iframe-alignment-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/iframes/composited-iframe-alignment-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
index 290b2c179..782a82c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
@@ -11,15 +11,16 @@
         {
           "position": [8, 72],
           "bounds": [302, 302],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [1, 1],
               "bounds": [285, 285],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 800],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/masked-ancestor-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/masked-ancestor-expected.png
index ce2c0e82..788c843 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/masked-ancestor-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/masked-ancestor-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
index b85a763..f4e88a0 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
@@ -25,15 +25,16 @@
           "position": [8, 68],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -137,10 +138,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2562],
+  "bounds": [785, 2578],
   "children": [
     {
-      "bounds": [785, 2562],
+      "bounds": [785, 2578],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -148,15 +149,16 @@
           "position": [8, 68],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -260,24 +262,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4530],
+  "bounds": [785, 4562],
   "children": [
     {
-      "bounds": [785, 4530],
+      "bounds": [785, 4562],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -380,24 +383,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6450],
+  "bounds": [785, 6498],
   "children": [
     {
-      "bounds": [785, 6450],
+      "bounds": [785, 6498],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/selection-gaps-toggling-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/selection-gaps-toggling-expected.txt
index 4a47763..7bb7d757 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/selection-gaps-toggling-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/selection-gaps-toggling-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -134,24 +135,25 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2514],
+  "bounds": [785, 2530],
   "children": [
     {
-      "bounds": [785, 2514],
+      "bounds": [785, 2530],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -254,24 +256,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4434],
+  "bounds": [785, 4466],
   "children": [
     {
-      "bounds": [785, 4434],
+      "bounds": [785, 4466],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
index d6996d2..f6d489f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -134,10 +135,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2514],
+  "bounds": [785, 2530],
   "children": [
     {
-      "bounds": [785, 2514],
+      "bounds": [785, 2530],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -145,15 +146,16 @@
           "position": [8, 68],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -257,10 +259,10 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4482],
+  "bounds": [785, 4514],
   "children": [
     {
-      "bounds": [785, 4482],
+      "bounds": [785, 4514],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -268,15 +270,16 @@
           "position": [8, 68],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -380,24 +383,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6450],
+  "bounds": [785, 6498],
   "children": [
     {
-      "bounds": [785, 6450],
+      "bounds": [785, 6498],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/textarea-scroll-touch-expected.txt
index ebcfe549..7569bf1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,16 +11,17 @@
           "position": [18, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 328],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -45,16 +46,17 @@
           "position": [248, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 328],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
index ee3d294..c45f25aa 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [500, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [-2000, -2000, 5000, 5000]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [485, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [5000, 5000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 0, 5000, 5000]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/shadows/shadow-drawing-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/shadows/shadow-drawing-expected.png
index 1b746c7..e1e91d4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/shadows/shadow-drawing-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/shadows/shadow-drawing-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/squashing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/squashing/iframe-inside-squashed-layer-expected.txt
index 66fecc6..c727fa03 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/squashing/iframe-inside-squashed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/squashing/iframe-inside-squashed-layer-expected.txt
@@ -39,8 +39,8 @@
                 "LayoutView #document",
                 "LayoutBlockFlow HTML",
                 "LayoutBlockFlow BODY",
-                "VerticalScrollbar",
-                "LayoutView #document"
+                "LayoutView #document",
+                "VerticalScrollbar"
               ]
             }
           ]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css2.1/20110323/background-intrinsic-004-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css2.1/20110323/background-intrinsic-004-expected.png
index dea275b..9bc4f7e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/css2.1/20110323/background-intrinsic-004-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/css2.1/20110323/background-intrinsic-004-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-canvas-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-canvas-with-shadow-expected.png
index 9e2ab0ac..4d21886 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-canvas-with-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-canvas-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-shadow-expected.png
index bdd2569..d2e51ae 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-split-inline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-split-inline-expected.png
index 4b6f67e..406e0a8 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-split-inline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-split-inline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/basic-shadows-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/basic-shadows-expected.png
index 8e3cc85a..87e25a1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/basic-shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/basic-shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/box-shadow-expected.png
index 443c124..cccdb7f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/box-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/box-shadow-transformed-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/box-shadow-transformed-expected.png
index 688577c..1801dadf 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/box-shadow-transformed-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/box-shadow-transformed-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-box-shadow-radius-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-box-shadow-radius-expected.png
index 4beed5fa..0c69f85 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-box-shadow-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-box-shadow-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-box-shadows-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-box-shadows-expected.png
index 1f611b8..c979a34 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-box-shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-box-shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-expected.png
index 13fd9e7..1a9c561 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-subpixel-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-subpixel-expected.png
index 9199a49..39203b6 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-subpixel-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-subpixel-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-composite-shadow-expected.png
index ee46464..081c8b6 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-incremental-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-incremental-repaint-expected.png
index 942ab55..2da0067e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-incremental-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-incremental-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-shadow-source-in-expected.png
index 7f82cd3..7d63053 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-shadow-source-in-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-shadow-source-in-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/css/color-correction-on-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/css/color-correction-on-box-shadow-expected.png
index 9a833997..74e626e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/css/color-correction-on-box-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/css/color-correction-on-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/css/color-correction-on-text-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/css/color-correction-on-text-shadow-expected.png
index 741a8a1..f68b9d87 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/css/color-correction-on-text-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/css/color-correction-on-text-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/css/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/css/shadow-multiple-expected.png
index 9d09dcb52c..9418e4a4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/css/shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/css/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/dom/HTMLMeterElement/meter-styles-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/dom/HTMLMeterElement/meter-styles-expected.png
index 12b5085..802c1330 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/dom/HTMLMeterElement/meter-styles-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/dom/HTMLMeterElement/meter-styles-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
index 5cafdbb..44a5ca6f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
index 2197e82..95d0786 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
index 1f54172..4479c049 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
index fcc0c2f..1af304a4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
index f23c7b58..701fec3 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
index 2d441f0d..5e67fd3 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
index fb268524..7ac8c654 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index f7623c0b..2ba6472 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
index 0840041..5cdebf4b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/month-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/month-picker-appearance-expected.png
index 354c5811..3cae0ef 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/month-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/month-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/month-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
index 9475382..74d65da 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/week-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/week-picker-appearance-expected.png
index 55d4fd16..699e8ef 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/week-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/week-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/week-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
index 191148d..53acbef 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/checkbox/checkbox-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/checkbox/checkbox-appearance-basic-expected.png
index 076c06a0..9b620d1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/checkbox/checkbox-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/checkbox/checkbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-expected.png
index 27f93a02..533e1c4d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
index 5fc2c773..242a21e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
index 2c38100..95a7b3c7 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
index 33b29812..3f4d256 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
index da67ab2..e0826830 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
index b479a975..79dd632 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/radio/radio-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/radio/radio-appearance-basic-expected.png
index 2b87326..50295ea 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/radio/radio-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/radio/radio-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/range/range-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/range/range-appearance-basic-expected.png
index 642bb7bc..b61ca39 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/range/range-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/range/range-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/search/search-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/search/search-appearance-basic-expected.png
index 1995589d..557ea92 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/search/search-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/search/search-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/listbox-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/listbox-appearance-basic-expected.png
index de027a3a..8194a41c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/listbox-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/listbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.png
index 70d0b7c..c4a1297 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/submit/submit-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/submit/submit-appearance-basic-expected.png
index 3dbf1ba..bbe0323dc 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/submit/submit-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/submit/submit-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/text/text-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/text/text-appearance-basic-expected.png
index 016611d..e09a550 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/text/text-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/text/text-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/textarea/textarea-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/textarea/textarea-appearance-basic-expected.png
index 9a3e2c56..9f010af 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/textarea/textarea-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/textarea/textarea-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/details-open-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/details-open-repaint-expected.txt
index 93de88a..8df0e94 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/details-open-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/details-open-repaint-expected.txt
@@ -16,9 +16,10 @@
         "LayoutBlockFlow DIV id='details-content'",
         "LayoutTextControl INPUT",
         "LayoutBlockFlow DIV id='inner-editor'",
-        "HorizontalScrollbar",
-        "VerticalScrollbar",
         "LayoutBlockFlow DIV id='inner-editor'",
+        "HorizontalScrollbar",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "VerticalScrollbar",
         "LayoutText #text",
         "LayoutText #text"
       ]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/overflow-scroll-body-appear-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/overflow-scroll-body-appear-expected.txt
index 72c6d6b..1d10dc8 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/overflow-scroll-body-appear-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/overflow-scroll-body-appear-expected.txt
@@ -7,11 +7,13 @@
       "drawsContent": true,
       "repaintRects": [
         [785, 585, 15, 15],
+        [785, 0, 15, 585],
         [8, 52, 784, 20],
         [8, 52, 769, 20],
         [8, 16, 2000, 2072],
         [8, 16, 784, 20],
         [8, 16, 769, 20],
+        [0, 585, 785, 15],
         [0, 0, 2008, 2096],
         [0, 0, 785, 585]
       ],
@@ -27,8 +29,8 @@
         "LayoutBlockFlow BODY",
         "LayoutBlockFlow P",
         "LayoutBlockFlow P",
-        "HorizontalScrollbar",
-        "VerticalScrollbar"
+        "LayoutView #document",
+        "LayoutView #document"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/resize-scrollable-iframe-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/resize-scrollable-iframe-expected.txt
index 3949115..0a84efca 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/resize-scrollable-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/resize-scrollable-iframe-expected.txt
@@ -28,9 +28,10 @@
         "LayoutIFrame IFRAME id='iframe'",
         "LayoutView #document",
         "LayoutView #document",
+        "LayoutView #document",
         "HorizontalScrollbar",
-        "VerticalScrollbar",
-        "LayoutView #document"
+        "LayoutView #document",
+        "VerticalScrollbar"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/shadow-multiple-expected.png
index 3cd0696e..1e910b9 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/shadow-translucent-fill-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/text/shadow-translucent-fill-expected.png
index c557021..11c56ef7 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/text/shadow-translucent-fill-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/shadow-translucent-fill-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/stroking-decorations-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/text/stroking-decorations-expected.png
index 7e4cb50b..206b9267 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/text/stroking-decorations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/stroking-decorations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/stroking-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/text/stroking-expected.png
index dced0ffd..5773013c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/text/stroking-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/stroking-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/transforms/shadows-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/transforms/shadows-expected.png
index ca38354..8791d95 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/transforms/shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/transforms/shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/writing-mode/english-lr-text-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/writing-mode/english-lr-text-expected.png
index db30fdc..debcdde41 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/writing-mode/english-lr-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/writing-mode/english-lr-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-001-expected.png b/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-001-expected.png
index a8eb36e..3da9c97e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-001-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-001-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-002-expected.png b/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-002-expected.png
index a5aa8f6..5b5d0ed3 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-002-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-002-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-003-expected.png b/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-003-expected.png
index 10a4cc6..b7004cf 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-003-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-003-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-004-expected.png b/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-004-expected.png
index c3b29d4..51abafe 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-004-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-004-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-010-expected.png b/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-010-expected.png
index 1674291..94d1da84 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-010-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/text/textshadow-010-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/roundedrects/circle-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/roundedrects/circle-with-shadow-expected.png
index ca70c05..12b81e9 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/roundedrects/circle-with-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/roundedrects/circle-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/selection/selection-within-composited-scroller-expected.txt
index b172a4e..33e09c53 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/selection/selection-within-composited-scroller-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/selection/selection-within-composited-scroller-expected.txt
@@ -14,6 +14,7 @@
           "position": [8, 8],
           "bounds": [200, 200],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#D3D3D3",
           "repaintRects": [
@@ -25,10 +26,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 1620],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 610, 21, 19]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/plugins/webview-plugin-nested-iframe-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/linux/plugins/webview-plugin-nested-iframe-scroll-expected.png
new file mode 100644
index 0000000..c0d366e5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/plugins/webview-plugin-nested-iframe-scroll-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/plugins/webview-plugin-nested-iframe-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/plugins/webview-plugin-nested-iframe-scroll-expected.txt
new file mode 100644
index 0000000..c56df39
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/plugins/webview-plugin-nested-iframe-scroll-expected.txt
@@ -0,0 +1,19 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x175
+  LayoutBlockFlow {HTML} at (0,0) size 800x175
+    LayoutBlockFlow {BODY} at (8,8) size 784x159
+      LayoutText {#text} at (0,0) size 0x0
+layer at (8,8) size 304x154
+  LayoutIFrame {IFRAME} at (0,0) size 304x154 [border: (2px inset #EEEEEE)]
+    layer at (0,0) size 300x150 clip at (0,0) size 285x135 scrollY 50.00 scrollWidth 308 scrollHeight 3211
+      LayoutView at (0,0) size 300x150
+    layer at (0,0) size 285x3211 backgroundClip at (0,0) size 285x135 clip at (0,0) size 285x135
+      LayoutBlockFlow {HTML} at (0,0) size 285x3211
+        LayoutBlockFlow {BODY} at (8,8) size 269x3195
+          LayoutBlockFlow {DIV} at (0,0) size 269x40
+          LayoutBlockFlow (anonymous) at (0,40) size 269x155
+            LayoutText {#text} at (0,0) size 0x0
+          LayoutBlockFlow {DIV} at (0,195) size 269x3000
+    layer at (8,48) size 300x150 backgroundClip at (0,0) size 285x135 clip at (0,0) size 285x135
+      LayoutEmbeddedObject {EMBED} at (0,0) size 300x150
diff --git a/third_party/WebKit/LayoutTests/platform/android/plugins/webview-plugin-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/linux/plugins/webview-plugin-scroll-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/android/plugins/webview-plugin-scroll-expected.png
rename to third_party/WebKit/LayoutTests/platform/linux/plugins/webview-plugin-scroll-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-gradient-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-gradient-shadow-expected.png
index e4970a4e..4bbb039 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-gradient-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-gradient-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-shadow-multiple-expected.png
index 9a44e1d..c661a9dd2 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/repaint-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/repaint-shadow-expected.png
index 23c5cffe..21ba2be 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/repaint-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/repaint-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image1-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image1-expected.png
index d61ef55d..4d6a253d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image1-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image1-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-background-images-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-background-images-expected.png
index 1e778aa..d4d47a5 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-background-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-background-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
index ee46464..081c8b6 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
index 942ab55..2da0067e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png
new file mode 100644
index 0000000..7d63053
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-composite-shadow-expected.png
index bc4b9f5..042d80e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-incremental-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-incremental-repaint-expected.png
index dd0b145..3af638f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-incremental-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-incremental-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-shadow-source-in-expected.png
index fcac6ee..e3731d5 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-shadow-source-in-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-shadow-source-in-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
index b85a763..f4e88a0 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
@@ -25,15 +25,16 @@
           "position": [8, 68],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -137,10 +138,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2562],
+  "bounds": [785, 2578],
   "children": [
     {
-      "bounds": [785, 2562],
+      "bounds": [785, 2578],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -148,15 +149,16 @@
           "position": [8, 68],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -260,24 +262,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4530],
+  "bounds": [785, 4562],
   "children": [
     {
-      "bounds": [785, 4530],
+      "bounds": [785, 4562],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -380,24 +383,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6450],
+  "bounds": [785, 6498],
   "children": [
     {
-      "bounds": [785, 6450],
+      "bounds": [785, 6498],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt
index 4a47763..7bb7d757 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -134,24 +135,25 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2514],
+  "bounds": [785, 2530],
   "children": [
     {
-      "bounds": [785, 2514],
+      "bounds": [785, 2530],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -254,24 +256,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4434],
+  "bounds": [785, 4466],
   "children": [
     {
-      "bounds": [785, 4434],
+      "bounds": [785, 4466],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
index d6996d2..f6d489f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -134,10 +135,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2514],
+  "bounds": [785, 2530],
   "children": [
     {
-      "bounds": [785, 2514],
+      "bounds": [785, 2530],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -145,15 +146,16 @@
           "position": [8, 68],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -257,10 +259,10 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4482],
+  "bounds": [785, 4514],
   "children": [
     {
-      "bounds": [785, 4482],
+      "bounds": [785, 4514],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -268,15 +270,16 @@
           "position": [8, 68],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -380,24 +383,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6450],
+  "bounds": [785, 6498],
   "children": [
     {
-      "bounds": [785, 6450],
+      "bounds": [785, 6498],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt
index 52e2586..b08b28b4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 61],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 0, 48, 656]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 656],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 0, 48, 656]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt
index 8336acb..16a6c02 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt
@@ -16,6 +16,7 @@
         {
           "position": [0, 60],
           "bounds": [800, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [244, 0, 40, 19],
@@ -29,10 +30,10 @@
           "children": [
             {
               "bounds": [785, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [785, 1345],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [244, 0, 40, 19],
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
index ebcfe549..7569bf1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,16 +11,17 @@
           "position": [18, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 328],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -45,16 +46,17 @@
           "position": [248, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 328],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt
index 569027b..c36669f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 108],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 190, 74, 19],
@@ -28,10 +29,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 260],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 240, 74, 19],
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/spv2/paint/roundedrects/circle-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/spv2/paint/roundedrects/circle-with-shadow-expected.png
new file mode 100644
index 0000000..12b81e9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/spv2/paint/roundedrects/circle-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
index ee3d294..c45f25aa 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [500, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [-2000, -2000, 5000, 5000]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [485, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [5000, 5000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 0, 5000, 5000]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt
index 93de88a..8df0e94 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt
@@ -16,9 +16,10 @@
         "LayoutBlockFlow DIV id='details-content'",
         "LayoutTextControl INPUT",
         "LayoutBlockFlow DIV id='inner-editor'",
-        "HorizontalScrollbar",
-        "VerticalScrollbar",
         "LayoutBlockFlow DIV id='inner-editor'",
+        "HorizontalScrollbar",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "VerticalScrollbar",
         "LayoutText #text",
         "LayoutText #text"
       ]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/overflow-scroll-body-appear-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/overflow-scroll-body-appear-expected.txt
index 72c6d6b..1d10dc8 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/overflow-scroll-body-appear-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/overflow-scroll-body-appear-expected.txt
@@ -7,11 +7,13 @@
       "drawsContent": true,
       "repaintRects": [
         [785, 585, 15, 15],
+        [785, 0, 15, 585],
         [8, 52, 784, 20],
         [8, 52, 769, 20],
         [8, 16, 2000, 2072],
         [8, 16, 784, 20],
         [8, 16, 769, 20],
+        [0, 585, 785, 15],
         [0, 0, 2008, 2096],
         [0, 0, 785, 585]
       ],
@@ -27,8 +29,8 @@
         "LayoutBlockFlow BODY",
         "LayoutBlockFlow P",
         "LayoutBlockFlow P",
-        "HorizontalScrollbar",
-        "VerticalScrollbar"
+        "LayoutView #document",
+        "LayoutView #document"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/resize-scrollable-iframe-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/resize-scrollable-iframe-expected.txt
index 3949115..0a84efca 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/resize-scrollable-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/resize-scrollable-iframe-expected.txt
@@ -28,9 +28,10 @@
         "LayoutIFrame IFRAME id='iframe'",
         "LayoutView #document",
         "LayoutView #document",
+        "LayoutView #document",
         "HorizontalScrollbar",
-        "VerticalScrollbar",
-        "LayoutView #document"
+        "LayoutView #document",
+        "VerticalScrollbar"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png
new file mode 100644
index 0000000..1e910b9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/paint/roundedrects/circle-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/paint/roundedrects/circle-with-shadow-expected.png
new file mode 100644
index 0000000..12b81e9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/paint/roundedrects/circle-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt
index b172a4e..33e09c53 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt
@@ -14,6 +14,7 @@
           "position": [8, 8],
           "bounds": [200, 200],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#D3D3D3",
           "repaintRects": [
@@ -25,10 +26,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 1620],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 610, 21, 19]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/compositing/shadows/shadow-drawing-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/compositing/shadows/shadow-drawing-expected.png
index ac704ed..2196f775 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/compositing/shadows/shadow-drawing-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/compositing/shadows/shadow-drawing-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/box-shadow/basic-shadows-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/box-shadow/basic-shadows-expected.png
index fbd99b5..1382e80 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/box-shadow/basic-shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/box-shadow/basic-shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/css/color-correction-on-text-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/css/color-correction-on-text-shadow-expected.png
index 3d957e7..7185b89 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/css/color-correction-on-text-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/css/color-correction-on-text-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/css/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/css/shadow-multiple-expected.png
index 4454b4d..f54479e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/css/shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/css/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
index 45bf9bd..39e539fd7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
index d132c0a..5653d6b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
index 19289c7..4391254e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
index a4d06d8..d8d1a84 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
index 832090c..85533d6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
index 06c7c4ac..d68b5b8 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
index 837e744..e36ae13 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index 3c377645..6dd5f077 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
index 51ce71ea..4796e2d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/month-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/month-picker-appearance-expected.png
index 2379bba3..d70826c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/month-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/month-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/month-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
index 5b84523b..dfe11fa 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/week-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/week-picker-appearance-expected.png
index 566fa88f..c3959e1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/week-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/week-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/week-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
index da9aa3b..d3ac266 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/checkbox/checkbox-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/checkbox/checkbox-appearance-basic-expected.png
index c9aa133..525d3eb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/checkbox/checkbox-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/checkbox/checkbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/color/color-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/color/color-suggestion-picker-appearance-expected.png
index 5addab9..9606a4c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/color/color-suggestion-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/color/color-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
index 1848abf0..953e70ea 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
index bb9df56..e2f5a2ab 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
index 0250b965..3cee443 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/input-appearance-height-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/input-appearance-height-expected.png
index 988f4276..ccf4d09 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/input-appearance-height-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/input-appearance-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/radio/radio-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/radio/radio-appearance-basic-expected.png
index 71b5cc50..1900a6f5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/radio/radio-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/radio/radio-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/search/search-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/search/search-appearance-basic-expected.png
index dddd965..9e1e1fd 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/search/search-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/search/search-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/select/listbox-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/select/listbox-appearance-basic-expected.png
index 0e7aa9a..89cac62 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/select/listbox-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/select/listbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/select/menulist-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/select/menulist-appearance-basic-expected.png
index af6fed9..17b30ae 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/select/menulist-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/select/menulist-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/submit/submit-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/submit/submit-appearance-basic-expected.png
index a8e0824..b999377 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/submit/submit-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/submit/submit-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/text/text-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/text/text-appearance-basic-expected.png
index 75d88d8..6e521f8a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/text/text-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/text/text-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/repaint/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/repaint/shadow-multiple-expected.png
index fd893aa..ac04001 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/repaint/shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/repaint/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/shadow-translucent-fill-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/shadow-translucent-fill-expected.png
index f3f28ec..9e450b5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/shadow-translucent-fill-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/shadow-translucent-fill-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/stroking-decorations-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/stroking-decorations-expected.png
index e6c4b9a1..e4c94fe5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/stroking-decorations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/stroking-decorations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/stroking-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/stroking-expected.png
index ba0be40..5de917c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/stroking-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/stroking-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/transforms/shadows-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/transforms/shadows-expected.png
index 832de4f..a2345f1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/transforms/shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/transforms/shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/writing-mode/english-lr-text-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/writing-mode/english-lr-text-expected.png
index 47cc4a4..48ab939 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/writing-mode/english-lr-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/writing-mode/english-lr-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-001-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-001-expected.png
index 6d0a170a..d4f5d42b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-001-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-001-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-002-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-002-expected.png
index 8a9d012..0b0b8a4d2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-002-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-002-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-003-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-003-expected.png
index b08c3448..9e9c1ad9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-003-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-003-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-004-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-004-expected.png
index cd49f4e..ac43bfd 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-004-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-004-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-010-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-010-expected.png
index 0ca89de..01d9a7c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-010-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/ietestcenter/css3/text/textshadow-010-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/plugins/webview-plugin-nested-iframe-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/plugins/webview-plugin-nested-iframe-scroll-expected.png
new file mode 100644
index 0000000..f8d1053
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/plugins/webview-plugin-nested-iframe-scroll-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/svg/css/text-gradient-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/svg/css/text-gradient-shadow-expected.png
index cca7ea9d..9721365d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/svg/css/text-gradient-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/svg/css/text-gradient-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/svg/css/text-shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/svg/css/text-shadow-multiple-expected.png
index 6638ca9..fb9ae3e8 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/svg/css/text-shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/svg/css/text-shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/svg/custom/repaint-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/svg/custom/repaint-shadow-expected.png
index d904b03..21ba2be 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/svg/custom/repaint-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/svg/custom/repaint-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/custom/repaint-shadow-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-lion/svg/custom/repaint-shadow-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/mac-retina/svg/custom/repaint-shadow-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac-lion/svg/custom/repaint-shadow-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/svg/wicd/test-scalable-background-image1-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/svg/wicd/test-scalable-background-image1-expected.png
index 87642d23..63fd0aa 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-lion/svg/wicd/test-scalable-background-image1-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/svg/wicd/test-scalable-background-image1-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png
new file mode 100644
index 0000000..ac04001
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-lion/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mavericks/compositing/overflow/textarea-scroll-touch-expected.txt
index 4e9eea9..bd1fe76 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,16 +11,17 @@
           "position": [18, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 308],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -45,16 +46,17 @@
           "position": [248, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 308],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/box-shadow/basic-shadows-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/box-shadow/basic-shadows-expected.png
index fe7fa27..24a5ee5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/box-shadow/basic-shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/box-shadow/basic-shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/css/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/css/shadow-multiple-expected.png
index ffacec9..b87cbad 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/css/shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/css/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
index 48c013b..a7ec163c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
index 5a83912..2ae680c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
index 96643b6..51632d6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
index aa673444..23947d4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
index 90d8ae9..56791568 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
index 780556c..28d1c27 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
index c8f262f..6e4954e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index 08ea838..098a09e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
index c7c4717..ebc968d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/month-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/month-picker-appearance-expected.png
index de2f1de..fc8f585 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/month-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/month-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/month-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
index 82adc5b..22f5847 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/week-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/week-picker-appearance-expected.png
index f3dd6ff..f01ffee 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/week-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/week-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/week-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
index 94e2197..e2f1d849 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/checkbox/checkbox-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/checkbox/checkbox-appearance-basic-expected.png
index a567f5e..c250bab 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/checkbox/checkbox-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/checkbox/checkbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-appearance-expected.png
index 26b9a3f..6cfeda1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
index 4a5499b..5ad1a7e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
index 741b0b44..331c2d0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
index e323c0b..0ce022ea 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
index 5c07d61f..26c29e1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
index c9a769ca..4460499 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/input-appearance-height-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/input-appearance-height-expected.png
index cf51d73..c5cb912 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/input-appearance-height-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/input-appearance-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/radio/radio-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/radio/radio-appearance-basic-expected.png
index 9054dde..c445536c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/radio/radio-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/radio/radio-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/search/search-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/search/search-appearance-basic-expected.png
index 89dcbbb..0f8773f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/search/search-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/search/search-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/select/listbox-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/select/listbox-appearance-basic-expected.png
index a60c1b0e..8a11411 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/select/listbox-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/select/listbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/select/menulist-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/select/menulist-appearance-basic-expected.png
index 8d19a7c..dfeca3a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/select/menulist-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/select/menulist-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/submit/submit-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/submit/submit-appearance-basic-expected.png
index 39390f13..f801e37f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/submit/submit-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/submit/submit-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/text/text-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/text/text-appearance-basic-expected.png
index 644f1c7..69dd2fe 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/text/text-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/text/text-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/textarea/textarea-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/textarea/textarea-appearance-basic-expected.png
index b1d85e5..eafaef1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/textarea/textarea-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/textarea/textarea-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/details-open-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/details-open-repaint-expected.txt
index 7d95bd6..24b4f5e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/details-open-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/details-open-repaint-expected.txt
@@ -16,9 +16,10 @@
         "LayoutBlockFlow DIV id='details-content'",
         "LayoutTextControl INPUT",
         "LayoutBlockFlow DIV id='inner-editor'",
-        "HorizontalScrollbar",
-        "VerticalScrollbar",
         "LayoutBlockFlow DIV id='inner-editor'",
+        "HorizontalScrollbar",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "VerticalScrollbar",
         "LayoutText #text",
         "LayoutText #text"
       ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/japanese-rl-selection-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/japanese-rl-selection-repaint-expected.txt
index 20d342c4..0a55488 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/japanese-rl-selection-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/japanese-rl-selection-repaint-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [420, 23, 352, 541]
+        [420, 23, 352, 548]
       ],
       "paintInvalidationClients": [
         "LayoutBlockFlow HTML",
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/writing-mode/japanese-lr-selection-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/writing-mode/japanese-lr-selection-expected.png
index 9c9f99f2..f7556de 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/writing-mode/japanese-lr-selection-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/writing-mode/japanese-lr-selection-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/writing-mode/japanese-rl-selection-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/writing-mode/japanese-rl-selection-expected.png
index 5a2db32c..f83ce03 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/writing-mode/japanese-rl-selection-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/writing-mode/japanese-rl-selection-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/plugins/webview-plugin-nested-iframe-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/plugins/webview-plugin-nested-iframe-scroll-expected.png
new file mode 100644
index 0000000..7ad45f0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/plugins/webview-plugin-nested-iframe-scroll-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/svg/wicd/test-scalable-background-image1-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/svg/wicd/test-scalable-background-image1-expected.png
index 5500a0e..0259dd4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/svg/wicd/test-scalable-background-image1-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/svg/wicd/test-scalable-background-image1-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
index 4e9eea9..bd1fe76 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,16 +11,17 @@
           "position": [18, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 308],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -45,16 +46,17 @@
           "position": [248, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 308],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt
index 7d95bd6..24b4f5e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt
@@ -16,9 +16,10 @@
         "LayoutBlockFlow DIV id='details-content'",
         "LayoutTextControl INPUT",
         "LayoutBlockFlow DIV id='inner-editor'",
-        "HorizontalScrollbar",
-        "VerticalScrollbar",
         "LayoutBlockFlow DIV id='inner-editor'",
+        "HorizontalScrollbar",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "VerticalScrollbar",
         "LayoutText #text",
         "LayoutText #text"
       ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/syncpaint/fast/repaint/japanese-rl-selection-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/syncpaint/fast/repaint/japanese-rl-selection-repaint-expected.txt
index 20d342c4..0a55488 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/syncpaint/fast/repaint/japanese-rl-selection-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/syncpaint/fast/repaint/japanese-rl-selection-repaint-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [420, 23, 352, 541]
+        [420, 23, 352, 548]
       ],
       "paintInvalidationClients": [
         "LayoutBlockFlow HTML",
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
index 8e15217..1bd5f24a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
index 61a396d1..4b4e3b3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/color/color-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/color/color-suggestion-picker-appearance-expected.png
index be415af..7d6f70a5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/color/color-suggestion-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/color/color-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
index 868a66d..09f8022 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
index 96f05aa2..4039c79 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
index e4ddf3e..e0fa627 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/svg/custom/repaint-shadow-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/svg/custom/repaint-shadow-expected.txt
deleted file mode 100644
index 5f1ef34..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/svg/custom/repaint-shadow-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-X
-X
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/layer-creation/fixed-position-in-fixed-overflow-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/layer-creation/fixed-position-in-fixed-overflow-expected.txt
index 10d67a88..5901513 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/layer-creation/fixed-position-in-fixed-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/layer-creation/fixed-position-in-fixed-overflow-expected.txt
@@ -9,14 +9,15 @@
         {
           "position": [8, 13],
           "bounds": [800, 600],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [785, 600],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [785, 1000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "children": [
                     {
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
index 5ce42ac..793ba403 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
@@ -11,15 +11,16 @@
         {
           "position": [8, 68],
           "bounds": [302, 302],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [1, 1],
               "bounds": [285, 285],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 800],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
index 33ff673..9272994 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/clear-scroll-parent-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/clear-scroll-parent-expected.txt
index 24e6bde..b0f9331e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/clear-scroll-parent-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/clear-scroll-parent-expected.txt
@@ -9,15 +9,16 @@
         {
           "position": [8, 8],
           "bounds": [308, 208],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [4, 4],
               "bounds": [285, 200],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 530],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/composited-scrolling-paint-phases-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/composited-scrolling-paint-phases-expected.txt
index c44da56..d31f513 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/composited-scrolling-paint-phases-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/composited-scrolling-paint-phases-expected.txt
@@ -45,6 +45,7 @@
             {
               "position": [28, 20],
               "bounds": [202, 202],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "paintingPhases": [
                 "GraphicsLayerPaintBackground",
@@ -55,6 +56,7 @@
                 {
                   "position": [1, 1],
                   "bounds": [185, 185],
+                  "shouldFlattenTransform": false,
                   "paintingPhases": [
                     "GraphicsLayerPaintBackground",
                     "GraphicsLayerPaintForeground",
@@ -63,7 +65,6 @@
                   "children": [
                     {
                       "bounds": [185, 715],
-                      "shouldFlattenTransform": false,
                       "drawsContent": true,
                       "paintingPhases": [
                         "GraphicsLayerPaintForeground",
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/content-gains-scrollbars-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/content-gains-scrollbars-expected.txt
index aa0a47e..57415b7f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/content-gains-scrollbars-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/content-gains-scrollbars-expected.txt
@@ -9,14 +9,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [85, 100],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [85, 200],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [10, 200]
@@ -40,14 +41,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [100, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 85],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [200, 10]
@@ -71,14 +73,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 200],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [200, 200]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/overflow-scrollbar-layers-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/overflow-scrollbar-layers-expected.txt
index aa0a47e..57415b7f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/overflow-scrollbar-layers-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/overflow-scrollbar-layers-expected.txt
@@ -9,14 +9,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [85, 100],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [85, 200],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [10, 200]
@@ -40,14 +41,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [100, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 85],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [200, 10]
@@ -71,14 +73,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 200],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [200, 200]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
index de87e717..f89d82f8 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
@@ -24,14 +24,15 @@
                       "children": [
                         {
                           "bounds": [1200, 1000],
+                          "shouldFlattenTransform": false,
                           "drawsContent": true,
                           "children": [
                             {
                               "bounds": [1200, 1000],
+                              "shouldFlattenTransform": false,
                               "children": [
                                 {
                                   "bounds": [1200, 10000],
-                                  "shouldFlattenTransform": false,
                                   "drawsContent": true
                                 }
                               ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/scroll-parent-absolute-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/scroll-parent-absolute-expected.txt
index 545b2e7..a1d3349 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/scroll-parent-absolute-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/scroll-parent-absolute-expected.txt
@@ -13,15 +13,16 @@
               "position": [8, 8],
               "bounds": [500, 500],
               "contentsOpaque": true,
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "backgroundColor": "#0000FF",
               "children": [
                 {
                   "bounds": [485, 485],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [485, 5000],
-                      "shouldFlattenTransform": false,
                       "drawsContent": true
                     }
                   ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
index 3e92e6b8..c47f3ada 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
@@ -16,15 +16,16 @@
           "children": [
             {
               "bounds": [102, 102],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [1, 1],
                   "bounds": [100, 100],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
-                      "bounds": [100, 180],
-                      "shouldFlattenTransform": false
+                      "bounds": [100, 180]
                     }
                   ]
                 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
index f0c1146..94225b0cbb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
@@ -8,14 +8,15 @@
       "children": [
         {
           "bounds": [320, 340],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [305, 325],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [305, 1224],
-                  "shouldFlattenTransform": false
+                  "bounds": [305, 1224]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/scrolling-without-painting-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/scrolling-without-painting-expected.txt
index 3b5d109..9c59c47 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/scrolling-without-painting-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/scrolling-without-painting-expected.txt
@@ -9,15 +9,16 @@
         {
           "position": [8, 8],
           "bounds": [202, 202],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [1, 1],
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 1025],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
index 79dee4ad..ff16fcb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
@@ -25,15 +25,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -139,10 +140,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2481],
+  "bounds": [785, 2496],
   "children": [
     {
-      "bounds": [785, 2481],
+      "bounds": [785, 2496],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -150,15 +151,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -264,24 +266,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4356],
+  "bounds": [785, 4386],
   "children": [
     {
-      "bounds": [785, 4356],
+      "bounds": [785, 4386],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -386,24 +389,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6186],
+  "bounds": [785, 6231],
   "children": [
     {
-      "bounds": [785, 6186],
+      "bounds": [785, 6231],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/selection-gaps-toggling-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/selection-gaps-toggling-expected.txt
index 476204a..3ceba0314 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/selection-gaps-toggling-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/selection-gaps-toggling-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -136,24 +137,25 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2418],
+  "bounds": [785, 2433],
   "children": [
     {
-      "bounds": [785, 2418],
+      "bounds": [785, 2433],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -258,24 +260,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4248],
+  "bounds": [785, 4278],
   "children": [
     {
-      "bounds": [785, 4248],
+      "bounds": [785, 4278],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
index 154a301..3018a43 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -136,10 +137,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2436],
+  "bounds": [785, 2451],
   "children": [
     {
-      "bounds": [785, 2436],
+      "bounds": [785, 2451],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -147,15 +148,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -261,10 +263,10 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4311],
+  "bounds": [785, 4341],
   "children": [
     {
-      "bounds": [785, 4311],
+      "bounds": [785, 4341],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -272,15 +274,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -386,24 +389,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6186],
+  "bounds": [785, 6231],
   "children": [
     {
-      "bounds": [785, 6186],
+      "bounds": [785, 6231],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/textarea-scroll-touch-expected.txt
index 2ced3c6..4c696b6d3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,16 +11,17 @@
           "position": [18, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 308],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -46,16 +47,17 @@
           "position": [248, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 308],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
index 3da12b3..36918c7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
@@ -12,15 +12,16 @@
             {
               "position": [10, 10],
               "bounds": [104, 104],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [2, 2],
                   "bounds": [85, 85],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [85, 144],
-                      "shouldFlattenTransform": false,
                       "drawsContent": true
                     }
                   ]
@@ -74,15 +75,16 @@
         {
           "position": [130, 10],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [105, 144],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -132,15 +134,16 @@
             {
               "position": [250, 10],
               "bounds": [104, 104],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [2, 2],
                   "bounds": [85, 85],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
-                      "bounds": [85, 144],
-                      "shouldFlattenTransform": false
+                      "bounds": [85, 144]
                     }
                   ]
                 },
@@ -196,15 +199,16 @@
             {
               "position": [370, 10],
               "bounds": [104, 104],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [2, 2],
                   "bounds": [85, 85],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [85, 144],
-                      "shouldFlattenTransform": false,
                       "drawsContent": true
                     }
                   ]
@@ -258,15 +262,16 @@
         {
           "position": [10, 130],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [105, 144],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -316,15 +321,16 @@
             {
               "position": [130, 130],
               "bounds": [104, 104],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [2, 2],
                   "bounds": [85, 85],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
-                      "bounds": [85, 144],
-                      "shouldFlattenTransform": false
+                      "bounds": [85, 144]
                     }
                   ]
                 },
@@ -377,15 +383,16 @@
         {
           "position": [250, 130],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [105, 144],
-                  "shouldFlattenTransform": false
+                  "bounds": [105, 144]
                 }
               ]
             },
@@ -431,15 +438,16 @@
         {
           "position": [370, 130],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [105, 144],
-                  "shouldFlattenTransform": false
+                  "bounds": [105, 144]
                 }
               ]
             },
@@ -485,15 +493,16 @@
         {
           "position": [10, 250],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [85, 144],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -547,15 +556,16 @@
         {
           "position": [130, 250],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [85, 144],
-                  "shouldFlattenTransform": false
+                  "bounds": [85, 144]
                 }
               ]
             },
@@ -608,15 +618,16 @@
         {
           "position": [250, 250],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [85, 144],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -670,15 +681,16 @@
         {
           "position": [370, 250],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [85, 144],
-                  "shouldFlattenTransform": false
+                  "bounds": [85, 144]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/updating-scrolling-content-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/updating-scrolling-content-expected.txt
index 1411ec6..dd01697 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/updating-scrolling-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/overflow/updating-scrolling-content-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 0, 185, 200]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 1200],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 0, 185, 200]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
index 43d00ee..579784f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [500, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [-2000, -2000, 5000, 5000]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [485, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [5000, 5000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 0, 5000, 5000]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/scrollbars/nested-overlay-scrollbars-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/scrollbars/nested-overlay-scrollbars-expected.txt
index ece2a700..df69cd2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/scrollbars/nested-overlay-scrollbars-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/scrollbars/nested-overlay-scrollbars-expected.txt
@@ -9,29 +9,31 @@
         {
           "position": [8, 8],
           "bounds": [404, 404],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [400, 400],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [400, 704],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "children": [
                     {
                       "position": [0, 500],
                       "bounds": [204, 204],
+                      "shouldFlattenTransform": false,
                       "drawsContent": true,
                       "children": [
                         {
                           "position": [2, 2],
                           "bounds": [200, 200],
+                          "shouldFlattenTransform": false,
                           "children": [
                             {
                               "bounds": [5000, 9000],
-                              "shouldFlattenTransform": false,
                               "drawsContent": true
                             }
                           ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/squashing/composited-bounds-for-negative-z-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/squashing/composited-bounds-for-negative-z-expected.txt
index bee8371..7057cdf 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/squashing/composited-bounds-for-negative-z-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/squashing/composited-bounds-for-negative-z-expected.txt
@@ -23,14 +23,15 @@
             {
               "position": [108, 100],
               "bounds": [300, 300],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "bounds": [285, 300],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
-                      "bounds": [285, 1000],
-                      "shouldFlattenTransform": false
+                      "bounds": [285, 1000]
                     }
                   ]
                 },
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/update-paint-phases-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/update-paint-phases-expected.txt
index 9bd3514..b8ad8e91 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/update-paint-phases-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/update-paint-phases-expected.txt
@@ -19,6 +19,7 @@
         {
           "position": [8, 8],
           "bounds": [102, 102],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "paintingPhases": [
             "GraphicsLayerPaintBackground",
@@ -29,6 +30,7 @@
             {
               "position": [1, 1],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "paintingPhases": [
                 "GraphicsLayerPaintBackground",
                 "GraphicsLayerPaintForeground",
@@ -37,7 +39,6 @@
               "children": [
                 {
                   "bounds": [85, 120],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "paintingPhases": [
                     "GraphicsLayerPaintForeground",
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/box-shadow/basic-shadows-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/box-shadow/basic-shadows-expected.png
index 3e10dce..28e7842 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/box-shadow/basic-shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/box-shadow/basic-shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/css/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/css/shadow-multiple-expected.png
index a2d1e294..49b7864 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/css/shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/css/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
index 67774466..73835d0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
index b3b30e25..9f479b3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
index 65f3d536..825b96b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
index 438c3499..9d25818 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
index 3c7a15b7..522ddaf 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
index e9a206b..f86904c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
index af4e93c2..5ed861a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index 27f8cb5..8559ace 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
index db1965e..253c331 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/month-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/month-picker-appearance-expected.png
index 36513bcb..a917d24 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/month-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/month-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/month-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
index 606521a..abae747 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/week-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/week-picker-appearance-expected.png
index 0bb50668..7d571e4a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/week-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/week-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/week-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
index db4c9f56..62055e99 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/checkbox/checkbox-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/checkbox/checkbox-appearance-basic-expected.png
index e4e1be1..25657b7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/checkbox/checkbox-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/checkbox/checkbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/color/color-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/color/color-suggestion-picker-appearance-expected.png
index 45dde81..8899fba 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/color/color-suggestion-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/color/color-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
index 8c644b7..bda1d27 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
index d08db91..82a6fd5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
index f79806a5..2d8caf9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/input-appearance-height-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/input-appearance-height-expected.png
index d085f6b..5133d59 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/input-appearance-height-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/input-appearance-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/radio/radio-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/radio/radio-appearance-basic-expected.png
index f8755f3..8f85857 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/radio/radio-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/radio/radio-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/search/search-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/search/search-appearance-basic-expected.png
index d2cb102..cdbf0d85 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/search/search-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/search/search-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/select/listbox-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/select/listbox-appearance-basic-expected.png
index de37d0d..b730ab7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/select/listbox-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/select/listbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/select/menulist-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/select/menulist-appearance-basic-expected.png
index e62f90cf..76232d0c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/select/menulist-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/select/menulist-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/submit/submit-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/submit/submit-appearance-basic-expected.png
index 3cb6e28..e76f820 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/submit/submit-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/submit/submit-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/text/text-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/text/text-appearance-basic-expected.png
index 1b3312aa..caefb0ec 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/text/text-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/text/text-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/repaint/overflow-move-after-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/repaint/overflow-move-after-scroll-expected.txt
index 04f34ec..d439faa6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/repaint/overflow-move-after-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/repaint/overflow-move-after-scroll-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [10, 60],
           "bounds": [700, 400],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [300, 100, 120, 50],
@@ -17,10 +18,10 @@
           "children": [
             {
               "bounds": [685, 385],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [685, 600],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [300, 200, 120, 50],
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/repaint/overflow-scroll-after-move-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/repaint/overflow-scroll-after-move-expected.txt
index 8000cd2..60d03cb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/repaint/overflow-scroll-after-move-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/repaint/overflow-scroll-after-move-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [10, 60],
           "bounds": [300, 400],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [50, 160, 200, 50],
@@ -17,10 +18,10 @@
           "children": [
             {
               "bounds": [285, 385],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 900],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [50, 310, 200, 50],
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/text/shadow-translucent-fill-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/text/shadow-translucent-fill-expected.png
index c750e984..7f1d458f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/text/shadow-translucent-fill-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/text/shadow-translucent-fill-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/ietestcenter/css3/text/textshadow-003-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/ietestcenter/css3/text/textshadow-003-expected.png
index 90b9c30..c30fbfa 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/ietestcenter/css3/text/textshadow-003-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/ietestcenter/css3/text/textshadow-003-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/ietestcenter/css3/text/textshadow-004-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/ietestcenter/css3/text/textshadow-004-expected.png
index e351377b..35b02e3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/ietestcenter/css3/text/textshadow-004-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/ietestcenter/css3/text/textshadow-004-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/paint/invalidation/invalidate-after-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/paint/invalidation/invalidate-after-composited-scroll-expected.txt
index d4c77521..d62008bc 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/paint/invalidation/invalidate-after-composited-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/paint/invalidation/invalidate-after-composited-scroll-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [300, 300],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 50, 100, 100]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [185, 200],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 4900],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 2400, 100, 100]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/paint/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/paint/selection/selection-within-composited-scroller-expected.txt
index dc2e7c9..2cc30127 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/paint/selection/selection-within-composited-scroller-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/paint/selection/selection-within-composited-scroller-expected.txt
@@ -14,6 +14,7 @@
           "position": [8, 8],
           "bounds": [200, 200],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#D3D3D3",
           "repaintRects": [
@@ -25,10 +26,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 1620],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 610, 23, 18]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/plugins/webview-plugin-nested-iframe-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/plugins/webview-plugin-nested-iframe-scroll-expected.png
new file mode 100644
index 0000000..fd64cf1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/plugins/webview-plugin-nested-iframe-scroll-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/svg/wicd/test-scalable-background-image1-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/svg/wicd/test-scalable-background-image1-expected.png
index df65f40..348b05c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/svg/wicd/test-scalable-background-image1-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/svg/wicd/test-scalable-background-image1-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
index 33ff673..9272994 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt
index 24e6bde..b0f9331e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt
@@ -9,15 +9,16 @@
         {
           "position": [8, 8],
           "bounds": [308, 208],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [4, 4],
               "bounds": [285, 200],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 530],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/composited-scrolling-paint-phases-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/composited-scrolling-paint-phases-expected.txt
index c44da56..d31f513 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/composited-scrolling-paint-phases-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/composited-scrolling-paint-phases-expected.txt
@@ -45,6 +45,7 @@
             {
               "position": [28, 20],
               "bounds": [202, 202],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "paintingPhases": [
                 "GraphicsLayerPaintBackground",
@@ -55,6 +56,7 @@
                 {
                   "position": [1, 1],
                   "bounds": [185, 185],
+                  "shouldFlattenTransform": false,
                   "paintingPhases": [
                     "GraphicsLayerPaintBackground",
                     "GraphicsLayerPaintForeground",
@@ -63,7 +65,6 @@
                   "children": [
                     {
                       "bounds": [185, 715],
-                      "shouldFlattenTransform": false,
                       "drawsContent": true,
                       "paintingPhases": [
                         "GraphicsLayerPaintForeground",
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-gains-scrollbars-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-gains-scrollbars-expected.txt
index aa0a47e..57415b7f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-gains-scrollbars-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-gains-scrollbars-expected.txt
@@ -9,14 +9,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [85, 100],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [85, 200],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [10, 200]
@@ -40,14 +41,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [100, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 85],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [200, 10]
@@ -71,14 +73,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 200],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [200, 200]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-expected.txt
index 05c99ae5..316288127 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-expected.txt
@@ -9,14 +9,15 @@
         {
           "position": [8, 8],
           "bounds": [300, 300],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 285],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [1000, 1000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-toggle-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-toggle-expected.txt
index 05c99ae5..316288127 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-toggle-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-toggle-expected.txt
@@ -9,14 +9,15 @@
         {
           "position": [8, 8],
           "bounds": [300, 300],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 285],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [1000, 1000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-overlay-with-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-overlay-with-touch-expected.txt
index 05c99ae5..316288127 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-overlay-with-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-overlay-with-touch-expected.txt
@@ -9,14 +9,15 @@
         {
           "position": [8, 8],
           "bounds": [300, 300],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 285],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [1000, 1000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-scrollbar-layers-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-scrollbar-layers-expected.txt
index aa0a47e..57415b7f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-scrollbar-layers-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-scrollbar-layers-expected.txt
@@ -9,14 +9,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [85, 100],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [85, 200],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [10, 200]
@@ -40,14 +41,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [100, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 85],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [200, 10]
@@ -71,14 +73,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 200],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [200, 200]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
index de87e717..f89d82f8 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
@@ -24,14 +24,15 @@
                       "children": [
                         {
                           "bounds": [1200, 1000],
+                          "shouldFlattenTransform": false,
                           "drawsContent": true,
                           "children": [
                             {
                               "bounds": [1200, 1000],
+                              "shouldFlattenTransform": false,
                               "children": [
                                 {
                                   "bounds": [1200, 10000],
-                                  "shouldFlattenTransform": false,
                                   "drawsContent": true
                                 }
                               ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute-expected.txt
index 545b2e7..a1d3349 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute-expected.txt
@@ -13,15 +13,16 @@
               "position": [8, 8],
               "bounds": [500, 500],
               "contentsOpaque": true,
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "backgroundColor": "#0000FF",
               "children": [
                 {
                   "bounds": [485, 485],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [485, 5000],
-                      "shouldFlattenTransform": false,
                       "drawsContent": true
                     }
                   ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
index 3e92e6b8..c47f3ada 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
@@ -16,15 +16,16 @@
           "children": [
             {
               "bounds": [102, 102],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [1, 1],
                   "bounds": [100, 100],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
-                      "bounds": [100, 180],
-                      "shouldFlattenTransform": false
+                      "bounds": [100, 180]
                     }
                   ]
                 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
index f0c1146..94225b0cbb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
@@ -8,14 +8,15 @@
       "children": [
         {
           "bounds": [320, 340],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [305, 325],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [305, 1224],
-                  "shouldFlattenTransform": false
+                  "bounds": [305, 1224]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-without-painting-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-without-painting-expected.txt
index 3b5d109..9c59c47 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-without-painting-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-without-painting-expected.txt
@@ -9,15 +9,16 @@
         {
           "position": [8, 8],
           "bounds": [202, 202],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [1, 1],
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 1025],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
index 79dee4ad..ff16fcb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
@@ -25,15 +25,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -139,10 +140,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2481],
+  "bounds": [785, 2496],
   "children": [
     {
-      "bounds": [785, 2481],
+      "bounds": [785, 2496],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -150,15 +151,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -264,24 +266,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4356],
+  "bounds": [785, 4386],
   "children": [
     {
-      "bounds": [785, 4356],
+      "bounds": [785, 4386],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -386,24 +389,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6186],
+  "bounds": [785, 6231],
   "children": [
     {
-      "bounds": [785, 6186],
+      "bounds": [785, 6231],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt
index 476204a..3ceba0314 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -136,24 +137,25 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2418],
+  "bounds": [785, 2433],
   "children": [
     {
-      "bounds": [785, 2418],
+      "bounds": [785, 2433],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -258,24 +260,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4248],
+  "bounds": [785, 4278],
   "children": [
     {
-      "bounds": [785, 4248],
+      "bounds": [785, 4278],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
index 154a301..3018a43 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -136,10 +137,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2436],
+  "bounds": [785, 2451],
   "children": [
     {
-      "bounds": [785, 2436],
+      "bounds": [785, 2451],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -147,15 +148,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -261,10 +263,10 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4311],
+  "bounds": [785, 4341],
   "children": [
     {
-      "bounds": [785, 4311],
+      "bounds": [785, 4341],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -272,15 +274,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -386,24 +389,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6186],
+  "bounds": [785, 6231],
   "children": [
     {
-      "bounds": [785, 6186],
+      "bounds": [785, 6231],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt
index 85ad93d7..5ae74dc 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 57],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 0, 47, 615]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 615],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 0, 47, 615]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt
index f84961f..b1ced04b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt
@@ -16,6 +16,7 @@
         {
           "position": [0, 54],
           "bounds": [800, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [268, 0, 46, 18],
@@ -29,10 +30,10 @@
           "children": [
             {
               "bounds": [785, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [785, 1340],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [268, 0, 46, 18],
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
index 2ced3c6..4c696b6d3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,16 +11,17 @@
           "position": [18, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 308],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -46,16 +47,17 @@
           "position": [248, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 308],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
index 3da12b3..36918c7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
@@ -12,15 +12,16 @@
             {
               "position": [10, 10],
               "bounds": [104, 104],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [2, 2],
                   "bounds": [85, 85],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [85, 144],
-                      "shouldFlattenTransform": false,
                       "drawsContent": true
                     }
                   ]
@@ -74,15 +75,16 @@
         {
           "position": [130, 10],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [105, 144],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -132,15 +134,16 @@
             {
               "position": [250, 10],
               "bounds": [104, 104],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [2, 2],
                   "bounds": [85, 85],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
-                      "bounds": [85, 144],
-                      "shouldFlattenTransform": false
+                      "bounds": [85, 144]
                     }
                   ]
                 },
@@ -196,15 +199,16 @@
             {
               "position": [370, 10],
               "bounds": [104, 104],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [2, 2],
                   "bounds": [85, 85],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [85, 144],
-                      "shouldFlattenTransform": false,
                       "drawsContent": true
                     }
                   ]
@@ -258,15 +262,16 @@
         {
           "position": [10, 130],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [105, 144],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -316,15 +321,16 @@
             {
               "position": [130, 130],
               "bounds": [104, 104],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [2, 2],
                   "bounds": [85, 85],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
-                      "bounds": [85, 144],
-                      "shouldFlattenTransform": false
+                      "bounds": [85, 144]
                     }
                   ]
                 },
@@ -377,15 +383,16 @@
         {
           "position": [250, 130],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [105, 144],
-                  "shouldFlattenTransform": false
+                  "bounds": [105, 144]
                 }
               ]
             },
@@ -431,15 +438,16 @@
         {
           "position": [370, 130],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [105, 144],
-                  "shouldFlattenTransform": false
+                  "bounds": [105, 144]
                 }
               ]
             },
@@ -485,15 +493,16 @@
         {
           "position": [10, 250],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [85, 144],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -547,15 +556,16 @@
         {
           "position": [130, 250],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [85, 144],
-                  "shouldFlattenTransform": false
+                  "bounds": [85, 144]
                 }
               ]
             },
@@ -608,15 +618,16 @@
         {
           "position": [250, 250],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [85, 144],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -670,15 +681,16 @@
         {
           "position": [370, 250],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [85, 144],
-                  "shouldFlattenTransform": false
+                  "bounds": [85, 144]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt
index 7fbe5e6f..9398d44 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 108],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 167, 75, 18],
@@ -28,10 +29,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 234],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 216, 75, 18],
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-expected.txt
index b114bd1..57c1d874 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 108],
           "bounds": [210, 210],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 0, 210, 210]
@@ -20,10 +21,10 @@
             {
               "position": [5, 5],
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [400, 400],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [-5, -5, 210, 210]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-content-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-content-expected.txt
index 1411ec6..dd01697 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-content-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 0, 185, 200]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 1200],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 0, 185, 200]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
index 43d00ee..579784f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [500, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [-2000, -2000, 5000, 5000]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [485, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [5000, 5000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 0, 5000, 5000]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/fast/repaint/overflow-move-after-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/fast/repaint/overflow-move-after-scroll-expected.txt
index 04f34ec..d439faa6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/fast/repaint/overflow-move-after-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/fast/repaint/overflow-move-after-scroll-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [10, 60],
           "bounds": [700, 400],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [300, 100, 120, 50],
@@ -17,10 +18,10 @@
           "children": [
             {
               "bounds": [685, 385],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [685, 600],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [300, 200, 120, 50],
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/fast/repaint/overflow-scroll-after-move-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/fast/repaint/overflow-scroll-after-move-expected.txt
index 8000cd2..60d03cb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/fast/repaint/overflow-scroll-after-move-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/fast/repaint/overflow-scroll-after-move-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [10, 60],
           "bounds": [300, 400],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [50, 160, 200, 50],
@@ -17,10 +18,10 @@
           "children": [
             {
               "bounds": [285, 385],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 900],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [50, 310, 200, 50],
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/paint/invalidation/invalidate-after-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/paint/invalidation/invalidate-after-composited-scroll-expected.txt
index d4c77521..d62008bc 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/paint/invalidation/invalidate-after-composited-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/paint/invalidation/invalidate-after-composited-scroll-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [300, 300],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 50, 100, 100]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [185, 200],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 4900],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 2400, 100, 100]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt
index dc2e7c9..2cc30127 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt
@@ -14,6 +14,7 @@
           "position": [8, 8],
           "bounds": [200, 200],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#D3D3D3",
           "repaintRects": [
@@ -25,10 +26,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 1620],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 610, 23, 18]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/culling/scrolled-within-boxshadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/culling/scrolled-within-boxshadow-expected.png
deleted file mode 100644
index 4ebcb61..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/culling/scrolled-within-boxshadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/culling/translated-boxshadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/culling/translated-boxshadow-expected.png
deleted file mode 100644
index b6f8f6a..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/culling/translated-boxshadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/culling/unscrolled-within-boxshadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/culling/unscrolled-within-boxshadow-expected.png
deleted file mode 100644
index 4ebcb61..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/culling/unscrolled-within-boxshadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/clipping-foreground-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/clipping-foreground-expected.png
index a4275c3b..b4ecca1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/clipping-foreground-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/clipping-foreground-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/foreground-layer-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/foreground-layer-expected.png
deleted file mode 100644
index f6a2b529..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/foreground-layer-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/iframes/composited-iframe-alignment-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/iframes/composited-iframe-alignment-expected.png
index 933601ac..beebe39 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/iframes/composited-iframe-alignment-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/iframes/composited-iframe-alignment-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/masked-ancestor-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/masked-ancestor-expected.png
index 916eeb8d..bca8861e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/masked-ancestor-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/masked-ancestor-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
index da4ea44..63c3fb5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
@@ -25,15 +25,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -137,10 +138,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2451],
+  "bounds": [785, 2466],
   "children": [
     {
-      "bounds": [785, 2451],
+      "bounds": [785, 2466],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -148,15 +149,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -260,24 +262,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4296],
+  "bounds": [785, 4326],
   "children": [
     {
-      "bounds": [785, 4296],
+      "bounds": [785, 4326],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -380,24 +383,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6096],
+  "bounds": [785, 6141],
   "children": [
     {
-      "bounds": [785, 6096],
+      "bounds": [785, 6141],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/selection-gaps-toggling-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/selection-gaps-toggling-expected.txt
index 9b101a4..2adaf001 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/selection-gaps-toggling-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/selection-gaps-toggling-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -134,24 +135,25 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2388],
+  "bounds": [785, 2403],
   "children": [
     {
-      "bounds": [785, 2388],
+      "bounds": [785, 2403],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -254,24 +256,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4188],
+  "bounds": [785, 4218],
   "children": [
     {
-      "bounds": [785, 4188],
+      "bounds": [785, 4218],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
index 69734cb..8760b3d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -134,10 +135,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2406],
+  "bounds": [785, 2421],
   "children": [
     {
-      "bounds": [785, 2406],
+      "bounds": [785, 2421],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -145,15 +146,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -257,10 +259,10 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4251],
+  "bounds": [785, 4281],
   "children": [
     {
-      "bounds": [785, 4251],
+      "bounds": [785, 4281],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -268,15 +270,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -380,24 +383,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6096],
+  "bounds": [785, 6141],
   "children": [
     {
-      "bounds": [785, 6096],
+      "bounds": [785, 6141],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/textarea-scroll-touch-expected.txt
index 75ac18e..e023c562d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,16 +11,17 @@
           "position": [18, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 270],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -45,16 +46,17 @@
           "position": [248, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 270],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
index ee3d294..c45f25aa 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [500, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [-2000, -2000, 5000, 5000]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [485, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [5000, 5000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 0, 5000, 5000]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/shadows/shadow-drawing-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/shadows/shadow-drawing-expected.png
index a400b374..b19c51bb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/shadows/shadow-drawing-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/shadows/shadow-drawing-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/squashing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/squashing/iframe-inside-squashed-layer-expected.txt
index 216140d8..43c17a1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/squashing/iframe-inside-squashed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/squashing/iframe-inside-squashed-layer-expected.txt
@@ -39,8 +39,8 @@
                 "LayoutView #document",
                 "LayoutBlockFlow HTML",
                 "LayoutBlockFlow BODY",
-                "VerticalScrollbar",
-                "LayoutView #document"
+                "LayoutView #document",
+                "VerticalScrollbar"
               ]
             }
           ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css2.1/20110323/background-intrinsic-004-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css2.1/20110323/background-intrinsic-004-expected.png
index 01b8d3c..f3b1064 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css2.1/20110323/background-intrinsic-004-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css2.1/20110323/background-intrinsic-004-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-canvas-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-canvas-with-shadow-expected.png
index 7ede3a8b..e13d1c3c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-canvas-with-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-canvas-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-shadow-expected.png
index 55f23d37..fca45167 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-split-inline-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-split-inline-expected.png
index 4f04469..9914a2c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-split-inline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-split-inline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/basic-shadows-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/basic-shadows-expected.png
index cf1728b..31df05f8 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/basic-shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/basic-shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-expected.png
index 1d1d049..cf3038e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-transformed-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-transformed-expected.png
index 9e41c63..c06e0219 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-transformed-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-transformed-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-expected.png
index 3387f96..06a7610 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-subpixel-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-subpixel-expected.png
index 6faa863..3d9bf12 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-subpixel-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-subpixel-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/scaled-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/scaled-box-shadow-expected.png
deleted file mode 100644
index 715ea1f..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/scaled-box-shadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/shadow-buffer-partial-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/shadow-buffer-partial-expected.png
deleted file mode 100644
index efab88e..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/shadow-buffer-partial-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/single-pixel-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/single-pixel-shadow-expected.png
deleted file mode 100644
index fe6fcd5..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/single-pixel-shadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-composite-shadow-expected.png
index 21ce7a8..0720e0c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-incremental-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-incremental-repaint-expected.png
index fe35edd8..aed138d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-incremental-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-incremental-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-shadow-source-in-expected.png
index 6dcdb8e1..47e5a36 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-shadow-source-in-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-shadow-source-in-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/css/color-correction-on-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/css/color-correction-on-box-shadow-expected.png
index ab81d471d0..b86666f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/css/color-correction-on-box-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/css/color-correction-on-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/css/color-correction-on-text-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/css/color-correction-on-text-shadow-expected.png
index 4714683..37835e3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/css/color-correction-on-text-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/css/color-correction-on-text-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/css/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/css/shadow-multiple-expected.png
index 4045dc3..7c21bb7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/css/shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/css/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/dom/HTMLInputElement/input-slider-update-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/dom/HTMLInputElement/input-slider-update-expected.png
index 7e7e9cd4..6f87bcb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/dom/HTMLInputElement/input-slider-update-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/dom/HTMLInputElement/input-slider-update-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/dom/HTMLMeterElement/meter-styles-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/dom/HTMLMeterElement/meter-styles-expected.png
index 2fe73c7..29d1f4f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/dom/HTMLMeterElement/meter-styles-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/dom/HTMLMeterElement/meter-styles-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
index 66456c5f..fa8bf66 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
index b9c3a55..6813dbf 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
index b31243a..5ba412ae 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
index f678ff0..02d4dd1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
index 171028d4..9d5883e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
index a5f09481..e15ab94 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
index 65cad2e..57b0b32 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index e3273e44..f544bcb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
index 8407367..1c54dced 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/month-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/month-picker-appearance-expected.png
index 98a38286..2854537 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/month-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/month-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/month-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
index 35e92a3..8a7192b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/week-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/week-picker-appearance-expected.png
index f8f27f21..64fb12d2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/week-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/week-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/week-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
index 99703fdd..70b6ee08 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/checkbox/checkbox-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/checkbox/checkbox-appearance-basic-expected.png
index 23d3469..b57b9c2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/checkbox/checkbox-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/checkbox/checkbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-appearance-expected.png
index 2525a13..62370cf 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
index 6e8a329..592c3bae 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
index 851e4582..24efd68 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
index b26cff9d..861b9dc 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
index 6a3784c..a83f4be 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
index 523d414..ef196383 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-expected.png
index a04d2b9..70acb54d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
index d161adb..66ceb3b9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png
index 0291ae5..fc3d074 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-transform-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-transform-expected.png
index a473192..d05166b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-transform-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-transform-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/input-appearance-height-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/input-appearance-height-expected.png
index 18bad50..2c54fd6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/input-appearance-height-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/input-appearance-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/radio/radio-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/radio/radio-appearance-basic-expected.png
index db0eb09..f99ffa2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/radio/radio-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/radio/radio-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/input-appearance-range-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/input-appearance-range-expected.png
index b91ddbe..bb1f6c07 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/input-appearance-range-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/input-appearance-range-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/range-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/range-appearance-basic-expected.png
index d3153fd..8fcb7cec 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/range-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/range-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/range-focus-by-mouse-then-keydown-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/range-focus-by-mouse-then-keydown-expected.png
index f850aea..1e2cd9a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/range-focus-by-mouse-then-keydown-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/range-focus-by-mouse-then-keydown-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/slider-padding-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/slider-padding-expected.png
index c6ae8fd..b27759b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/slider-padding-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/slider-padding-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/slider-thumb-shared-style-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/slider-thumb-shared-style-expected.png
index cf19a56..410ce729 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/slider-thumb-shared-style-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/slider-thumb-shared-style-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/thumbslider-no-parent-slider-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/thumbslider-no-parent-slider-expected.png
index 04fe7791..18142b7fe 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/thumbslider-no-parent-slider-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/thumbslider-no-parent-slider-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/search/search-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/search/search-appearance-basic-expected.png
index 2f92a0c0..72ad1db 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/search/search-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/search/search-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/listbox-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/listbox-appearance-basic-expected.png
index 080ca278..3a582bf 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/listbox-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/listbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/menulist-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/menulist-appearance-basic-expected.png
index 558816f..1ad8543 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/menulist-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/menulist-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/submit/submit-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/submit/submit-appearance-basic-expected.png
index cceceaa..9c3850bd 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/submit/submit-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/submit/submit-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/text/text-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/text/text-appearance-basic-expected.png
index 1d05919..b4eac386 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/text/text-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/text/text-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/textarea/textarea-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/textarea/textarea-appearance-basic-expected.png
index b8d467c..8dfd803 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/textarea/textarea-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/textarea/textarea-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/details-open-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/details-open-repaint-expected.txt
index 1767b18..1c8cdee 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/details-open-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/details-open-repaint-expected.txt
@@ -16,9 +16,10 @@
         "LayoutBlockFlow DIV id='details-content'",
         "LayoutTextControl INPUT",
         "LayoutBlockFlow DIV id='inner-editor'",
-        "HorizontalScrollbar",
-        "VerticalScrollbar",
         "LayoutBlockFlow DIV id='inner-editor'",
+        "HorizontalScrollbar",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "VerticalScrollbar",
         "LayoutText #text",
         "LayoutText #text"
       ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/japanese-rl-selection-clear-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/japanese-rl-selection-clear-expected.txt
index cd413be..9ccf8bb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/japanese-rl-selection-clear-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/japanese-rl-selection-clear-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [387, 123, 385, 392]
+        [387, 123, 385, 399]
       ],
       "paintInvalidationClients": [
         "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/japanese-rl-selection-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/japanese-rl-selection-repaint-expected.txt
index f8d5e71..1de0bc05 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/japanese-rl-selection-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/japanese-rl-selection-repaint-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [420, 23, 352, 553]
+        [420, 23, 352, 560]
       ],
       "paintInvalidationClients": [
         "LayoutBlockFlow HTML",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-9-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-9-expected.txt
index 8f7d6cf8..196a8e53 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-9-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-9-expected.txt
@@ -140,8 +140,8 @@
         "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
         "InlineTextBox 'here; the great\n'",
         "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-        "VerticalScrollbar",
-        "LayoutView #document"
+        "LayoutView #document",
+        "VerticalScrollbar"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/resize-scrollable-iframe-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/resize-scrollable-iframe-expected.txt
index 3142a2ea..5b7319c0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/resize-scrollable-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/resize-scrollable-iframe-expected.txt
@@ -28,9 +28,10 @@
         "LayoutIFrame IFRAME id='iframe'",
         "LayoutView #document",
         "LayoutView #document",
+        "LayoutView #document",
         "HorizontalScrollbar",
-        "VerticalScrollbar",
-        "LayoutView #document"
+        "LayoutView #document",
+        "VerticalScrollbar"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/shadow-multiple-expected.png
index 278b33ad..11d37bfd 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/slider-thumb-drag-release-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/slider-thumb-drag-release-expected.png
index 7e7e9cd4..6f87bcb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/slider-thumb-drag-release-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/slider-thumb-drag-release-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/shadow-translucent-fill-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/text/shadow-translucent-fill-expected.png
index e765c7ec..b062cc5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/text/shadow-translucent-fill-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/shadow-translucent-fill-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/stroking-decorations-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/text/stroking-decorations-expected.png
index 382c5db..f2f71a48 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/text/stroking-decorations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/stroking-decorations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/stroking-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/text/stroking-expected.png
index 8761075..01e5e8bf 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/text/stroking-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/stroking-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/transforms/shadows-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/transforms/shadows-expected.png
index da937a2..9c43dc22 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/transforms/shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/transforms/shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/writing-mode/english-lr-text-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/writing-mode/english-lr-text-expected.png
index 75d22960..84eba8f4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/writing-mode/english-lr-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/writing-mode/english-lr-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/writing-mode/japanese-lr-selection-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/writing-mode/japanese-lr-selection-expected.png
index fd735395..825cc947 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/writing-mode/japanese-lr-selection-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/writing-mode/japanese-lr-selection-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/writing-mode/japanese-rl-selection-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/writing-mode/japanese-rl-selection-expected.png
index 4f5657c..e8f0113 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/writing-mode/japanese-rl-selection-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/writing-mode/japanese-rl-selection-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-001-expected.png b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-001-expected.png
index 7dc0de0..3aca52f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-001-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-001-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-002-expected.png b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-002-expected.png
index e98a33d8..be5f2d9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-002-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-002-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-003-expected.png b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-003-expected.png
index 3f84f2b..c2f32db 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-003-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-003-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-004-expected.png b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-004-expected.png
index 8cb2c51e..f3f0e6e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-004-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-004-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-010-expected.png b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-010-expected.png
index 96c0f21e..8bb969e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-010-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/text/textshadow-010-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/roundedrects/circle-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/roundedrects/circle-with-shadow-expected.png
index e1f67c0..efefbf6d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/roundedrects/circle-with-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/roundedrects/circle-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
index 6d46f6e..40080e17 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/selection/selection-within-composited-scroller-expected.txt
index 43c49b4..8e8c646 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/selection/selection-within-composited-scroller-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/selection/selection-within-composited-scroller-expected.txt
@@ -14,6 +14,7 @@
           "position": [8, 8],
           "bounds": [200, 200],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#D3D3D3",
           "repaintRects": [
@@ -25,10 +26,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 1620],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 610, 23, 18]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/plugins/webview-plugin-nested-iframe-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/mac/plugins/webview-plugin-nested-iframe-scroll-expected.png
new file mode 100644
index 0000000..d333639
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/plugins/webview-plugin-nested-iframe-scroll-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/plugins/webview-plugin-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/mac/plugins/webview-plugin-scroll-expected.png
new file mode 100644
index 0000000..035d1b9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/plugins/webview-plugin-scroll-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-gradient-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-gradient-shadow-expected.png
index bef2a409..fa6ad36 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-gradient-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-gradient-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-shadow-multiple-expected.png
index bea282d..905bae01 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/repaint-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/repaint-shadow-expected.png
index 49bf3d3..5df5ed1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/repaint-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/repaint-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/wicd/test-scalable-background-image1-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/wicd/test-scalable-background-image1-expected.png
index 3b54e4c..60334b1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/wicd/test-scalable-background-image1-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/wicd/test-scalable-background-image1-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-background-images-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-background-images-expected.png
index 9013d9e..32924f43 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-background-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-background-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
index 21ce7a8..0720e0c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
index fe35edd8..aed138d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png
index 6dcdb8e1..47e5a36 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-composite-shadow-expected.png
index 8ec79349..d7016fd 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-incremental-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-incremental-repaint-expected.png
index 64c0f5c..635d1144 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-incremental-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-incremental-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-shadow-source-in-expected.png
index 32e0d70..2423c30 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-shadow-source-in-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-shadow-source-in-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
index da4ea44..63c3fb5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
@@ -25,15 +25,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -137,10 +138,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2451],
+  "bounds": [785, 2466],
   "children": [
     {
-      "bounds": [785, 2451],
+      "bounds": [785, 2466],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -148,15 +149,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -260,24 +262,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4296],
+  "bounds": [785, 4326],
   "children": [
     {
-      "bounds": [785, 4296],
+      "bounds": [785, 4326],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -380,24 +383,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6096],
+  "bounds": [785, 6141],
   "children": [
     {
-      "bounds": [785, 6096],
+      "bounds": [785, 6141],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt
index 9b101a4..2adaf001 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -134,24 +135,25 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2388],
+  "bounds": [785, 2403],
   "children": [
     {
-      "bounds": [785, 2388],
+      "bounds": [785, 2403],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -254,24 +256,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4188],
+  "bounds": [785, 4218],
   "children": [
     {
-      "bounds": [785, 4188],
+      "bounds": [785, 4218],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
index 69734cb..8760b3d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -134,10 +135,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2406],
+  "bounds": [785, 2421],
   "children": [
     {
-      "bounds": [785, 2406],
+      "bounds": [785, 2421],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -145,15 +146,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -257,10 +259,10 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4251],
+  "bounds": [785, 4281],
   "children": [
     {
-      "bounds": [785, 4251],
+      "bounds": [785, 4281],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -268,15 +270,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -380,24 +383,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6096],
+  "bounds": [785, 6141],
   "children": [
     {
-      "bounds": [785, 6096],
+      "bounds": [785, 6141],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt
index 05b1990c..1674497 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 57],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 0, 47, 615]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 615],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 0, 47, 615]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt
index 4b8e7e4..54f110c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt
@@ -16,6 +16,7 @@
         {
           "position": [0, 54],
           "bounds": [800, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [268, 0, 46, 18],
@@ -29,10 +30,10 @@
           "children": [
             {
               "bounds": [785, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [785, 1340],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [268, 0, 46, 18],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
index 75ac18e..e023c562d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,16 +11,17 @@
           "position": [18, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 270],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -45,16 +46,17 @@
           "position": [248, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 270],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt
index 6a84b252..c54365e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 108],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 167, 75, 18],
@@ -28,10 +29,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 234],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 216, 75, 18],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/spv2/paint/roundedrects/circle-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/spv2/paint/roundedrects/circle-with-shadow-expected.png
new file mode 100644
index 0000000..efefbf6d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/spv2/paint/roundedrects/circle-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/spv2/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/spv2/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
new file mode 100644
index 0000000..40080e17
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/spv2/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
index ee3d294..c45f25aa 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [500, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [-2000, -2000, 5000, 5000]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [485, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [5000, 5000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 0, 5000, 5000]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt
index 1767b18..1c8cdee 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt
@@ -16,9 +16,10 @@
         "LayoutBlockFlow DIV id='details-content'",
         "LayoutTextControl INPUT",
         "LayoutBlockFlow DIV id='inner-editor'",
-        "HorizontalScrollbar",
-        "VerticalScrollbar",
         "LayoutBlockFlow DIV id='inner-editor'",
+        "HorizontalScrollbar",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "VerticalScrollbar",
         "LayoutText #text",
         "LayoutText #text"
       ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/japanese-rl-selection-clear-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/japanese-rl-selection-clear-expected.txt
index cd413be..9ccf8bb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/japanese-rl-selection-clear-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/japanese-rl-selection-clear-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [387, 123, 385, 392]
+        [387, 123, 385, 399]
       ],
       "paintInvalidationClients": [
         "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/japanese-rl-selection-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/japanese-rl-selection-repaint-expected.txt
index f8d5e71..1de0bc05 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/japanese-rl-selection-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/japanese-rl-selection-repaint-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [420, 23, 352, 553]
+        [420, 23, 352, 560]
       ],
       "paintInvalidationClients": [
         "LayoutBlockFlow HTML",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/line-flow-with-floats-9-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/line-flow-with-floats-9-expected.txt
index 8f7d6cf8..196a8e53 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/line-flow-with-floats-9-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/line-flow-with-floats-9-expected.txt
@@ -140,8 +140,8 @@
         "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
         "InlineTextBox 'here; the great\n'",
         "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-        "VerticalScrollbar",
-        "LayoutView #document"
+        "LayoutView #document",
+        "VerticalScrollbar"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/overflow-move-after-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/overflow-move-after-scroll-expected.txt
index 67397b3a..8197a75f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/overflow-move-after-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/overflow-move-after-scroll-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [10, 60],
           "bounds": [700, 400],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [300, 100, 120, 50],
@@ -17,10 +18,10 @@
           "children": [
             {
               "bounds": [685, 385],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [685, 600],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [300, 200, 120, 50],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/overflow-scroll-after-move-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/overflow-scroll-after-move-expected.txt
index d4e783d..7a74da9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/overflow-scroll-after-move-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/overflow-scroll-after-move-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [10, 60],
           "bounds": [300, 400],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [50, 160, 200, 50],
@@ -17,10 +18,10 @@
           "children": [
             {
               "bounds": [285, 385],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 900],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [50, 310, 200, 50],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/resize-scrollable-iframe-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/resize-scrollable-iframe-expected.txt
index 3142a2ea..5b7319c0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/resize-scrollable-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/resize-scrollable-iframe-expected.txt
@@ -28,9 +28,10 @@
         "LayoutIFrame IFRAME id='iframe'",
         "LayoutView #document",
         "LayoutView #document",
+        "LayoutView #document",
         "HorizontalScrollbar",
-        "VerticalScrollbar",
-        "LayoutView #document"
+        "LayoutView #document",
+        "VerticalScrollbar"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png
new file mode 100644
index 0000000..11d37bfd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/slider-thumb-drag-release-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/slider-thumb-drag-release-expected.png
index 7e7e9cd4..6f87bcb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/slider-thumb-drag-release-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/slider-thumb-drag-release-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/paint/invalidation/invalidate-after-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/paint/invalidation/invalidate-after-composited-scroll-expected.txt
index 7a475c6..c46d6c2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/paint/invalidation/invalidate-after-composited-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/paint/invalidation/invalidate-after-composited-scroll-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [300, 300],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 50, 100, 100]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [185, 200],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 4900],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 2400, 100, 100]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/paint/roundedrects/circle-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/paint/roundedrects/circle-with-shadow-expected.png
new file mode 100644
index 0000000..efefbf6d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/paint/roundedrects/circle-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
new file mode 100644
index 0000000..40080e17
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt
index 43c49b4..8e8c646 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt
@@ -14,6 +14,7 @@
           "position": [8, 8],
           "bounds": [200, 200],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#D3D3D3",
           "repaintRects": [
@@ -25,10 +26,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 1620],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 610, 23, 18]
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/geometry/clipping-foreground-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/geometry/clipping-foreground-expected.png
index 943aa5d..864ea47 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/geometry/clipping-foreground-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/geometry/clipping-foreground-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png
index 0bbd60b9..18acd4c 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/iframes/composited-iframe-alignment-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/iframes/composited-iframe-alignment-expected.png
index ab506a1..37fc17b 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/iframes/composited-iframe-alignment-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/iframes/composited-iframe-alignment-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
index 290b2c179..782a82c 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
@@ -11,15 +11,16 @@
         {
           "position": [8, 72],
           "bounds": [302, 302],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [1, 1],
               "bounds": [285, 285],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 800],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/masks/masked-ancestor-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/masks/masked-ancestor-expected.png
index 2f4364b5..62d59fe 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/masks/masked-ancestor-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/masks/masked-ancestor-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
index b85a763..f4e88a0 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
@@ -25,15 +25,16 @@
           "position": [8, 68],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -137,10 +138,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2562],
+  "bounds": [785, 2578],
   "children": [
     {
-      "bounds": [785, 2562],
+      "bounds": [785, 2578],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -148,15 +149,16 @@
           "position": [8, 68],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -260,24 +262,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4530],
+  "bounds": [785, 4562],
   "children": [
     {
-      "bounds": [785, 4530],
+      "bounds": [785, 4562],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -380,24 +383,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6450],
+  "bounds": [785, 6498],
   "children": [
     {
-      "bounds": [785, 6450],
+      "bounds": [785, 6498],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/overflow/selection-gaps-toggling-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/overflow/selection-gaps-toggling-expected.txt
index 4a47763..7bb7d757 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/overflow/selection-gaps-toggling-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/overflow/selection-gaps-toggling-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -134,24 +135,25 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2514],
+  "bounds": [785, 2530],
   "children": [
     {
-      "bounds": [785, 2514],
+      "bounds": [785, 2530],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -254,24 +256,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4434],
+  "bounds": [785, 4466],
   "children": [
     {
-      "bounds": [785, 4434],
+      "bounds": [785, 4466],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
index d6996d2..f6d489f 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -134,10 +135,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2514],
+  "bounds": [785, 2530],
   "children": [
     {
-      "bounds": [785, 2514],
+      "bounds": [785, 2530],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -145,15 +146,16 @@
           "position": [8, 68],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -257,10 +259,10 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4482],
+  "bounds": [785, 4514],
   "children": [
     {
-      "bounds": [785, 4482],
+      "bounds": [785, 4514],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -268,15 +270,16 @@
           "position": [8, 68],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -380,24 +383,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6450],
+  "bounds": [785, 6498],
   "children": [
     {
-      "bounds": [785, 6450],
+      "bounds": [785, 6498],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/overflow/textarea-scroll-touch-expected.txt
index ebcfe549..7569bf1 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,16 +11,17 @@
           "position": [18, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 328],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -45,16 +46,17 @@
           "position": [248, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 328],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
index ee3d294..c45f25aa 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [500, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [-2000, -2000, 5000, 5000]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [485, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [5000, 5000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 0, 5000, 5000]
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/shadows/shadow-drawing-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/shadows/shadow-drawing-expected.png
index bcf2ca52..c9270d9 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/shadows/shadow-drawing-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/shadows/shadow-drawing-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/squashing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/squashing/iframe-inside-squashed-layer-expected.txt
index 66fecc6..c727fa03 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/squashing/iframe-inside-squashed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/squashing/iframe-inside-squashed-layer-expected.txt
@@ -39,8 +39,8 @@
                 "LayoutView #document",
                 "LayoutBlockFlow HTML",
                 "LayoutBlockFlow BODY",
-                "VerticalScrollbar",
-                "LayoutView #document"
+                "LayoutView #document",
+                "VerticalScrollbar"
               ]
             }
           ]
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/css2.1/20110323/background-intrinsic-004-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/css2.1/20110323/background-intrinsic-004-expected.png
index d6a2bc9..17a36b597 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/css2.1/20110323/background-intrinsic-004-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/css2.1/20110323/background-intrinsic-004-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/borders/border-radius-mask-canvas-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/borders/border-radius-mask-canvas-with-shadow-expected.png
index f6e4953..3f8539b 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/borders/border-radius-mask-canvas-with-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/borders/border-radius-mask-canvas-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/borders/border-radius-mask-video-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/borders/border-radius-mask-video-shadow-expected.png
index 13d9428..e8dcf33 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/borders/border-radius-mask-video-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/borders/border-radius-mask-video-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/borders/border-radius-split-inline-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/borders/border-radius-split-inline-expected.png
index 8f301dd..affcc26 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/borders/border-radius-split-inline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/borders/border-radius-split-inline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/basic-shadows-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/basic-shadows-expected.png
index e3ecb8a..4d97e58 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/basic-shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/basic-shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/box-shadow-expected.png
index 0533bc3..1d177cf 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/box-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/box-shadow-transformed-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/box-shadow-transformed-expected.png
index bf66b12..210347c1 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/box-shadow-transformed-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/box-shadow-transformed-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-box-shadow-radius-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-box-shadow-radius-expected.png
index 4beed5fa..0c69f85 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-box-shadow-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-box-shadow-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-box-shadows-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-box-shadows-expected.png
index 1f611b8..c979a34 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-box-shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-box-shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-expected.png
index 4ed0cde..ce0e1a8 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-subpixel-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-subpixel-expected.png
index ff7699c1..4e5b6ca2 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-subpixel-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-subpixel-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/canvas/canvas-composite-shadow-expected.png
index 801b131..6162a23 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/canvas/canvas-incremental-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/canvas/canvas-incremental-repaint-expected.png
index 3fd19e7..50d10e5 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/canvas/canvas-incremental-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/canvas/canvas-incremental-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/canvas/canvas-shadow-source-in-expected.png
index cbaefe7..93a2e0a9 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/canvas/canvas-shadow-source-in-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/canvas/canvas-shadow-source-in-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/css/color-correction-on-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/css/color-correction-on-box-shadow-expected.png
index f3b119a..e48d5f0 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/css/color-correction-on-box-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/css/color-correction-on-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/css/color-correction-on-text-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/css/color-correction-on-text-shadow-expected.png
index db304f6..4910b41e 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/css/color-correction-on-text-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/css/color-correction-on-text-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/css/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/css/shadow-multiple-expected.png
index d26b7ba..f96be81 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/css/shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/css/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/dom/HTMLMeterElement/meter-styles-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/dom/HTMLMeterElement/meter-styles-expected.png
index 75c3d7f..b83333f 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/dom/HTMLMeterElement/meter-styles-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/dom/HTMLMeterElement/meter-styles-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
index 85eba515..0e20ecc 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
index 80d551b..d7c1e988 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
index 74c4259..7c9113f4 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
index 16e58ab4..97b09bd19 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
index 58b2937..db1b375f 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
index a93dc0a..e20e27b 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
index 13f1ae7..e9e295e9 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index f7a502c5a..bb659cf 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
index 23b46f6..19f4e9f 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/month-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/month-picker-appearance-expected.png
index 18c52c8..69e4a3f 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/month-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/month-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/month-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
index f32d47b..5180f1d5 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/week-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/week-picker-appearance-expected.png
index b42a5927..116d2b4 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/week-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/week-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/week-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
index 0f64ebdf..5b650a2 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/checkbox/checkbox-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/checkbox/checkbox-appearance-basic-expected.png
index 076c06a0..9b620d1 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/checkbox/checkbox-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/checkbox/checkbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
index 9a16851c..cb436e3 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
index 6a7e64e..f800f94 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
index 792bad1..36dcd69 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/radio/radio-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/radio/radio-appearance-basic-expected.png
index 2b87326..50295ea 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/radio/radio-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/radio/radio-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/range/range-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/range/range-appearance-basic-expected.png
index 642bb7bc..b61ca39 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/range/range-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/range/range-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/search/search-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/search/search-appearance-basic-expected.png
index a34a252..afb196a 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/search/search-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/search/search-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/select/listbox-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/select/listbox-appearance-basic-expected.png
index 3fdf6eb..9c5379ab 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/select/listbox-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/select/listbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/select/menulist-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/select/menulist-appearance-basic-expected.png
index c152328..3042b23 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/select/menulist-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/select/menulist-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/submit/submit-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/submit/submit-appearance-basic-expected.png
index 93a56b0e..4802f1f 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/submit/submit-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/submit/submit-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/text/text-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/text/text-appearance-basic-expected.png
index 23594ec..6fbd080 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/text/text-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/text/text-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/textarea/textarea-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/textarea/textarea-appearance-basic-expected.png
index a458ee1..bf187fdd 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/textarea/textarea-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/forms/textarea/textarea-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/details-open-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/details-open-repaint-expected.txt
index fbce702..e1d66101 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/details-open-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/details-open-repaint-expected.txt
@@ -16,9 +16,10 @@
         "LayoutBlockFlow DIV id='details-content'",
         "LayoutTextControl INPUT",
         "LayoutBlockFlow DIV id='inner-editor'",
-        "HorizontalScrollbar",
-        "VerticalScrollbar",
         "LayoutBlockFlow DIV id='inner-editor'",
+        "HorizontalScrollbar",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "VerticalScrollbar",
         "LayoutText #text",
         "LayoutText #text"
       ]
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/overflow-scroll-body-appear-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/overflow-scroll-body-appear-expected.txt
index 72c6d6b..1d10dc8 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/overflow-scroll-body-appear-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/overflow-scroll-body-appear-expected.txt
@@ -7,11 +7,13 @@
       "drawsContent": true,
       "repaintRects": [
         [785, 585, 15, 15],
+        [785, 0, 15, 585],
         [8, 52, 784, 20],
         [8, 52, 769, 20],
         [8, 16, 2000, 2072],
         [8, 16, 784, 20],
         [8, 16, 769, 20],
+        [0, 585, 785, 15],
         [0, 0, 2008, 2096],
         [0, 0, 785, 585]
       ],
@@ -27,8 +29,8 @@
         "LayoutBlockFlow BODY",
         "LayoutBlockFlow P",
         "LayoutBlockFlow P",
-        "HorizontalScrollbar",
-        "VerticalScrollbar"
+        "LayoutView #document",
+        "LayoutView #document"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/resize-scrollable-iframe-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/resize-scrollable-iframe-expected.txt
index 3949115..0a84efca 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/resize-scrollable-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/resize-scrollable-iframe-expected.txt
@@ -28,9 +28,10 @@
         "LayoutIFrame IFRAME id='iframe'",
         "LayoutView #document",
         "LayoutView #document",
+        "LayoutView #document",
         "HorizontalScrollbar",
-        "VerticalScrollbar",
-        "LayoutView #document"
+        "LayoutView #document",
+        "VerticalScrollbar"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/shadow-multiple-expected.png
index ccd7c8e..9515e2d 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/shadow-translucent-fill-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/shadow-translucent-fill-expected.png
index 549b741..8060544 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/shadow-translucent-fill-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/shadow-translucent-fill-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/stroking-decorations-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/stroking-decorations-expected.png
index 8e7ae67..f2a47c5 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/stroking-decorations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/stroking-decorations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/stroking-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/stroking-expected.png
index 8645c09..4dcfd1a 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/stroking-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/stroking-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/transforms/shadows-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/transforms/shadows-expected.png
index 52c8d638..c4dfb2b 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/transforms/shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/transforms/shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/writing-mode/english-lr-text-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/writing-mode/english-lr-text-expected.png
index b9c278e4..99a6b4bc 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/writing-mode/english-lr-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/writing-mode/english-lr-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-001-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-001-expected.png
index c7e5031..3b3d6b7a 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-001-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-001-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-002-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-002-expected.png
index 41c529c..3b3d6b7a 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-002-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-002-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-003-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-003-expected.png
index 1752e2f..3b3d6b7a 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-003-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-003-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-004-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-004-expected.png
index 5bd5515..3b3d6b7a 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-004-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-004-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-010-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-010-expected.png
index 5aeaf1e..3b3d6b7a 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-010-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/text/textshadow-010-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
new file mode 100644
index 0000000..2f58da4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/paint/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/paint/selection/selection-within-composited-scroller-expected.txt
index b172a4e..33e09c53 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/paint/selection/selection-within-composited-scroller-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/paint/selection/selection-within-composited-scroller-expected.txt
@@ -14,6 +14,7 @@
           "position": [8, 8],
           "bounds": [200, 200],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#D3D3D3",
           "repaintRects": [
@@ -25,10 +26,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 1620],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 610, 21, 19]
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/plugins/webview-plugin-nested-iframe-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/plugins/webview-plugin-nested-iframe-scroll-expected.png
new file mode 100644
index 0000000..c0d366e5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/plugins/webview-plugin-nested-iframe-scroll-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/plugins/webview-plugin-nested-iframe-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/plugins/webview-plugin-nested-iframe-scroll-expected.txt
new file mode 100644
index 0000000..c56df39
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/plugins/webview-plugin-nested-iframe-scroll-expected.txt
@@ -0,0 +1,19 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x175
+  LayoutBlockFlow {HTML} at (0,0) size 800x175
+    LayoutBlockFlow {BODY} at (8,8) size 784x159
+      LayoutText {#text} at (0,0) size 0x0
+layer at (8,8) size 304x154
+  LayoutIFrame {IFRAME} at (0,0) size 304x154 [border: (2px inset #EEEEEE)]
+    layer at (0,0) size 300x150 clip at (0,0) size 285x135 scrollY 50.00 scrollWidth 308 scrollHeight 3211
+      LayoutView at (0,0) size 300x150
+    layer at (0,0) size 285x3211 backgroundClip at (0,0) size 285x135 clip at (0,0) size 285x135
+      LayoutBlockFlow {HTML} at (0,0) size 285x3211
+        LayoutBlockFlow {BODY} at (8,8) size 269x3195
+          LayoutBlockFlow {DIV} at (0,0) size 269x40
+          LayoutBlockFlow (anonymous) at (0,40) size 269x155
+            LayoutText {#text} at (0,0) size 0x0
+          LayoutBlockFlow {DIV} at (0,195) size 269x3000
+    layer at (8,48) size 300x150 backgroundClip at (0,0) size 285x135 clip at (0,0) size 285x135
+      LayoutEmbeddedObject {EMBED} at (0,0) size 300x150
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/plugins/webview-plugin-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/plugins/webview-plugin-scroll-expected.png
index 77722993..b5daa85 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/plugins/webview-plugin-scroll-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/plugins/webview-plugin-scroll-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/svg/custom/repaint-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/svg/custom/repaint-shadow-expected.png
index 23c5cffe..e2ff7ce 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/svg/custom/repaint-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/svg/custom/repaint-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/repaint-shadow-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/svg/custom/repaint-shadow-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/linux/svg/custom/repaint-shadow-expected.txt
rename to third_party/WebKit/LayoutTests/platform/win-xp/svg/custom/repaint-shadow-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/svg/wicd/test-scalable-background-image1-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/svg/wicd/test-scalable-background-image1-expected.png
index d40e05c..e1b0942 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/svg/wicd/test-scalable-background-image1-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/svg/wicd/test-scalable-background-image1-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png
new file mode 100644
index 0000000..cbaefe7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/gpu/fast/canvas/canvas-scale-strokePath-shadow-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/gpu/fast/canvas/canvas-scale-strokePath-shadow-expected.txt
new file mode 100644
index 0000000..aeb83637
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/gpu/fast/canvas/canvas-scale-strokePath-shadow-expected.txt
@@ -0,0 +1,57 @@
+Ensure correct behavior of canvas with path stroke + shadow after scaling. A blue and red checkered pattern should be displayed.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is 255
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is 255
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is 255
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 76
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 76
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 76
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 200
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 49
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 199
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 70
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 70
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 69
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
index b85a763..f4e88a0 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
@@ -25,15 +25,16 @@
           "position": [8, 68],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -137,10 +138,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2562],
+  "bounds": [785, 2578],
   "children": [
     {
-      "bounds": [785, 2562],
+      "bounds": [785, 2578],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -148,15 +149,16 @@
           "position": [8, 68],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -260,24 +262,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4530],
+  "bounds": [785, 4562],
   "children": [
     {
-      "bounds": [785, 4530],
+      "bounds": [785, 4562],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -380,24 +383,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6450],
+  "bounds": [785, 6498],
   "children": [
     {
-      "bounds": [785, 6450],
+      "bounds": [785, 6498],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt
index 4a47763..7bb7d757 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -134,24 +135,25 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2514],
+  "bounds": [785, 2530],
   "children": [
     {
-      "bounds": [785, 2514],
+      "bounds": [785, 2530],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -254,24 +256,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4434],
+  "bounds": [785, 4466],
   "children": [
     {
-      "bounds": [785, 4434],
+      "bounds": [785, 4466],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
index d6996d2..f6d489f 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -134,10 +135,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2514],
+  "bounds": [785, 2530],
   "children": [
     {
-      "bounds": [785, 2514],
+      "bounds": [785, 2530],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -145,15 +146,16 @@
           "position": [8, 68],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -257,10 +259,10 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4482],
+  "bounds": [785, 4514],
   "children": [
     {
-      "bounds": [785, 4482],
+      "bounds": [785, 4514],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -268,15 +270,16 @@
           "position": [8, 68],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -380,24 +383,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6450],
+  "bounds": [785, 6498],
   "children": [
     {
-      "bounds": [785, 6450],
+      "bounds": [785, 6498],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 68],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt
index 52e2586..b08b28b4 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 61],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 0, 48, 656]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 656],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 0, 48, 656]
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt
index 8336acb..16a6c02 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt
@@ -16,6 +16,7 @@
         {
           "position": [0, 60],
           "bounds": [800, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [244, 0, 40, 19],
@@ -29,10 +30,10 @@
           "children": [
             {
               "bounds": [785, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [785, 1345],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [244, 0, 40, 19],
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
index ebcfe549..7569bf1 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,16 +11,17 @@
           "position": [18, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 328],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -45,16 +46,17 @@
           "position": [248, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 328],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt
index 569027b..c36669f 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 108],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 190, 74, 19],
@@ -28,10 +29,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 260],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 240, 74, 19],
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/spv2/paint/roundedrects/circle-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/spv2/paint/roundedrects/circle-with-shadow-expected.png
new file mode 100644
index 0000000..05b29cb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/spv2/paint/roundedrects/circle-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/spv2/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/spv2/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
new file mode 100644
index 0000000..2f58da4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/spv2/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
index ee3d294..c45f25aa 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [500, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [-2000, -2000, 5000, 5000]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [485, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [5000, 5000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 0, 5000, 5000]
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png
new file mode 100644
index 0000000..ccd7c8e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/paint/roundedrects/circle-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/paint/roundedrects/circle-with-shadow-expected.png
new file mode 100644
index 0000000..05b29cb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/paint/roundedrects/circle-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
new file mode 100644
index 0000000..2f58da4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt
index b172a4e..33e09c53 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt
@@ -14,6 +14,7 @@
           "position": [8, 8],
           "bounds": [200, 200],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#D3D3D3",
           "repaintRects": [
@@ -25,10 +26,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 1620],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 610, 21, 19]
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/clipping-foreground-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/clipping-foreground-expected.png
index 0b53c87..3ebd36c0 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/clipping-foreground-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/clipping-foreground-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png
index 507d21c..4f23fa7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/iframes/composited-iframe-alignment-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/iframes/composited-iframe-alignment-expected.png
index fa28eda5..76d4e30d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/iframes/composited-iframe-alignment-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/iframes/composited-iframe-alignment-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/masks/masked-ancestor-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/masks/masked-ancestor-expected.png
index 3c1b7dd6..368a716 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/masks/masked-ancestor-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/masks/masked-ancestor-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
index 8025a804..6de1e896 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
@@ -25,15 +25,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -137,10 +138,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2574],
+  "bounds": [785, 2590],
   "children": [
     {
-      "bounds": [785, 2574],
+      "bounds": [785, 2590],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -148,15 +149,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -260,24 +262,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4542],
+  "bounds": [785, 4574],
   "children": [
     {
-      "bounds": [785, 4542],
+      "bounds": [785, 4574],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -380,24 +383,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6462],
+  "bounds": [785, 6510],
   "children": [
     {
-      "bounds": [785, 6462],
+      "bounds": [785, 6510],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/selection-gaps-toggling-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/selection-gaps-toggling-expected.txt
index cbce4a5..6d2416b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/selection-gaps-toggling-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/selection-gaps-toggling-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -134,24 +135,25 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2508],
+  "bounds": [785, 2524],
   "children": [
     {
-      "bounds": [785, 2508],
+      "bounds": [785, 2524],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -254,24 +256,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4428],
+  "bounds": [785, 4460],
   "children": [
     {
-      "bounds": [785, 4428],
+      "bounds": [785, 4460],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
index 25504b7..daed0fe 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -134,10 +135,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2526],
+  "bounds": [785, 2542],
   "children": [
     {
-      "bounds": [785, 2526],
+      "bounds": [785, 2542],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -145,15 +146,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -257,10 +259,10 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4494],
+  "bounds": [785, 4526],
   "children": [
     {
-      "bounds": [785, 4494],
+      "bounds": [785, 4526],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -268,15 +270,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -380,24 +383,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6462],
+  "bounds": [785, 6510],
   "children": [
     {
-      "bounds": [785, 6462],
+      "bounds": [785, 6510],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/textarea-scroll-touch-expected.txt
index 11cc373..06a89a1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,16 +11,17 @@
           "position": [18, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 337],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -45,16 +46,17 @@
           "position": [248, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 337],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
index 185df10..6b1f32c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [500, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [-2001, -2000, 5001, 5000]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [485, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [5000, 5000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [-1, 0, 5001, 5000]
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/shadows/shadow-drawing-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/shadows/shadow-drawing-expected.png
index 1a42947..2e334558 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/shadows/shadow-drawing-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/shadows/shadow-drawing-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/squashing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/squashing/iframe-inside-squashed-layer-expected.txt
index 743103a..3c5f8c3f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/squashing/iframe-inside-squashed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/squashing/iframe-inside-squashed-layer-expected.txt
@@ -39,8 +39,8 @@
                 "LayoutView #document",
                 "LayoutBlockFlow HTML",
                 "LayoutBlockFlow BODY",
-                "VerticalScrollbar",
-                "LayoutView #document"
+                "LayoutView #document",
+                "VerticalScrollbar"
               ]
             }
           ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/css2.1/20110323/background-intrinsic-004-expected.png b/third_party/WebKit/LayoutTests/platform/win/css2.1/20110323/background-intrinsic-004-expected.png
index e568cb6ff..a901ef3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css2.1/20110323/background-intrinsic-004-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css2.1/20110323/background-intrinsic-004-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-canvas-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-canvas-with-shadow-expected.png
index a6f196830..7a56562 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-canvas-with-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-canvas-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-shadow-expected.png
index 7026e31..822b482 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-split-inline-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-split-inline-expected.png
index ba159d1..ce30f5a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-split-inline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-split-inline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/basic-shadows-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/basic-shadows-expected.png
index 7cef696..2244c24 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/basic-shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/basic-shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/box-shadow-expected.png
index 8825b4e..4766beb 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/box-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/box-shadow-transformed-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/box-shadow-transformed-expected.png
index cd481d5..388229c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/box-shadow-transformed-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/box-shadow-transformed-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-expected.png
index a11abb0..a0f2a7a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-subpixel-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-subpixel-expected.png
index 4a1b9736..50bd45a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-subpixel-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-subpixel-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/scaled-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/scaled-box-shadow-expected.png
deleted file mode 100644
index 0eab716..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/scaled-box-shadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-composite-shadow-expected.png
index 0913de7..8bdf0d4 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-incremental-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-incremental-repaint-expected.png
index 89ca8de..2b64d6d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-incremental-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-incremental-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-shadow-source-in-expected.png
index 647e06c0..71a985ba 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-shadow-source-in-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-shadow-source-in-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css/color-correction-on-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/css/color-correction-on-box-shadow-expected.png
index c507d02..a7942cc 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/css/color-correction-on-box-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/css/color-correction-on-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css/color-correction-on-text-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/css/color-correction-on-text-shadow-expected.png
index 6656fb69..5fb2b918 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/css/color-correction-on-text-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/css/color-correction-on-text-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/css/shadow-multiple-expected.png
index 24244f3..ab5eaf1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/css/shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/css/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/dom/HTMLMeterElement/meter-element-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/dom/HTMLMeterElement/meter-element-expected.png
index 7fa8c52..9de2602 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/dom/HTMLMeterElement/meter-element-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/dom/HTMLMeterElement/meter-element-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/dom/HTMLMeterElement/meter-styles-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/dom/HTMLMeterElement/meter-styles-expected.png
index 0d63067..04c2947 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/dom/HTMLMeterElement/meter-styles-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/dom/HTMLMeterElement/meter-styles-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
index 8bde39bf..ef36a15 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
index 941ceeb3..ea68cfba 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
index a957671..d1c24c5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
index 0de07c0..2d1db31 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
index 378f838..a8f8df35 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
index 2e93b15..dcf0e8c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
index 339513d..16d11d5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index ea6dda7..02d4f8f6 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
index b25c1272..ab9fe91 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/month-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/month-picker-appearance-expected.png
index a50d27ff..12bddc063 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/month-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/month-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/month-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
index ff6b66a..eb189b1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/week-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/week-picker-appearance-expected.png
index aca0df4..d7270fe 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/week-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/week-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/week-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
index 504f3d2..01ecb5c7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/checkbox/checkbox-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/checkbox/checkbox-appearance-basic-expected.png
index a3f10ad..d182363 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/checkbox/checkbox-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/checkbox/checkbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-expected.png
index abe84fce..84819383 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
index 9eec0c29..900b262 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
index 218af4d..a02ac14 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
index 8d1e130..d04c1348 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
index 6dd5a2f..e1de9a9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
index 208e621..1739a1c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-with-scrollbar-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/radio/radio-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/radio/radio-appearance-basic-expected.png
index e40097db..a07a7de 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/radio/radio-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/radio/radio-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/range/range-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/range/range-appearance-basic-expected.png
index 0ae54cd..18d756e1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/range/range-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/range/range-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/search/search-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/search/search-appearance-basic-expected.png
index af1addc9..cbb410a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/search/search-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/search/search-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/listbox-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/listbox-appearance-basic-expected.png
index fe4db5d..a7a708c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/listbox-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/listbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.png
index 4b642da..e59b484f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/submit/submit-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/submit/submit-appearance-basic-expected.png
index 7646999..be1e296 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/submit/submit-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/submit/submit-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/text/text-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/text/text-appearance-basic-expected.png
index ecb800f..7119766 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/text/text-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/text/text-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/textarea/textarea-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/textarea/textarea-appearance-basic-expected.png
index 0054875..62fc9e8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/textarea/textarea-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/textarea/textarea-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/details-open-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/details-open-repaint-expected.txt
index a5b4147..b955518 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/details-open-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/details-open-repaint-expected.txt
@@ -16,9 +16,10 @@
         "LayoutBlockFlow DIV id='details-content'",
         "LayoutTextControl INPUT",
         "LayoutBlockFlow DIV id='inner-editor'",
-        "HorizontalScrollbar",
-        "VerticalScrollbar",
         "LayoutBlockFlow DIV id='inner-editor'",
+        "HorizontalScrollbar",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "VerticalScrollbar",
         "LayoutText #text",
         "LayoutText #text"
       ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-9-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-9-expected.txt
index 85cbe25..be3588b7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-9-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-9-expected.txt
@@ -155,8 +155,8 @@
         "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
         "InlineTextBox 'here; the great\n'",
         "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-        "VerticalScrollbar",
-        "LayoutView #document"
+        "LayoutView #document",
+        "VerticalScrollbar"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/resize-scrollable-iframe-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/resize-scrollable-iframe-expected.txt
index 9a47d4b..1fb0cf2d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/resize-scrollable-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/resize-scrollable-iframe-expected.txt
@@ -28,9 +28,10 @@
         "LayoutIFrame IFRAME id='iframe'",
         "LayoutView #document",
         "LayoutView #document",
+        "LayoutView #document",
         "HorizontalScrollbar",
-        "VerticalScrollbar",
-        "LayoutView #document"
+        "LayoutView #document",
+        "VerticalScrollbar"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/shadow-multiple-expected.png
index d644b724..698aafa 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/shadow-translucent-fill-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/shadow-translucent-fill-expected.png
index 8962e82..deb18d0 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/text/shadow-translucent-fill-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/shadow-translucent-fill-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/transforms/shadows-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/transforms/shadows-expected.png
index ba52932..6421c3c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/transforms/shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/transforms/shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/writing-mode/english-lr-text-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/writing-mode/english-lr-text-expected.png
index f9e1d625..a8d145a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/writing-mode/english-lr-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/writing-mode/english-lr-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-001-expected.png b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-001-expected.png
index da64ca7..4364f4b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-001-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-001-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-003-expected.png b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-003-expected.png
index cedc8644..c35f31a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-003-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-003-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-004-expected.png b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-004-expected.png
index 67f3ed29..1a8094f4 100644
--- a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-004-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-004-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/roundedrects/circle-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/roundedrects/circle-with-shadow-expected.png
index dc3035c..70a7377 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/roundedrects/circle-with-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/roundedrects/circle-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
index 2f58da4..d8d8dacd 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/selection/selection-within-composited-scroller-expected.txt
index b0f1abd..11b96f8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/selection/selection-within-composited-scroller-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/selection/selection-within-composited-scroller-expected.txt
@@ -14,6 +14,7 @@
           "position": [8, 8],
           "bounds": [200, 200],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#D3D3D3",
           "repaintRects": [
@@ -25,10 +26,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 1620],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 610, 23, 17]
diff --git a/third_party/WebKit/LayoutTests/platform/win/plugins/webview-plugin-nested-iframe-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/win/plugins/webview-plugin-nested-iframe-scroll-expected.png
new file mode 100644
index 0000000..568161b5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/plugins/webview-plugin-nested-iframe-scroll-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/plugins/webview-plugin-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/win/plugins/webview-plugin-scroll-expected.png
new file mode 100644
index 0000000..04957a9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/plugins/webview-plugin-scroll-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/repaint-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/repaint-shadow-expected.png
index 4d593408..0e614e1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/repaint-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/repaint-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/repaint-shadow-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/custom/repaint-shadow-expected.txt
deleted file mode 100644
index 3d8223a..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/repaint-shadow-expected.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-  "bounds": [800, 600],
-  "children": [
-    {
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "repaintRects": [
-        [412, 15, 1, 261],
-        [171, 15, 242, 261],
-        [171, 15, 242, 261],
-        [170, 15, 242, 261],
-        [170, 15, 242, 261]
-      ],
-      "paintInvalidationClients": [
-        "RootInlineBox",
-        "InlineTextBox 'X'",
-        "LayoutSVGRoot svg",
-        "LayoutSVGText text",
-        "LayoutSVGInlineText #text",
-        "InlineTextBox 'X'"
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/wicd/test-scalable-background-image1-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/wicd/test-scalable-background-image1-expected.png
index e1bf258..3d9f9ad5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/wicd/test-scalable-background-image1-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/wicd/test-scalable-background-image1-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-background-images-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-background-images-expected.png
index 4ba1d92..c09e939c9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-background-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-background-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
index 0913de7..8bdf0d4 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
index 89ca8de..2b64d6d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png
new file mode 100644
index 0000000..71a985ba
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-composite-shadow-expected.png
index e900edd..d1402425 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-incremental-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-incremental-repaint-expected.png
index d9c05519..40c38fc 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-incremental-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-incremental-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-shadow-source-in-expected.png
index 3b3e55d..965e3cc 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-shadow-source-in-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-shadow-source-in-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
index 8025a804..6de1e896 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-after-removing-scrolling-contents-expected.txt
@@ -25,15 +25,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -137,10 +138,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2574],
+  "bounds": [785, 2590],
   "children": [
     {
-      "bounds": [785, 2574],
+      "bounds": [785, 2590],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -148,15 +149,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -260,24 +262,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4542],
+  "bounds": [785, 4574],
   "children": [
     {
-      "bounds": [785, 4542],
+      "bounds": [785, 4574],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -380,24 +383,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6462],
+  "bounds": [785, 6510],
   "children": [
     {
-      "bounds": [785, 6462],
+      "bounds": [785, 6510],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt
index cbce4a5..6d2416b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -134,24 +135,25 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2508],
+  "bounds": [785, 2524],
   "children": [
     {
-      "bounds": [785, 2508],
+      "bounds": [785, 2524],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -254,24 +256,25 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4428],
+  "bounds": [785, 4460],
   "children": [
     {
-      "bounds": [785, 4428],
+      "bounds": [785, 4460],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 62],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
index 25504b7..daed0fe 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/selection-gaps-toggling-with-scrolling-contents-expected.txt
@@ -24,14 +24,15 @@
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
@@ -134,10 +135,10 @@
 *** iteration 2: ***
 
 {
-  "bounds": [785, 2526],
+  "bounds": [785, 2542],
   "children": [
     {
-      "bounds": [785, 2526],
+      "bounds": [785, 2542],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -145,15 +146,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -257,10 +259,10 @@
 *** iteration 3: ***
 
 {
-  "bounds": [785, 4494],
+  "bounds": [785, 4526],
   "children": [
     {
-      "bounds": [785, 4494],
+      "bounds": [785, 4526],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
@@ -268,15 +270,16 @@
           "position": [8, 80],
           "bounds": [300, 500],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#0000FF",
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 665],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -380,24 +383,25 @@
 *** iteration 4: ***
 
 {
-  "bounds": [785, 6462],
+  "bounds": [785, 6510],
   "children": [
     {
-      "bounds": [785, 6462],
+      "bounds": [785, 6510],
       "contentsOpaque": true,
       "drawsContent": true,
       "children": [
         {
           "position": [8, 80],
           "bounds": [300, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [285, 665],
-                  "shouldFlattenTransform": false
+                  "bounds": [285, 665]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt
index 5aa53e6..8f004660 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-color-change-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 57],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 0, 48, 656]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 656],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 0, 48, 656]
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt
index ff1468f..7b65e75 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/text-match-highlight-expected.txt
@@ -16,6 +16,7 @@
         {
           "position": [0, 54],
           "bounds": [800, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [270, 0, 46, 17],
@@ -29,10 +30,10 @@
           "children": [
             {
               "bounds": [785, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [785, 1340],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [270, 0, 46, 17],
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
index 11cc373..06a89a1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,16 +11,17 @@
           "position": [18, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 337],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -45,16 +46,17 @@
           "position": [248, 18],
           "bounds": [206, 126],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#CCCCCC",
           "children": [
             {
               "position": [1, 1],
               "bounds": [189, 124],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [189, 337],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt
index b81eed4b..6831e63 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-and-content-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 108],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 167, 75, 17],
@@ -28,10 +29,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 234],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 216, 75, 17],
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/spv2/paint/roundedrects/circle-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/spv2/paint/roundedrects/circle-with-shadow-expected.png
new file mode 100644
index 0000000..70a7377
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/spv2/paint/roundedrects/circle-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/spv2/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/spv2/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
new file mode 100644
index 0000000..d8d8dacd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/spv2/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
index 185df10..6b1f32c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [500, 500],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [-2001, -2000, 5001, 5000]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [485, 485],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [5000, 5000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [-1, 0, 5001, 5000]
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt
index a5b4147..b955518 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/details-open-repaint-expected.txt
@@ -16,9 +16,10 @@
         "LayoutBlockFlow DIV id='details-content'",
         "LayoutTextControl INPUT",
         "LayoutBlockFlow DIV id='inner-editor'",
-        "HorizontalScrollbar",
-        "VerticalScrollbar",
         "LayoutBlockFlow DIV id='inner-editor'",
+        "HorizontalScrollbar",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "VerticalScrollbar",
         "LayoutText #text",
         "LayoutText #text"
       ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/line-flow-with-floats-9-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/line-flow-with-floats-9-expected.txt
index 85cbe25..be3588b7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/line-flow-with-floats-9-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/line-flow-with-floats-9-expected.txt
@@ -155,8 +155,8 @@
         "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
         "InlineTextBox 'here; the great\n'",
         "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-        "VerticalScrollbar",
-        "LayoutView #document"
+        "LayoutView #document",
+        "VerticalScrollbar"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/resize-scrollable-iframe-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/resize-scrollable-iframe-expected.txt
index 9a47d4b..1fb0cf2d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/resize-scrollable-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/resize-scrollable-iframe-expected.txt
@@ -28,9 +28,10 @@
         "LayoutIFrame IFRAME id='iframe'",
         "LayoutView #document",
         "LayoutView #document",
+        "LayoutView #document",
         "HorizontalScrollbar",
-        "VerticalScrollbar",
-        "LayoutView #document"
+        "LayoutView #document",
+        "VerticalScrollbar"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png
new file mode 100644
index 0000000..698aafa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/paint/roundedrects/circle-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/paint/roundedrects/circle-with-shadow-expected.png
new file mode 100644
index 0000000..70a7377
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/paint/roundedrects/circle-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
new file mode 100644
index 0000000..d8d8dacd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt
index b0f1abd..11b96f8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/paint/selection/selection-within-composited-scroller-expected.txt
@@ -14,6 +14,7 @@
           "position": [8, 8],
           "bounds": [200, 200],
           "contentsOpaque": true,
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "backgroundColor": "#D3D3D3",
           "repaintRects": [
@@ -25,10 +26,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 1620],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 610, 23, 17]
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
index 6b7bfa2..817e16ac 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
index 297067d1..e63b5b5 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
index dc4f072..806cdcc3 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
index 76845e8..206187c 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
index 9a7f8fe..97b7cde 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
index 18e7786..6617f6d 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index 3197125..bbf87d9b 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
index cd8ed6c7..bd99f41 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/month-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/month-picker-appearance-expected.png
index 0e8d3e0..3403f94 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/month-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/month-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/month-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
index 1e93b01..9f366f2 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/week-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/week-picker-appearance-expected.png
index 826b990..602610e8 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/week-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/week-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/week-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
index 27ba0720..4b324df 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/search/search-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/search/search-appearance-basic-expected.png
index 1ccd9045..62a68f07 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/search/search-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/search/search-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/text/stroking-decorations-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/text/stroking-decorations-expected.png
index a235ae0..0710d6e9 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/text/stroking-decorations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/text/stroking-decorations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/text/stroking-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/text/stroking-expected.png
index 6979c0a..3b13b14ea 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/text/stroking-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/text/stroking-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/writing-mode/english-lr-text-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/writing-mode/english-lr-text-expected.png
index 67a6d2db..4fbc4bec 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/writing-mode/english-lr-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/writing-mode/english-lr-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-002-expected.png b/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-002-expected.png
index eb737ae6..e9c4f39 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-002-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-002-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-010-expected.png b/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-010-expected.png
index 659b24b..a91aa3d1 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-010-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-010-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/css/text-gradient-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/css/text-gradient-shadow-expected.png
index b714e48..52d8916 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/css/text-gradient-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/css/text-gradient-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/css/text-shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/css/text-shadow-multiple-expected.png
index 6a85865..78ba0764 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/css/text-shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/css/text-shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/custom/repaint-shadow-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/svg/custom/repaint-shadow-expected.txt
index 5f1ef34..3d8223a 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/custom/repaint-shadow-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/custom/repaint-shadow-expected.txt
@@ -1,2 +1,26 @@
-X
-X
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [412, 15, 1, 261],
+        [171, 15, 242, 261],
+        [171, 15, 242, 261],
+        [170, 15, 242, 261],
+        [170, 15, 242, 261]
+      ],
+      "paintInvalidationClients": [
+        "RootInlineBox",
+        "InlineTextBox 'X'",
+        "LayoutSVGRoot svg",
+        "LayoutSVGText text",
+        "LayoutSVGInlineText #text",
+        "InlineTextBox 'X'"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/plugins/resources/iframe-with-webview-plugin.html b/third_party/WebKit/LayoutTests/plugins/resources/iframe-with-webview-plugin.html
new file mode 100644
index 0000000..615bc03
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/plugins/resources/iframe-with-webview-plugin.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<div style="height: 40px"></div>
+<embed id="plugin" type="application/x-plugin-placeholder-test"></embed>
+<div style="height: 3000px"></div>
+<script>
+onload = function() {
+    window.scrollBy(0, 50);
+}
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/plugins/webview-plugin-nested-iframe-scroll-expected.txt b/third_party/WebKit/LayoutTests/plugins/webview-plugin-nested-iframe-scroll-expected.txt
new file mode 100644
index 0000000..00b9c0fc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/plugins/webview-plugin-nested-iframe-scroll-expected.txt
@@ -0,0 +1,19 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x174
+  LayoutBlockFlow {HTML} at (0,0) size 800x174
+    LayoutBlockFlow {BODY} at (8,8) size 784x158
+      LayoutText {#text} at (0,0) size 0x0
+layer at (8,8) size 304x154
+  LayoutIFrame {IFRAME} at (0,0) size 304x154 [border: (2px inset #EEEEEE)]
+    layer at (0,0) size 300x150 clip at (0,0) size 285x135 scrollY 50.00 scrollWidth 308 scrollHeight 3210
+      LayoutView at (0,0) size 300x150
+    layer at (0,0) size 285x3210 backgroundClip at (0,0) size 285x135 clip at (0,0) size 285x135
+      LayoutBlockFlow {HTML} at (0,0) size 285x3210
+        LayoutBlockFlow {BODY} at (8,8) size 269x3194
+          LayoutBlockFlow {DIV} at (0,0) size 269x40
+          LayoutBlockFlow (anonymous) at (0,40) size 269x154
+            LayoutText {#text} at (0,0) size 0x0
+          LayoutBlockFlow {DIV} at (0,194) size 269x3000
+    layer at (8,48) size 300x150 backgroundClip at (0,0) size 285x135 clip at (0,0) size 285x135
+      LayoutEmbeddedObject {EMBED} at (0,0) size 300x150
diff --git a/third_party/WebKit/LayoutTests/plugins/webview-plugin-nested-iframe-scroll.html b/third_party/WebKit/LayoutTests/plugins/webview-plugin-nested-iframe-scroll.html
new file mode 100644
index 0000000..e87127e2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/plugins/webview-plugin-nested-iframe-scroll.html
@@ -0,0 +1,18 @@
+<!doctype HTML>
+<iframe src="resources/iframe-with-webview-plugin.html"></iframe>
+<script>
+onload = function() {
+    if (window.testRunner) {
+        window.testRunner.waitUntilDone();
+        // Need to paint two frames in order to allow the plugin to properly load.
+        // TODO(chrishtr): find out why and fix.
+        requestAnimationFrame(function() {
+            requestAnimationFrame(function() {
+                requestAnimationFrame(function() {
+                    window.testRunner.notifyDone();
+                });
+            });
+        });
+    }
+}
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/plugins/webview-plugin-scroll-expected.png b/third_party/WebKit/LayoutTests/plugins/webview-plugin-scroll-expected.png
deleted file mode 100644
index b5daa85..0000000
--- a/third_party/WebKit/LayoutTests/plugins/webview-plugin-scroll-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/printing/multicol-2-pages-expected.html b/third_party/WebKit/LayoutTests/printing/multicol-2-pages-expected.html
new file mode 100644
index 0000000..d0d8bd8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/printing/multicol-2-pages-expected.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<style>
+    .fakeColumn { float:left; width:200px; }
+    .fakeColumn:not(:first-child) { padding-left:4px; }
+    .fakeColumn:not(:last-child) { border-right:3px solid hotpink; padding-right:4px; }
+</style>
+<script>
+if (window.testRunner)
+    testRunner.setPrinting();
+if (window.internals)
+    internals.settings.setShouldPrintBackgrounds(true);
+</script>
+<!-- TODO(mstensho): Try to come up with something that doesn't make assumptions about page
+     height. Currently, there's no way of specifying it for layout tests. This test currently
+     assumes that 5 lines will fit in each column on the first page, and the remaining ones on the
+     next page. -->
+<p>There should be three columns in this document - on this page, and on the next page. The numbers
+    should be in ascending order when reading columns from left to right, page by page.</p>
+<div style="width:622px; font-size:112px; background:papayawhip;">
+    <div>
+        <div class="fakeColumn">
+            01<br>
+            02<br>
+            03<br>
+            04<br>
+            05<br>
+            16<br>
+            17<br>
+            18<br>
+        </div>
+        <div class="fakeColumn">
+            06<br>
+            07<br>
+            08<br>
+            09<br>
+            10<br>
+            19<br>
+            20<br>
+            21<br>
+        </div>
+        <div class="fakeColumn">
+            11<br>
+            12<br>
+            13<br>
+            14<br>
+            15<br>
+            22<br>
+            23<br>
+        </div>
+    </div>
+    <div style="clear:both;"></div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/printing/multicol-2-pages.html b/third_party/WebKit/LayoutTests/printing/multicol-2-pages.html
new file mode 100644
index 0000000..0835328
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/printing/multicol-2-pages.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<script>
+if (window.testRunner)
+    testRunner.setPrinting();
+if (window.internals)
+    internals.settings.setShouldPrintBackgrounds(true);
+</script>
+<!-- TODO(mstensho): Try to come up with something that doesn't make assumptions about page
+     height. Currently, there's no way of specifying it for layout tests. This test currently
+     assumes that 5 lines will fit in each column on the first page, and the remaining ones on the
+     next page. -->
+<p>There should be three columns in this document - on this page, and on the next page. The numbers
+    should be in ascending order when reading columns from left to right, page by page.</p>
+<div style="-webkit-columns:3; -webkit-column-gap:11px; -webkit-column-rule:3px solid hotpink; width:622px; font-size:112px; background:papayawhip;">
+    01<br>
+    02<br>
+    03<br>
+    04<br>
+    05<br>
+    06<br>
+    07<br>
+    08<br>
+    09<br>
+    10<br>
+    11<br>
+    12<br>
+    13<br>
+    14<br>
+    15<br>
+    16<br>
+    17<br>
+    18<br>
+    19<br>
+    20<br>
+    21<br>
+    22<br>
+    23<br>
+</div>
diff --git a/third_party/WebKit/LayoutTests/printing/multicol-expected.txt b/third_party/WebKit/LayoutTests/printing/multicol-expected.txt
new file mode 100644
index 0000000..427f3d4b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/printing/multicol-expected.txt
@@ -0,0 +1,21 @@
+PASS internals.numberOfPages(800, 800) is 2
+PASS successfullyParsed is true
+
+TEST COMPLETE
+To run this test manually, print this document.
+
+There should be 2 pages in this document.
+
+m
+u
+l
+t
+i
+c
+o
+l
+
+F
+T
+W
+
diff --git a/third_party/WebKit/LayoutTests/printing/multicol-not-supported-expected.txt b/third_party/WebKit/LayoutTests/printing/multicol-not-supported-expected.txt
deleted file mode 100644
index 31f9bbf..0000000
--- a/third_party/WebKit/LayoutTests/printing/multicol-not-supported-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-PASS internals.numberOfPages(800, 800) is 6
-PASS successfullyParsed is true
-
-TEST COMPLETE
-To run this test manually, print this document.
-
-There should be 6 pages in this document. Multicol doesn't work well with printing, so it should be disabled. See crbug.com/99358
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/third_party/WebKit/LayoutTests/printing/multicol-not-supported.html b/third_party/WebKit/LayoutTests/printing/multicol-not-supported.html
deleted file mode 100644
index 2f31933..0000000
--- a/third_party/WebKit/LayoutTests/printing/multicol-not-supported.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<script src="../resources/js-test.js"></script>
-<p>To run this test manually, print this document.</p>
-<p>There should be 6 pages in this document. Multicol doesn't work well with printing, so it should
-    be disabled. See crbug.com/99358</p>
-<div style="page-break-before:always; -webkit-columns:10; line-height:400px;">
-    <br>
-    <br>
-    <br>
-    <br>
-    <br>
-    <br>
-    <br>
-    <br>
-    <br>
-    <br>
-</div>
-<script>
-    if (window.internals)
-        shouldBe("internals.numberOfPages(800, 800)", "6");
-</script>
diff --git a/third_party/WebKit/LayoutTests/printing/multicol.html b/third_party/WebKit/LayoutTests/printing/multicol.html
new file mode 100644
index 0000000..711eead
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/printing/multicol.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<script src="../resources/js-test.js"></script>
+<p>To run this test manually, print this document.</p>
+<p>There should be 2 pages in this document.</p>
+<div style="page-break-before:always; -webkit-columns:12; -webkit-column-gap:0; width:12em; text-align:center; line-height:400px;">
+    m<br>
+    u<br>
+    l<br>
+    t<br>
+    i<br>
+    c<br>
+    o<br>
+    l<br>
+    <br>
+    F<br>
+    T<br>
+    W<br>
+</div>
+<script>
+    if (window.internals)
+        shouldBe("internals.numberOfPages(800, 800)", "2");
+</script>
diff --git a/third_party/WebKit/LayoutTests/svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt b/third_party/WebKit/LayoutTests/svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
index 9d685de1..0fa9de8 100644
--- a/third_party/WebKit/LayoutTests/svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
@@ -51,6 +51,7 @@
         "LayoutSVGRect rect",
         "LayoutSVGRect rect",
         "LayoutText #text",
+        "LayoutView #document",
         "LayoutView #document"
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt b/third_party/WebKit/LayoutTests/svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
index 9d685de1..0fa9de8 100644
--- a/third_party/WebKit/LayoutTests/svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
@@ -51,6 +51,7 @@
         "LayoutSVGRect rect",
         "LayoutSVGRect rect",
         "LayoutText #text",
+        "LayoutView #document",
         "LayoutView #document"
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-draw-canvas-on-canvas-shadow-expected.txt b/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-draw-canvas-on-canvas-shadow-expected.txt
index b247dfe..5b3196b 100644
--- a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-draw-canvas-on-canvas-shadow-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-draw-canvas-on-canvas-shadow-expected.txt
@@ -6,15 +6,15 @@
 PASS d[0] is 255
 PASS d[1] is 0
 PASS d[2] is 0
-FAIL d[3] should be 255. Was 228.
+PASS d[3] is 255
 PASS d[0] is 255
 PASS d[1] is 0
 PASS d[2] is 0
-FAIL d[3] should be 255. Was 228.
+PASS d[3] is 255
 PASS d[0] is 255
 PASS d[1] is 0
 PASS d[2] is 0
-FAIL d[3] should be 255. Was 203.
+PASS d[3] is 255
 PASS d[0] is 255
 PASS d[1] is 0
 PASS d[2] is 0
diff --git a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-scale-drawImage-shadow-expected.txt b/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-scale-drawImage-shadow-expected.txt
index 228bdbaa..b54ef615 100644
--- a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-scale-drawImage-shadow-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-scale-drawImage-shadow-expected.txt
@@ -6,11 +6,11 @@
 PASS d[0] is 255
 PASS d[1] is 0
 PASS d[2] is 0
-FAIL d[3] should be 255. Was 203.
+PASS d[3] is 255
 PASS d[0] is 255
 PASS d[1] is 0
 PASS d[2] is 0
-FAIL d[3] should be 255. Was 203.
+PASS d[3] is 255
 PASS d[0] is 255
 PASS d[1] is 0
 PASS d[2] is 0
@@ -18,7 +18,7 @@
 PASS d[0] is 255
 PASS d[1] is 0
 PASS d[2] is 0
-FAIL d[3] is not around 76 (actual: 61)
+PASS d[3] is around 76
 PASS d[0] is 255
 PASS d[1] is 0
 PASS d[2] is 0
diff --git a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-scale-strokePath-shadow-expected.txt b/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-scale-strokePath-shadow-expected.txt
new file mode 100644
index 0000000..edcfdfe
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-scale-strokePath-shadow-expected.txt
@@ -0,0 +1,57 @@
+Ensure correct behavior of canvas with path stroke + shadow after scaling. A blue and red checkered pattern should be displayed.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is 255
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is 255
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is 255
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 76
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 76
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 76
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+FAIL d[3] is not around 200 (actual: 224)
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+FAIL d[3] is not around 49 (actual: 28)
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+FAIL d[3] is not around 199 (actual: 224)
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 70
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 70
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 69
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/mouse-down-on-resizable-expected.txt b/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/mouse-down-on-resizable-expected.txt
deleted file mode 100644
index 7dd75881..0000000
--- a/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/mouse-down-on-resizable-expected.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-
-Verifies that correct mouse events are fired and when resizing an element
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
---- mousedown preventDefault ---
---- move mouse into target ---
---- start resizing ---
-1 Received pointerdown
-2 Received mousedown
---- mouse released ---
---- No preventDefault ---
---- move mouse into target ---
---- start resizing ---
-3 Received pointerdown
-4 Received mousedown
---- mouse released ---
-5 Received pointerup
-6 Received mouseup
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/fake-mouse-event-pointer-types-expected.txt b/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/fake-mouse-event-pointer-types-expected.txt
new file mode 100644
index 0000000..b9b9ae5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/fake-mouse-event-pointer-types-expected.txt
@@ -0,0 +1,18 @@
+pointermove
+mousemove
+pointermove
+mousemove
+Verifies that fake mouse events have correct pointer type for pointer events.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+--- move mouse into target ---
+1 Received pointermove mouse
+2 Received mousemove
+3 Received pointermove mouse
+4 Received mousemove
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
index 39c25efe..ad67ede 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt
index 21ff09a..82736418 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt
@@ -9,15 +9,16 @@
         {
           "position": [8, 8],
           "bounds": [308, 208],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [4, 4],
               "bounds": [285, 200],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [285, 530],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/composited-scrolling-paint-phases-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/composited-scrolling-paint-phases-expected.txt
index 6d86be9..4013b92d 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/composited-scrolling-paint-phases-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/composited-scrolling-paint-phases-expected.txt
@@ -45,6 +45,7 @@
             {
               "position": [28, 20],
               "bounds": [202, 202],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "paintingPhases": [
                 "GraphicsLayerPaintBackground",
@@ -55,6 +56,7 @@
                 {
                   "position": [1, 1],
                   "bounds": [185, 185],
+                  "shouldFlattenTransform": false,
                   "paintingPhases": [
                     "GraphicsLayerPaintBackground",
                     "GraphicsLayerPaintForeground",
@@ -63,7 +65,6 @@
                   "children": [
                     {
                       "bounds": [185, 715],
-                      "shouldFlattenTransform": false,
                       "drawsContent": true,
                       "paintingPhases": [
                         "GraphicsLayerPaintForeground",
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-gains-scrollbars-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-gains-scrollbars-expected.txt
index d243ed8b..10f2551 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-gains-scrollbars-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-gains-scrollbars-expected.txt
@@ -9,14 +9,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [85, 100],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [85, 200],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [10, 200]
@@ -39,14 +40,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [100, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 85],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [200, 10]
@@ -69,14 +71,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 200],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [200, 200]
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-expected.txt
index 9b7a759..e62037c 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-expected.txt
@@ -9,14 +9,15 @@
         {
           "position": [8, 8],
           "bounds": [300, 300],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 285],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [1000, 1000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-toggle-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-toggle-expected.txt
index 9b7a759..e62037c 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-toggle-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-toggle-expected.txt
@@ -9,14 +9,15 @@
         {
           "position": [8, 8],
           "bounds": [300, 300],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 285],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [1000, 1000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-overlay-with-touch-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-overlay-with-touch-expected.txt
index 9b7a759..e62037c 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-overlay-with-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-overlay-with-touch-expected.txt
@@ -9,14 +9,15 @@
         {
           "position": [8, 8],
           "bounds": [300, 300],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [285, 285],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [1000, 1000],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-scrollbar-layers-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-scrollbar-layers-expected.txt
index d243ed8b..10f2551 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-scrollbar-layers-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-scrollbar-layers-expected.txt
@@ -9,14 +9,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [85, 100],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [85, 200],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [10, 200]
@@ -39,14 +40,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [100, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 85],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [200, 10]
@@ -69,14 +71,15 @@
         {
           "position": [8, 13],
           "bounds": [100, 100],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [200, 200],
-                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [200, 200]
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
index b11e3e4..5244c6e 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
@@ -24,14 +24,15 @@
                       "children": [
                         {
                           "bounds": [1200, 1000],
+                          "shouldFlattenTransform": false,
                           "drawsContent": true,
                           "children": [
                             {
                               "bounds": [1200, 1000],
+                              "shouldFlattenTransform": false,
                               "children": [
                                 {
                                   "bounds": [1200, 10000],
-                                  "shouldFlattenTransform": false,
                                   "drawsContent": true
                                 }
                               ]
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute-expected.txt
index a861f58..631b21d 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute-expected.txt
@@ -13,15 +13,16 @@
               "position": [8, 8],
               "bounds": [500, 500],
               "contentsOpaque": true,
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "backgroundColor": "#0000FF",
               "children": [
                 {
                   "bounds": [485, 485],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [485, 5000],
-                      "shouldFlattenTransform": false,
                       "drawsContent": true
                     }
                   ]
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
index eca105b..de97ec2 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
@@ -16,15 +16,16 @@
           "children": [
             {
               "bounds": [102, 102],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [1, 1],
                   "bounds": [100, 100],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
-                      "bounds": [100, 180],
-                      "shouldFlattenTransform": false
+                      "bounds": [100, 180]
                     }
                   ]
                 }
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
index a74270d..e456a58 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
@@ -8,14 +8,15 @@
       "children": [
         {
           "bounds": [320, 340],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "bounds": [305, 325],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [305, 1224],
-                  "shouldFlattenTransform": false
+                  "bounds": [305, 1224]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-without-painting-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-without-painting-expected.txt
index 466febf8..11f017e2 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-without-painting-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-without-painting-expected.txt
@@ -9,15 +9,16 @@
         {
           "position": [8, 8],
           "bounds": [202, 202],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [1, 1],
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 1025],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
index 4b59382..6ca1829 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
@@ -12,15 +12,16 @@
             {
               "position": [10, 10],
               "bounds": [104, 104],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [2, 2],
                   "bounds": [85, 85],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [85, 144],
-                      "shouldFlattenTransform": false,
                       "drawsContent": true
                     }
                   ]
@@ -72,15 +73,16 @@
         {
           "position": [130, 10],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [105, 144],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -128,15 +130,16 @@
             {
               "position": [250, 10],
               "bounds": [104, 104],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [2, 2],
                   "bounds": [85, 85],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
-                      "bounds": [85, 144],
-                      "shouldFlattenTransform": false
+                      "bounds": [85, 144]
                     }
                   ]
                 },
@@ -190,15 +193,16 @@
             {
               "position": [370, 10],
               "bounds": [104, 104],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [2, 2],
                   "bounds": [85, 85],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
                       "bounds": [85, 144],
-                      "shouldFlattenTransform": false,
                       "drawsContent": true
                     }
                   ]
@@ -250,15 +254,16 @@
         {
           "position": [10, 130],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [105, 144],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -306,15 +311,16 @@
             {
               "position": [130, 130],
               "bounds": [104, 104],
+              "shouldFlattenTransform": false,
               "drawsContent": true,
               "children": [
                 {
                   "position": [2, 2],
                   "bounds": [85, 85],
+                  "shouldFlattenTransform": false,
                   "children": [
                     {
-                      "bounds": [85, 144],
-                      "shouldFlattenTransform": false
+                      "bounds": [85, 144]
                     }
                   ]
                 },
@@ -365,15 +371,16 @@
         {
           "position": [250, 130],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [105, 144],
-                  "shouldFlattenTransform": false
+                  "bounds": [105, 144]
                 }
               ]
             },
@@ -417,15 +424,16 @@
         {
           "position": [370, 130],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [105, 144],
-                  "shouldFlattenTransform": false
+                  "bounds": [105, 144]
                 }
               ]
             },
@@ -469,15 +477,16 @@
         {
           "position": [10, 250],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [85, 144],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -529,15 +538,16 @@
         {
           "position": [130, 250],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [85, 144],
-                  "shouldFlattenTransform": false
+                  "bounds": [85, 144]
                 }
               ]
             },
@@ -588,15 +598,16 @@
         {
           "position": [250, 250],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [85, 144],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true
                 }
               ]
@@ -648,15 +659,16 @@
         {
           "position": [370, 250],
           "bounds": [104, 104],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "children": [
             {
               "position": [2, 2],
               "bounds": [85, 85],
+              "shouldFlattenTransform": false,
               "children": [
                 {
-                  "bounds": [85, 144],
-                  "shouldFlattenTransform": false
+                  "bounds": [85, 144]
                 }
               ]
             },
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-expected.txt
index 9894d08..fbf2a42f 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-container-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 108],
           "bounds": [210, 210],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 0, 210, 210]
@@ -20,10 +21,10 @@
             {
               "position": [5, 5],
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [400, 400],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [-5, -5, 210, 210]
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-content-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-content-expected.txt
index 59fbd8e..ecb91aa 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/updating-scrolling-content-expected.txt
@@ -9,6 +9,7 @@
         {
           "position": [8, 8],
           "bounds": [200, 200],
+          "shouldFlattenTransform": false,
           "drawsContent": true,
           "repaintRects": [
             [0, 0, 185, 200]
@@ -16,10 +17,10 @@
           "children": [
             {
               "bounds": [185, 185],
+              "shouldFlattenTransform": false,
               "children": [
                 {
                   "bounds": [185, 1200],
-                  "shouldFlattenTransform": false,
                   "drawsContent": true,
                   "repaintRects": [
                     [0, 0, 185, 200]
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
index 61931449..5d13ffa 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
@@ -281,6 +281,7 @@
     property currentTime
     property defaultMuted
     property defaultPlaybackRate
+    property disableRemotePlayback
     property duration
     property ended
     property error
@@ -994,6 +995,7 @@
     property currentTime
     property defaultMuted
     property defaultPlaybackRate
+    property disableRemotePlayback
     property duration
     property ended
     property error
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 14663cd..44071591 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -2030,6 +2030,7 @@
     getter currentTime
     getter defaultMuted
     getter defaultPlaybackRate
+    getter disableRemotePlayback
     getter duration
     getter ended
     getter error
@@ -2063,6 +2064,7 @@
     setter currentTime
     setter defaultMuted
     setter defaultPlaybackRate
+    setter disableRemotePlayback
     setter loop
     setter muted
     setter onencrypted
diff --git a/third_party/WebKit/LayoutTests/virtual/syncpaint/fast/repaint/overflow-scroll-body-appear-expected.txt b/third_party/WebKit/LayoutTests/virtual/syncpaint/fast/repaint/overflow-scroll-body-appear-expected.txt
index d62068de..cdd6904 100644
--- a/third_party/WebKit/LayoutTests/virtual/syncpaint/fast/repaint/overflow-scroll-body-appear-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/syncpaint/fast/repaint/overflow-scroll-body-appear-expected.txt
@@ -7,11 +7,13 @@
       "drawsContent": true,
       "repaintRects": [
         [785, 585, 15, 15],
+        [785, 0, 15, 585],
         [8, 50, 784, 18],
         [8, 50, 769, 18],
         [8, 16, 2000, 2068],
         [8, 16, 784, 18],
         [8, 16, 769, 18],
+        [0, 585, 785, 15],
         [0, 0, 2008, 2092],
         [0, 0, 785, 585]
       ],
@@ -27,8 +29,8 @@
         "LayoutBlockFlow BODY",
         "LayoutBlockFlow P",
         "LayoutBlockFlow P",
-        "HorizontalScrollbar",
-        "VerticalScrollbar"
+        "LayoutView #document",
+        "LayoutView #document"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-automation-expected.txt b/third_party/WebKit/LayoutTests/webaudio/biquad-automation-expected.txt
new file mode 100644
index 0000000..57a2ae7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/webaudio/biquad-automation-expected.txt
@@ -0,0 +1,15 @@
+Test Automation of Biquad Filters
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Output of bandpass filter with frequency automation equals [0,0.0782652199268341,0.11744670569896698,-0.002010007156059146,-0.031139623373746872,0.0723838210105896,0.04615558311343193,-0.06974676996469498,-0.02473430149257183,0.06254426389932632,-0.02191624790430069,-0.09223899245262146,0.007647276856005192,0.04232903569936752,-0.07107919454574585,-0.07092036306858063,...] with an element-wise tolerance of 0.00005.
+PASS Output of bandpass filter with Q automation equals [0,0.014149743132293224,0.05313149467110634,0.11025312542915344,0.17868348956108093,0.25172680616378784,0.3230687975883484,0.3869902193546295,0.4385446012020111,0.47369763255119324,0.48942655324935913,0.48377954959869385,0.455895334482193,0.40598464012145996,0.3352759778499603,0.24592919647693634,...] with an element-wise tolerance of 0.0000014.
+PASS Output of lowshelf filter with gain automation equals [0,0.47856831550598145,1.5545729398727417,3.054399251937866,4.675719738006592,6.195427417755127,7.4982218742370605,8.538782119750977,9.301715850830078,9.779485702514648,9.966057777404785,9.858304977416992,9.459100723266602,8.779397964477539,7.838820934295654,6.665206432342529,...] with an element-wise tolerance of 0.000008.
+PASS Output of bandpass filter with detune automation equals [0,0.0008333204896189272,0.0014042853144928813,0.0003864644968416542,0.0001289713109144941,0.0012249316787347198,0.0011354259913787246,0.00006134019349701703,0.00048309186240658164,0.0014227250358089805,0.0007017588941380382,-0.000017982178178499453,0.0009253751486539841,0.0013467228272929788,0.0002655529824551195,0.00017780107737053186,...] with an element-wise tolerance of 0.000005.
+PASS Output of peaking filter with automation of all parameters equals [0,0.9876883625984192,-0.30901700258255005,-0.8910065293312073,0.5877852439880371,0.7071067690849304,-0.80901700258255,-0.45399048924446106,0.9510565400123596,0.15643446147441864,-1,0.15643446147441864,0.9510565400123596,-0.45399048924446106,-0.80901700258255,0.7071067690849304,...] with an element-wise tolerance of 0.00033.
+PASS Output of bandpass filter with sinusoidal modulation of bandpass center frequency equals [0,0.0018003738950937986,0.00716581242159009,0.015862563624978065,0.027496544644236565,0.04151911661028862,0.05723972246050835,0.07384545356035233,0.09042731672525406,0.10601259768009186,0.11960244923830032,0.13021349906921387,0.13692189753055573,0.13890819251537323,0.13550083339214325,0.12621651589870453,...] with an element-wise tolerance of 0.000004.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-automation.html b/third_party/WebKit/LayoutTests/webaudio/biquad-automation.html
new file mode 100644
index 0000000..df36b8f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/webaudio/biquad-automation.html
@@ -0,0 +1,356 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Biquad Automation Test</title>
+    <script src="../resources/js-test.js"></script>
+    <script src="resources/compatibility.js"></script>
+    <script src="resources/audio-testing.js"></script>
+    <script src="resources/biquad-testing.js"></script>
+    <script src="resources/audioparam-testing.js"></script>
+  </head>
+  <body>
+    <script>
+      description("Test Automation of Biquad Filters");
+
+      window.jsTestIsAsync = true;
+
+      // Don't need to run these tests at high sampling rate, so just use a low one to reduce memory
+      // usage and complexity.
+      var sampleRate = 16000;
+
+      // How long to render for each test.
+      var renderDuration = 1;
+
+      var audit = Audit.createTaskRunner();
+
+      // The definition of the linear ramp automation function.
+      function linearRamp(t, v0, v1, t0, t1) {
+        return v0 + (v1 - v0) * (t - t0) / (t1 - t0);
+      }
+
+      // Generate the filter coefficients for the specified filter using the given parameters for
+      // the given duration.  |filterTypeFunction| is a function that returns the filter
+      // coefficients for one set of parameters.  |parameters| is a property bag that contains the
+      // start and end values (as an array) for each of the biquad attributes.  The properties are
+      // |freq|, |Q|, |gain|, and |detune|.  |duration| is the number of seconds for which the
+      // coefficients are generated.
+      //
+      // A property bag with properties |b0|, |b1|, |b2|, |a1|, |a2|.  Each propery is an array
+      // consisting of the coefficients for the time-varying biquad filter.
+      function generateFilterCoefficients(filterTypeFunction, parameters, duration) {
+         var endFrame = Math.ceil(duration * sampleRate);
+         var nCoef = endFrame;
+         var b0 = new Float64Array(nCoef);
+         var b1 = new Float64Array(nCoef);
+         var b2 = new Float64Array(nCoef);
+         var a1 = new Float64Array(nCoef);
+         var a2 = new Float64Array(nCoef);
+
+         var k = 0;
+         // If the property is not given, use the defaults.
+         var freqs = parameters.freq || [350, 350];
+         var qs = parameters.Q || [1, 1];
+         var gains = parameters.gain || [0, 0];
+         var detunes = parameters.detune || [0, 0];
+
+         for (var frame = 0; frame < endFrame; ++frame) {
+            // Apply linear ramp at frame |frame|.
+            var f = linearRamp(frame / sampleRate, freqs[0], freqs[1], 0, duration);
+            var q = linearRamp(frame / sampleRate, qs[0], qs[1], 0, duration);
+            var g = linearRamp(frame / sampleRate, gains[0], gains[1], 0, duration);
+            var d = linearRamp(frame / sampleRate, detunes[0], detunes[1], 0, duration);
+
+            // Compute actual frequency parameter
+            f = f * Math.pow(2, d / 1200);
+
+            // Compute filter coefficients
+            var coef = filterTypeFunction(f / (sampleRate / 2), q, g);
+            b0[k] = coef.b0;
+            b1[k] = coef.b1;
+            b2[k] = coef.b2;
+            a1[k] = coef.a1;
+            a2[k] = coef.a2;
+            ++k;
+         }
+
+         return {b0: b0, b1: b1, b2: b2, a1: a1, a2: a2};
+      }
+
+      // Apply the given time-varying biquad filter to the given signal, |signal|.  |coef| should be
+      // the time-varying coefficients of the filter, as returned by |generateFilterCoefficients|.
+      function timeVaryingFilter(signal, coef) {
+        var length = signal.length;
+        // Use double precision for the internal computations.
+        var y = new Float64Array(length);
+
+        // Prime the pump. (Assumes the signal has length >= 2!)
+        y[0] = coef.b0[0] * signal[0];
+        y[1] = coef.b0[1] * signal[1] + coef.b1[1] * signal[0] - coef.a1[1] * y[0];
+
+        for (var n = 2; n < length; ++n) {
+          y[n] = coef.b0[n] * signal[n] + coef.b1[n] * signal[n-1] + coef.b2[n] * signal[n-2];
+          y[n] -= coef.a1[n] * y[n-1] + coef.a2[n] * y[n-2];
+        }
+
+        // But convert the result to single precision for comparison.
+        return y.map(Math.fround);
+      }
+
+      // Configure the audio graph using |context|.  Returns the biquad filter node and the
+      // AudioBuffer used for the source.
+      function configureGraph(context, toneFrequency) {
+        // The source is just a simple sine wave.
+        var src = context.createBufferSource();
+        var b = context.createBuffer(1, renderDuration * sampleRate, sampleRate);
+        var data = b.getChannelData(0);
+        var omega = 2 * Math.PI * toneFrequency / sampleRate;
+        for (var k = 0; k < data.length; ++k) {
+          data[k] = Math.sin(omega * k);
+        }
+        src.buffer = b;
+        var f = context.createBiquadFilter();
+        src.connect(f);
+        f.connect(context.destination);
+
+        src.start();
+
+        return {filter: f, source: b};
+      }
+
+      function createFilterVerifier(filterCreator, threshold, parameters, input, message) {
+        return function (resultBuffer) {
+          var actual = resultBuffer.getChannelData(0);
+          var coefs = generateFilterCoefficients(filterCreator, parameters, renderDuration);
+
+          reference = timeVaryingFilter(input, coefs);
+
+          Should(message, actual).beCloseToArray(reference, threshold);
+        };
+      }
+
+      // Automate just the frequency parameter.  A bandpass filter is used where the center
+      // frequency is swept across the source (which is a simple tone).
+      audit.defineTask("automate-freq", function (done) {
+        var context = new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
+
+        // Center frequency of bandpass filter and also the frequency of the test tone.
+        var centerFreq = 10*440;
+
+        // Sweep the frequency +/- 9*440 Hz from the center.  This should cause the output to low at
+        // the beginning and end of the test where the done is outside the pass band of the filter,
+        // but high in the center where the tone is near the center of the pass band.
+        var parameters = {
+          freq: [centerFreq - 9*440, centerFreq + 9*440]
+        }
+        var graph = configureGraph(context, centerFreq);
+        var f = graph.filter;
+        var b = graph.source;
+
+        f.type = "bandpass";
+        f.frequency.setValueAtTime(parameters.freq[0], 0);
+        f.frequency.linearRampToValueAtTime(parameters.freq[1], renderDuration);
+
+        context.startRendering()
+          .then(createFilterVerifier(createBandpassFilter, 5e-5, parameters, b.getChannelData(0),
+            "Output of bandpass filter with frequency automation"))
+          .then(done);
+      });
+
+      // Automate just the Q parameter.  A bandpass filter is used where the Q of the filter is
+      // swept.
+      audit.defineTask("automate-q", function (done) {
+        var context = new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
+
+        // The frequency of the test tone.
+        var centerFreq = 440;
+
+        // Sweep the Q paramter between 1 and 200.  This will cause the output of the filter to pass
+        // most of the tone at the beginning to passing less of the tone at the end.  This is
+        // because we set center frequency of the bandpass filter to be slightly off from the actual
+        // tone.
+        var parameters = {
+          Q: [1, 200],
+          // Center frequency of the bandpass filter is just 25 Hz above the tone frequency.
+          freq: [centerFreq + 25, centerFreq + 25]
+        };
+        var graph = configureGraph(context, centerFreq);
+        var f = graph.filter;
+        var b = graph.source;
+
+        f.type = "bandpass";
+        f.frequency.value = parameters.freq[0];
+        f.Q.setValueAtTime(parameters.Q[0], 0);
+        f.Q.linearRampToValueAtTime(parameters.Q[1], renderDuration);
+
+        context.startRendering()
+          .then(createFilterVerifier(createBandpassFilter, 1.4e-6, parameters, b.getChannelData(0),
+            "Output of bandpass filter with Q automation"))
+          .then(done);
+      });
+
+      // Automate just the gain of the lowshelf filter.  A test tone will be in the lowshelf part of
+      // the filter.  The output will vary as the gain of the lowshelf is changed.
+      audit.defineTask("automate-gain", function (done) {
+        var context = new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
+
+        // Frequency of the test tone.
+        var centerFreq = 440;
+
+        // Set the cutoff frequency of the lowshelf to be significantly higher than the test tone.
+        // Sweep the gain from 20 dB to -20 dB.  (We go from 20 to -20 to easily verify that the
+        // filter didn't go unstable.)
+        var parameters = {
+          freq: [3500, 3500],
+          gain: [20, -20]
+        }
+        var graph = configureGraph(context, centerFreq);
+        var f = graph.filter;
+        var b = graph.source;
+
+        f.type = "lowshelf";
+        f.frequency.value = parameters.freq[0];
+        f.gain.setValueAtTime(parameters.gain[0], 0);
+        f.gain.linearRampToValueAtTime(parameters.gain[1], renderDuration);
+
+        context.startRendering()
+          .then(createFilterVerifier(createLowShelfFilter, 8e-6, parameters, b.getChannelData(0),
+            "Output of lowshelf filter with gain automation"))
+          .then(done);
+      });
+
+      // Automate just the detune parameter.  Basically the same test as for the frequncy parameter
+      // but we just use the detune parameter to modulate the frequency parameter.
+      audit.defineTask("automate-detune", function (done) {
+        var context = new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
+        var centerFreq = 10*440;
+        var parameters = {
+          freq: [centerFreq, centerFreq],
+          detune: [-10*1200, 10*1200]
+        };
+        var graph = configureGraph(context, centerFreq);
+        var f = graph.filter;
+        var b = graph.source;
+
+        f.type = "bandpass";
+        f.frequency.value = parameters.freq[0];
+        f.detune.setValueAtTime(parameters.detune[0], 0);
+        f.detune.linearRampToValueAtTime(parameters.detune[1], renderDuration);
+
+        context.startRendering()
+          .then(createFilterVerifier(createBandpassFilter, 5e-6, parameters, b.getChannelData(0),
+            "Output of bandpass filter with detune automation"))
+          .then(done);
+      });
+
+      // Automate all of the filter parameters at once.  This is a basic check that everything is
+      // working.  A peaking filter is used because it uses all of the parameters.
+      audit.defineTask("automate-all", function (done) {
+        var context = new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
+        var graph = configureGraph(context, 10*440);
+        var f = graph.filter;
+        var b = graph.source;
+
+        // Sweep all of the filter parameters.  These are pretty much arbitrary.
+        var parameters = {
+          freq: [10000, 100],
+          Q: [f.Q.value, .0001],
+          gain: [f.gain.value, 20],
+          detune: [2400, -2400]
+        };
+
+        f.type = "peaking";
+        // Set starting points for all parameters of the filter.  Start at 10 kHz for the center
+        // frequency, and the defaults for Q and gain.
+        f.frequency.setValueAtTime(parameters.freq[0], 0);
+        f.Q.setValueAtTime(parameters.Q[0], 0);
+        f.gain.setValueAtTime(parameters.gain[0], 0);
+        f.detune.setValueAtTime(parameters.detune[0], 0);
+
+        // Linear ramp each parameter
+        f.frequency.linearRampToValueAtTime(parameters.freq[1], renderDuration);
+        f.Q.linearRampToValueAtTime(parameters.Q[1], renderDuration);
+        f.gain.linearRampToValueAtTime(parameters.gain[1], renderDuration);
+        f.detune.linearRampToValueAtTime(parameters.detune[1], renderDuration);
+
+        context.startRendering()
+          .then(createFilterVerifier(createPeakingFilter, 3.3e-4, parameters, b.getChannelData(0),
+            "Output of peaking filter with automation of all parameters"))
+          .then(done);
+      });
+
+      // Test that modulation of the frequency parameter of the filter works.  A sinusoid of 440 Hz
+      // is the test signal that is applied to a bandpass biquad filter.  The frequency parameter of
+      // the filter is modulated by a sinusoid at 103 Hz, and the frequency modulation varies from
+      // 116 to 412 Hz.  (This test was taken from the description in
+      // https://github.com/WebAudio/web-audio-api/issues/509#issuecomment-94731355)
+      audit.defineTask("modulation", function (done) {
+        var context = new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
+
+        // Create a graph with the sinusoidal source at 440 Hz as the input to a biquad filter.
+        var graph = configureGraph(context, 440);
+        var f = graph.filter;
+        var b = graph.source;
+
+        f.type = "bandpass";
+        f.Q.value = 5;
+        f.frequency.value = 264;
+
+        // Create the modulation source, a sinusoid with frequency 103 Hz and amplitude 148.  (The
+        // amplitude of 148 is added to the filter's frequency value of 264 to produce a sinusoidal
+        // modulation of the frequency parameter from 116 to 412 Hz.)
+        var mod = context.createBufferSource();
+        var mbuffer = context.createBuffer(1, renderDuration * sampleRate, sampleRate);
+        var d = mbuffer.getChannelData(0);
+        var omega = 2 * Math.PI * 103 / sampleRate;
+        for (var k = 0; k < d.length; ++k) {
+          d[k] = 148 * Math.sin(omega * k);
+        }
+        mod.buffer = mbuffer;
+
+        mod.connect(f.frequency);
+      
+        mod.start();
+        context.startRendering()
+          .then(function (resultBuffer) {
+             var actual = resultBuffer.getChannelData(0);
+             // Compute the filter coefficients using the mod sine wave
+             
+             var endFrame = Math.ceil(renderDuration * sampleRate);
+             var nCoef = endFrame;
+             var b0 = new Float64Array(nCoef);
+             var b1 = new Float64Array(nCoef);
+             var b2 = new Float64Array(nCoef);
+             var a1 = new Float64Array(nCoef);
+             var a2 = new Float64Array(nCoef);
+
+             // Generate the filter coefficients when the frequency varies from 116 to 248 Hz using
+             // the 103 Hz sinusoid.
+             for (var k = 0; k < nCoef; ++k) {
+               var freq = f.frequency.value + d[k];
+               var c = createBandpassFilter(freq / (sampleRate / 2), f.Q.value, f.gain.value);
+               b0[k] = c.b0;
+               b1[k] = c.b1;
+               b2[k] = c.b2;
+               a1[k] = c.a1;
+               a2[k] = c.a2;
+             }
+             reference = timeVaryingFilter(b.getChannelData(0),
+               {b0: b0, b1: b1, b2: b2, a1: a1, a2: a2});
+
+             Should("Output of bandpass filter with sinusoidal modulation of bandpass center frequency",
+               actual)
+               .beCloseToArray(reference, 4e-6);
+           })
+          .then(done);
+      });
+
+      // All done!
+      audit.defineTask("finish", function (done) {
+        finishJSTest();
+        done();
+      });
+
+      audit.runTasks();
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
index fcc6b0a..6977796 100644
--- a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
@@ -294,6 +294,7 @@
     property currentTime
     property defaultMuted
     property defaultPlaybackRate
+    property disableRemotePlayback
     property duration
     property ended
     property error
@@ -1037,6 +1038,7 @@
     property currentTime
     property defaultMuted
     property defaultPlaybackRate
+    property disableRemotePlayback
     property duration
     property ended
     property error
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 45b0221..dde3259 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -2390,6 +2390,7 @@
     getter currentTime
     getter defaultMuted
     getter defaultPlaybackRate
+    getter disableRemotePlayback
     getter duration
     getter ended
     getter error
@@ -2433,6 +2434,7 @@
     setter currentTime
     setter defaultMuted
     setter defaultPlaybackRate
+    setter disableRemotePlayback
     setter loop
     setter muted
     setter onencrypted
diff --git a/third_party/WebKit/Source/bindings/core/v8/RejectedPromises.cpp b/third_party/WebKit/Source/bindings/core/v8/RejectedPromises.cpp
index 03638df9..564d9cd 100644
--- a/third_party/WebKit/Source/bindings/core/v8/RejectedPromises.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/RejectedPromises.cpp
@@ -148,8 +148,7 @@
 
     bool hasHandler()
     {
-        if (isCollected())
-            return false;
+        ASSERT(!isCollected());
         ScriptState::Scope scope(m_scriptState);
         v8::Local<v8::Value> value = m_promise.newLocal(m_scriptState->isolate());
         return v8::Local<v8::Promise>::Cast(value)->HasHandler();
@@ -275,6 +274,8 @@
 
     while (!queue->isEmpty()) {
         OwnPtrWillBeRawPtr<Message> message = queue->takeFirst();
+        if (message->isCollected())
+            continue;
         if (!message->hasHandler()) {
             message->report();
             message->makePromiseWeak();
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.cpp b/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.cpp
index eba7566..7602a27a 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.cpp
@@ -56,24 +56,35 @@
 
 static void useCounterCallback(v8::Isolate* isolate, v8::Isolate::UseCounterFeature feature)
 {
+    UseCounter::Feature blinkFeature;
     switch (feature) {
     case v8::Isolate::kUseAsm:
-        UseCounter::count(callingExecutionContext(isolate), UseCounter::UseAsm);
+        blinkFeature = UseCounter::UseAsm;
         break;
     case v8::Isolate::kBreakIterator:
-        UseCounter::count(callingExecutionContext(isolate), UseCounter::BreakIterator);
+        blinkFeature = UseCounter::BreakIterator;
         break;
     case v8::Isolate::kLegacyConst:
-        UseCounter::count(callingExecutionContext(isolate), UseCounter::LegacyConst);
+        blinkFeature = UseCounter::LegacyConst;
         break;
     case v8::Isolate::kObjectObserve:
-        UseCounter::count(callingExecutionContext(isolate), UseCounter::ObjectObserve);
+        blinkFeature = UseCounter::ObjectObserve;
+        break;
+    case v8::Isolate::kSloppyMode:
+        blinkFeature = UseCounter::V8SloppyMode;
+        break;
+    case v8::Isolate::kStrictMode:
+        blinkFeature = UseCounter::V8StrictMode;
+        break;
+    case v8::Isolate::kStrongMode:
+        blinkFeature = UseCounter::V8StrongMode;
         break;
     default:
         // This can happen if V8 has added counters that this version of Blink
         // does not know about. It's harmless.
-        break;
+        return;
     }
+    UseCounter::count(callingExecutionContext(isolate), blinkFeature);
 }
 
 V8PerIsolateData::V8PerIsolateData()
diff --git a/third_party/WebKit/Source/build/scripts/make_css_property_names.py b/third_party/WebKit/Source/build/scripts/make_css_property_names.py
index 5049e092..17d71a3 100755
--- a/third_party/WebKit/Source/build/scripts/make_css_property_names.py
+++ b/third_party/WebKit/Source/build/scripts/make_css_property_names.py
@@ -87,6 +87,13 @@
 #include "wtf/text/AtomicString.h"
 #include "wtf/text/WTFString.h"
 
+#ifdef _MSC_VER
+// Disable the warnings from casting a 64-bit pointer to 32-bit long
+// warning C4302: 'type cast': truncation from 'char (*)[28]' to 'long'
+// warning C4311: 'type cast': pointer truncation from 'char (*)[18]' to 'long'
+#pragma warning(disable : 4302 4311)
+#endif
+
 namespace blink {
 static const char propertyNameStringsPool[] = {
 %(property_name_strings)s
diff --git a/third_party/WebKit/Source/build/scripts/make_css_value_keywords.py b/third_party/WebKit/Source/build/scripts/make_css_value_keywords.py
index 8c2430d9..8ac8c02 100755
--- a/third_party/WebKit/Source/build/scripts/make_css_value_keywords.py
+++ b/third_party/WebKit/Source/build/scripts/make_css_value_keywords.py
@@ -46,6 +46,13 @@
 #include "core/css/HashTools.h"
 #include <string.h>
 
+#ifdef _MSC_VER
+// Disable the warnings from casting a 64-bit pointer to 32-bit long
+// warning C4302: 'type cast': truncation from 'char (*)[28]' to 'long'
+// warning C4311: 'type cast': pointer truncation from 'char (*)[18]' to 'long'
+#pragma warning(disable : 4302 4311)
+#endif
+
 namespace blink {
 static const char valueListStringPool[] = {
 %(value_keyword_strings)s
diff --git a/third_party/WebKit/Source/core/animation/SVGInterpolation.cpp b/third_party/WebKit/Source/core/animation/SVGInterpolation.cpp
deleted file mode 100644
index ee55150..0000000
--- a/third_party/WebKit/Source/core/animation/SVGInterpolation.cpp
+++ /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.
-
-#include "config.h"
-#include "core/animation/SVGInterpolation.h"
-
-#include "core/svg/SVGAnimateElement.h" // findElementInstances
-
-namespace blink {
-
-void SVGInterpolation::apply(SVGElement& targetElement) const
-{
-    SVGElement::InstanceUpdateBlocker blocker(&targetElement);
-    RefPtrWillBeRawPtr<SVGPropertyBase> value = interpolatedValue(targetElement);
-    SVGElementInstances instances = SVGAnimateElement::findElementInstances(&targetElement);
-
-    for (SVGElement* element : instances) {
-        RefPtrWillBeRawPtr<SVGAnimatedPropertyBase> animatedProperty =
-            element->propertyFromAttribute(attributeName());
-        if (animatedProperty) {
-            animatedProperty->setAnimatedValue(value);
-            element->invalidateSVGAttributes();
-            element->svgAttributeChanged(attributeName());
-        }
-    }
-}
-
-}
diff --git a/third_party/WebKit/Source/core/animation/SVGInterpolation.h b/third_party/WebKit/Source/core/animation/SVGInterpolation.h
index e9e0af9..986395b1 100644
--- a/third_party/WebKit/Source/core/animation/SVGInterpolation.h
+++ b/third_party/WebKit/Source/core/animation/SVGInterpolation.h
@@ -24,7 +24,10 @@
         return PropertyHandle(attributeName());
     }
 
-    void apply(SVGElement&) const;
+    void apply(SVGElement& targetElement) const
+    {
+        targetElement.setWebAnimatedAttribute(attributeName(), interpolatedValue(targetElement));
+    }
 
     virtual PassRefPtrWillBeRawPtr<SVGPropertyBase> interpolatedValue(SVGElement&) const = 0;
 
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi
index 33e5333..00b0105 100644
--- a/third_party/WebKit/Source/core/core.gypi
+++ b/third_party/WebKit/Source/core/core.gypi
@@ -513,6 +513,7 @@
             'layout/CounterNode.h',
             'layout/FloatingObjects.cpp',
             'layout/FloatingObjects.h',
+            'layout/FragmentationContext.h',
             'layout/GeneratedChildren.h',
             'layout/HitTestCache.cpp',
             'layout/HitTestCache.h',
@@ -695,6 +696,8 @@
             'layout/TracedLayoutObject.cpp',
             'layout/TracedLayoutObject.h',
             'layout/VerticalPositionCache.h',
+            'layout/ViewFragmentationContext.cpp',
+            'layout/ViewFragmentationContext.h',
             'layout/compositing/CompositedLayerMapping.cpp',
             'layout/compositing/CompositedLayerMapping.h',
             'layout/compositing/CompositingInputsUpdater.cpp',
@@ -912,7 +915,6 @@
             'animation/SVGIntegerInterpolationType.h',
             'animation/SVGIntegerOptionalIntegerInterpolationType.cpp',
             'animation/SVGIntegerOptionalIntegerInterpolationType.h',
-            'animation/SVGInterpolation.cpp',
             'animation/SVGInterpolation.h',
             'animation/SVGInterpolationType.cpp',
             'animation/SVGInterpolationType.h',
@@ -3867,6 +3869,7 @@
             'fetch/ResourceTest.cpp',
             'fileapi/FileListTest.cpp',
             'fileapi/FileTest.cpp',
+            'frame/FrameViewDidPaintTest.cpp',
             'frame/ImageBitmapTest.cpp',
             'frame/OriginsUsingFeaturesTest.cpp',
             'frame/RootFrameViewportTest.cpp',
diff --git a/third_party/WebKit/Source/core/css/CSS.idl b/third_party/WebKit/Source/core/css/CSS.idl
index 9ea911af..185541c4 100644
--- a/third_party/WebKit/Source/core/css/CSS.idl
+++ b/third_party/WebKit/Source/core/css/CSS.idl
@@ -35,5 +35,5 @@
 ] interface CSS {
     static boolean supports(DOMString property, DOMString value);
     static boolean supports(DOMString conditionText);
-    [RaisesException] static DOMString escape(DOMString ident);
+    static DOMString escape(DOMString ident);
 };
diff --git a/third_party/WebKit/Source/core/css/CSSMarkup.cpp b/third_party/WebKit/Source/core/css/CSSMarkup.cpp
index 7c5e8905..8515fca 100644
--- a/third_party/WebKit/Source/core/css/CSSMarkup.cpp
+++ b/third_party/WebKit/Source/core/css/CSSMarkup.cpp
@@ -200,7 +200,7 @@
     appendTo.append(' ');
 }
 
-bool serializeIdentifier(const String& identifier, StringBuilder& appendTo)
+void serializeIdentifier(const String& identifier, StringBuilder& appendTo)
 {
     bool isFirst = true;
     bool isSecond = false;
@@ -211,13 +211,13 @@
         if (c == 0) {
             // Check for lone surrogate which characterStartingAt does not return.
             c = identifier[index];
-            if (c == 0)
-                return false;
         }
 
         index += U16_LENGTH(c);
 
-        if (c <= 0x1f || c == 0x7f || (0x30 <= c && c <= 0x39 && (isFirst || (isSecond && isFirstCharHyphen))))
+        if (c == 0)
+            appendTo.append(0xfffd);
+        else if (c <= 0x1f || c == 0x7f || (0x30 <= c && c <= 0x39 && (isFirst || (isSecond && isFirstCharHyphen))))
             serializeCharacterAsCodePoint(c, appendTo);
         else if (c == 0x2d && isFirst && index == identifier.length())
             serializeCharacter(c, appendTo);
@@ -234,7 +234,6 @@
             isSecond = false;
         }
     }
-    return true;
 }
 
 void serializeString(const String& string, StringBuilder& appendTo)
diff --git a/third_party/WebKit/Source/core/css/CSSMarkup.h b/third_party/WebKit/Source/core/css/CSSMarkup.h
index 4da7037f..9371e94 100644
--- a/third_party/WebKit/Source/core/css/CSSMarkup.h
+++ b/third_party/WebKit/Source/core/css/CSSMarkup.h
@@ -33,7 +33,7 @@
 String quoteCSSURLIfNeeded(const String&);
 
 // Common serializing methods. See: http://dev.w3.org/csswg/cssom/#common-serializing-idioms
-bool serializeIdentifier(const String& identifier, StringBuilder& appendTo);
+void serializeIdentifier(const String& identifier, StringBuilder& appendTo);
 void serializeString(const String&, StringBuilder& appendTo);
 String serializeString(const String&);
 String serializeURI(const String&);
diff --git a/third_party/WebKit/Source/core/css/DOMWindowCSS.cpp b/third_party/WebKit/Source/core/css/DOMWindowCSS.cpp
index be978a7..8b05f6d03 100644
--- a/third_party/WebKit/Source/core/css/DOMWindowCSS.cpp
+++ b/third_party/WebKit/Source/core/css/DOMWindowCSS.cpp
@@ -30,12 +30,10 @@
 #include "config.h"
 #include "core/css/DOMWindowCSS.h"
 
-#include "bindings/core/v8/ExceptionState.h"
 #include "core/css/CSSMarkup.h"
 #include "core/css/CSSPropertyMetadata.h"
 #include "core/css/StylePropertySet.h"
 #include "core/css/parser/CSSParser.h"
-#include "core/dom/ExceptionCode.h"
 #include "wtf/text/StringBuilder.h"
 #include "wtf/text/WTFString.h"
 
@@ -58,13 +56,10 @@
     return CSSParser::parseSupportsCondition(conditionText);
 }
 
-String DOMWindowCSS::escape(const String& ident, ExceptionState& exceptionState)
+String DOMWindowCSS::escape(const String& ident)
 {
     StringBuilder builder;
-    if (!serializeIdentifier(ident, builder)) {
-        exceptionState.throwDOMException(InvalidCharacterError, "The string contains an invalid character.");
-        return String();
-    }
+    serializeIdentifier(ident, builder);
     return builder.toString();
 }
 
diff --git a/third_party/WebKit/Source/core/css/DOMWindowCSS.h b/third_party/WebKit/Source/core/css/DOMWindowCSS.h
index 8492a2dd..8f87267 100644
--- a/third_party/WebKit/Source/core/css/DOMWindowCSS.h
+++ b/third_party/WebKit/Source/core/css/DOMWindowCSS.h
@@ -38,14 +38,12 @@
 
 namespace blink {
 
-class ExceptionState;
-
 class DOMWindowCSS : public RefCountedWillBeGarbageCollected<DOMWindowCSS>, public ScriptWrappable {
     DEFINE_WRAPPERTYPEINFO();
 public:
     static bool supports(const String& property, const String& value);
     static bool supports(const String& conditionText);
-    static String escape(const String& ident, ExceptionState&);
+    static String escape(const String& ident);
 
     DEFINE_INLINE_TRACE() { }
 
diff --git a/third_party/WebKit/Source/core/css/SelectorChecker.cpp b/third_party/WebKit/Source/core/css/SelectorChecker.cpp
index 1f1f39e7..025b180 100644
--- a/third_party/WebKit/Source/core/css/SelectorChecker.cpp
+++ b/third_party/WebKit/Source/core/css/SelectorChecker.cpp
@@ -1160,7 +1160,7 @@
         return part == BackButtonEndPart || part == ForwardButtonEndPart || part == ForwardTrackPart;
     case CSSSelector::PseudoDoubleButton:
         {
-            ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
+            ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme().buttonsPlacement();
             if (part == BackButtonStartPart || part == ForwardButtonStartPart || part == BackTrackPart)
                 return buttonsPlacement == ScrollbarButtonsPlacementDoubleStart || buttonsPlacement == ScrollbarButtonsPlacementDoubleBoth;
             if (part == BackButtonEndPart || part == ForwardButtonEndPart || part == ForwardTrackPart)
@@ -1169,14 +1169,14 @@
         }
     case CSSSelector::PseudoSingleButton:
         {
-            ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
+            ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme().buttonsPlacement();
             if (part == BackButtonStartPart || part == ForwardButtonEndPart || part == BackTrackPart || part == ForwardTrackPart)
                 return buttonsPlacement == ScrollbarButtonsPlacementSingle;
             return false;
         }
     case CSSSelector::PseudoNoButton:
         {
-            ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
+            ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme().buttonsPlacement();
             if (part == BackTrackPart)
                 return buttonsPlacement == ScrollbarButtonsPlacementNone || buttonsPlacement == ScrollbarButtonsPlacementDoubleEnd;
             if (part == ForwardTrackPart)
diff --git a/third_party/WebKit/Source/core/css/cssom/KeywordValue.cpp b/third_party/WebKit/Source/core/css/cssom/KeywordValue.cpp
index 41f9c6e..ecf3033 100644
--- a/third_party/WebKit/Source/core/css/cssom/KeywordValue.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/KeywordValue.cpp
@@ -54,7 +54,7 @@
     return keywordValue();
 }
 
-PassRefPtrWillBeRawPtr<CSSValue> KeywordValue::toCSSValue()
+PassRefPtrWillBeRawPtr<CSSValue> KeywordValue::toCSSValue() const
 {
     switch (m_keywordValue) {
     case Initial:
diff --git a/third_party/WebKit/Source/core/css/cssom/KeywordValue.h b/third_party/WebKit/Source/core/css/cssom/KeywordValue.h
index 5816fe37..05e9b99 100644
--- a/third_party/WebKit/Source/core/css/cssom/KeywordValue.h
+++ b/third_party/WebKit/Source/core/css/cssom/KeywordValue.h
@@ -24,7 +24,7 @@
     virtual const String& keywordValue() const;
 
     String cssString() const override;
-    PassRefPtrWillBeRawPtr<CSSValue> toCSSValue() override;
+    PassRefPtrWillBeRawPtr<CSSValue> toCSSValue() const override;
 
 protected:
     KeywordValue(const String& keyword) : m_keywordValue(keywordValueFromString(keyword)) {}
diff --git a/third_party/WebKit/Source/core/css/cssom/NumberValue.h b/third_party/WebKit/Source/core/css/cssom/NumberValue.h
index ed4bfc2..43853b2 100644
--- a/third_party/WebKit/Source/core/css/cssom/NumberValue.h
+++ b/third_party/WebKit/Source/core/css/cssom/NumberValue.h
@@ -25,7 +25,7 @@
 
     String cssString() const override { return String::number(m_value); }
 
-    PassRefPtrWillBeRawPtr<CSSValue> toCSSValue() override
+    PassRefPtrWillBeRawPtr<CSSValue> toCSSValue() const override
     {
         return cssValuePool().createValue(m_value, CSSPrimitiveValue::UnitType::
 Number);
diff --git a/third_party/WebKit/Source/core/css/cssom/StyleValue.h b/third_party/WebKit/Source/core/css/cssom/StyleValue.h
index 2b70c7c5..3c25cf40 100644
--- a/third_party/WebKit/Source/core/css/cssom/StyleValue.h
+++ b/third_party/WebKit/Source/core/css/cssom/StyleValue.h
@@ -25,7 +25,7 @@
     static ScriptValue parse(ScriptState*, const String& property, const String& cssText);
 
     virtual String cssString() const = 0;
-    virtual PassRefPtrWillBeRawPtr<CSSValue> toCSSValue() = 0;
+    virtual PassRefPtrWillBeRawPtr<CSSValue> toCSSValue() const = 0;
 
     DEFINE_INLINE_VIRTUAL_TRACE() { }
 
diff --git a/third_party/WebKit/Source/core/css/html.css b/third_party/WebKit/Source/core/css/html.css
index 41cae015..3752a17 100644
--- a/third_party/WebKit/Source/core/css/html.css
+++ b/third_party/WebKit/Source/core/css/html.css
@@ -1120,11 +1120,5 @@
     border-width: 0px;
 }
 
-/* Disable multicol in printing, since it's not implemented properly. See crbug.com/99358 */
-
-@media print {
-    * { -webkit-columns: auto !important; }
-}
-
 /* noscript is handled internally, as it depends on settings. */
 
diff --git a/third_party/WebKit/Source/core/css/invalidation/StyleInvalidator.cpp b/third_party/WebKit/Source/core/css/invalidation/StyleInvalidator.cpp
index db5fa17..453479c8 100644
--- a/third_party/WebKit/Source/core/css/invalidation/StyleInvalidator.cpp
+++ b/third_party/WebKit/Source/core/css/invalidation/StyleInvalidator.cpp
@@ -43,23 +43,22 @@
 void StyleInvalidator::scheduleInvalidationSetsForElement(const InvalidationLists& invalidationLists, Element& element)
 {
     ASSERT(element.inActiveDocument());
-    if (element.styleChangeType() >= SubtreeStyleChange)
-        return;
-
     bool requiresDescendantInvalidation = false;
 
-    for (auto& invalidationSet : invalidationLists.descendants) {
-        if (invalidationSet->wholeSubtreeInvalid()) {
-            element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator));
-            clearInvalidation(element);
-            return;
+    if (element.styleChangeType() < SubtreeStyleChange) {
+        for (auto& invalidationSet : invalidationLists.descendants) {
+            if (invalidationSet->wholeSubtreeInvalid()) {
+                element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator));
+                requiresDescendantInvalidation = false;
+                break;
+            }
+
+            if (invalidationSet->invalidatesSelf())
+                element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator));
+
+            if (!invalidationSet->isEmpty())
+                requiresDescendantInvalidation = true;
         }
-
-        if (invalidationSet->invalidatesSelf())
-            element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator));
-
-        if (!invalidationSet->isEmpty())
-            requiresDescendantInvalidation = true;
     }
 
     if (invalidationLists.siblings.isEmpty() && !requiresDescendantInvalidation)
diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
index 8673868..57c8b523 100644
--- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
@@ -3905,7 +3905,7 @@
     BorderImageSliceParseContext context;
     for (CSSParserValue* val = m_valueList->current(); val; val = m_valueList->next()) {
         // FIXME calc() http://webkit.org/b/16662 : calc is parsed but values are not created yet.
-        if (context.allowNumber() && !isCalculation(val) && validUnit(val, FInteger | FNonNeg | FPercent)) {
+        if (context.allowNumber() && !isCalculation(val) && validUnit(val, FNumber | FNonNeg | FPercent)) {
             context.commitNumber(createPrimitiveNumericValue(val));
         } else if (context.allowFill() && val->id == CSSValueFill) {
             context.commitFill();
diff --git a/third_party/WebKit/Source/core/css/resolver/CSSToStyleMap.cpp b/third_party/WebKit/Source/core/css/resolver/CSSToStyleMap.cpp
index f838a9a5..dba82c86 100644
--- a/third_party/WebKit/Source/core/css/resolver/CSSToStyleMap.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/CSSToStyleMap.cpp
@@ -484,6 +484,13 @@
     }
 }
 
+static Length convertBorderImageSliceSide(const CSSPrimitiveValue& value)
+{
+    if (value.isPercentage())
+        return Length(value.getDoubleValue(), Percent);
+    return Length(round(value.getDoubleValue()), Fixed);
+}
+
 void CSSToStyleMap::mapNinePieceImageSlice(StyleResolverState&, const CSSValue& value, NinePieceImage& image)
 {
     if (!value.isBorderImageSliceValue())
@@ -495,22 +502,10 @@
     // Set up a length box to represent our image slices.
     LengthBox box;
     CSSQuadValue* slices = borderImageSlice.slices();
-    if (slices->top()->isPercentage())
-        box.m_top = Length(slices->top()->getDoubleValue(), Percent);
-    else
-        box.m_top = Length(slices->top()->getIntValue(), Fixed);
-    if (slices->bottom()->isPercentage())
-        box.m_bottom = Length(slices->bottom()->getDoubleValue(), Percent);
-    else
-        box.m_bottom = Length(slices->bottom()->getIntValue(), Fixed);
-    if (slices->left()->isPercentage())
-        box.m_left = Length(slices->left()->getDoubleValue(), Percent);
-    else
-        box.m_left = Length(slices->left()->getIntValue(), Fixed);
-    if (slices->right()->isPercentage())
-        box.m_right = Length(slices->right()->getDoubleValue(), Percent);
-    else
-        box.m_right = Length(slices->right()->getIntValue(), Fixed);
+    box.m_top = convertBorderImageSliceSide(*slices->top());
+    box.m_bottom = convertBorderImageSliceSide(*slices->bottom());
+    box.m_left = convertBorderImageSliceSide(*slices->left());
+    box.m_right = convertBorderImageSliceSide(*slices->right());
     image.setImageSlices(box);
 
     // Set our fill mode.
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
index 57a0fc5..0d966c4 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
@@ -126,9 +126,9 @@
     return rightToLeftDecl;
 }
 
-static void collectScopedResolversForHostedShadowTrees(const Element* element, WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8>& resolvers)
+static void collectScopedResolversForHostedShadowTrees(const Element& element, WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8>& resolvers)
 {
-    ElementShadow* shadow = element->shadow();
+    ElementShadow* shadow = element.shadow();
     if (!shadow)
         return;
 
@@ -385,7 +385,7 @@
     return treeScope->scopedStyleResolver();
 }
 
-void StyleResolver::matchAuthorRules(Element* element, ElementRuleCollector& collector)
+void StyleResolver::matchAuthorRules(const Element& element, ElementRuleCollector& collector)
 {
     collector.clearMatchedRules();
 
@@ -398,7 +398,7 @@
         resolversInShadowTree.at(j)->collectMatchingShadowHostRules(collector, ++cascadeOrder);
 
     // Apply normal rules from element scope.
-    if (ScopedStyleResolver* resolver = scopedResolverFor(*element))
+    if (ScopedStyleResolver* resolver = scopedResolverFor(element))
         resolver->collectMatchingAuthorRules(collector, ++cascadeOrder);
 
     // Apply /deep/ and ::shadow rules from outer scopes, and ::content from inner.
@@ -456,7 +456,7 @@
         }
     }
 
-    matchAuthorRules(state.element(), collector);
+    matchAuthorRules(*state.element(), collector);
 
     if (state.element()->isStyledElement()) {
         if (state.element()->inlineStyle()) {
@@ -497,7 +497,7 @@
     return scopingNode.treeScope().scopedStyleResolver()->hasDeepOrShadowSelector();
 }
 
-void StyleResolver::collectTreeBoundaryCrossingRules(Element* element, ElementRuleCollector& collector)
+void StyleResolver::collectTreeBoundaryCrossingRules(const Element& element, ElementRuleCollector& collector)
 {
     if (m_treeBoundaryCrossingScopes.isEmpty())
         return;
@@ -510,8 +510,8 @@
     for (const auto& scopingNode : m_treeBoundaryCrossingScopes) {
         // Skip rule collection for element when tree boundary crossing rules of scopingNode's
         // scope can never apply to it.
-        bool isInnerTreeScope = element->treeScope().isInclusiveAncestorOf(scopingNode->treeScope());
-        if (!shouldCheckScope(*element, *scopingNode, isInnerTreeScope))
+        bool isInnerTreeScope = element.treeScope().isInclusiveAncestorOf(scopingNode->treeScope());
+        if (!shouldCheckScope(element, *scopingNode, isInnerTreeScope))
             continue;
 
         CascadeOrder cascadeOrder = isInnerTreeScope ? innerCascadeOrder : outerCascadeOrder;
@@ -796,7 +796,7 @@
         collector.setPseudoStyleRequest(pseudoStyleRequest);
 
         matchUARules(collector);
-        matchAuthorRules(state.element(), collector);
+        matchAuthorRules(*state.element(), collector);
         collector.finishAddingAuthorRulesForTreeScope();
 
         if (!collector.matchedResult().hasMatchedProperties())
@@ -919,7 +919,7 @@
     StyleResolverState state(document(), element);
     ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
     collector.setMode(SelectorChecker::CollectingStyleRules);
-    collectPseudoRulesForElement(element, collector, NOPSEUDO, rulesToInclude);
+    collectPseudoRulesForElement(*element, collector, NOPSEUDO, rulesToInclude);
     return collector.matchedStyleRuleList();
 }
 
@@ -929,7 +929,7 @@
     StyleResolverState state(document(), element);
     ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
     collector.setMode(SelectorChecker::CollectingCSSRules);
-    collectPseudoRulesForElement(element, collector, pseudoId, rulesToInclude);
+    collectPseudoRulesForElement(*element, collector, pseudoId, rulesToInclude);
     return collector.matchedCSSRuleList();
 }
 
@@ -938,7 +938,7 @@
     return pseudoCSSRulesForElement(element, NOPSEUDO, rulesToInclude);
 }
 
-void StyleResolver::collectPseudoRulesForElement(Element* element, ElementRuleCollector& collector, PseudoId pseudoId, unsigned rulesToInclude)
+void StyleResolver::collectPseudoRulesForElement(const Element& element, ElementRuleCollector& collector, PseudoId pseudoId, unsigned rulesToInclude)
 {
     collector.setPseudoStyleRequest(PseudoStyleRequest(pseudoId));
 
@@ -1001,7 +1001,7 @@
 StyleRuleKeyframes* StyleResolver::findKeyframesRule(const Element* element, const AtomicString& animationName)
 {
     WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8> resolvers;
-    collectScopedResolversForHostedShadowTrees(element, resolvers);
+    collectScopedResolversForHostedShadowTrees(*element, resolvers);
     if (ScopedStyleResolver* scopedResolver = element->treeScope().scopedStyleResolver())
         resolvers.append(scopedResolver);
 
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleResolver.h b/third_party/WebKit/Source/core/css/resolver/StyleResolver.h
index 2e3c58a9..bcc878a0 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleResolver.h
+++ b/third_party/WebKit/Source/core/css/resolver/StyleResolver.h
@@ -202,13 +202,13 @@
 
     void appendCSSStyleSheet(CSSStyleSheet&);
 
-    void collectPseudoRulesForElement(Element*, ElementRuleCollector&, PseudoId, unsigned rulesToInclude);
+    void collectPseudoRulesForElement(const Element&, ElementRuleCollector&, PseudoId, unsigned rulesToInclude);
     void matchRuleSet(ElementRuleCollector&, RuleSet*);
     void matchUARules(ElementRuleCollector&);
-    void matchAuthorRules(Element*, ElementRuleCollector&);
+    void matchAuthorRules(const Element&, ElementRuleCollector&);
     void matchAllRules(StyleResolverState&, ElementRuleCollector&, bool includeSMILProperties);
     void collectFeatures();
-    void collectTreeBoundaryCrossingRules(Element*, ElementRuleCollector&);
+    void collectTreeBoundaryCrossingRules(const Element&, ElementRuleCollector&);
     void resetRuleFeatures();
 
     void applyMatchedProperties(StyleResolverState&, const MatchResult&);
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
index 380860b..de447cf4 100644
--- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp
+++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -1079,14 +1079,12 @@
     if (!layoutObject())
         return;
 
-    if (styleChangeType() < SubtreeStyleChange) {
-        if (computedStyle()->affectedByFocus() && computedStyle()->hasPseudoStyle(FIRST_LETTER))
-            setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Focus));
-        else if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByFocus())
-            toElement(this)->pseudoStateChanged(CSSSelector::PseudoFocus);
-        else if (computedStyle()->affectedByFocus())
-            setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Focus));
-    }
+    if (computedStyle()->affectedByFocus() && computedStyle()->hasPseudoStyle(FIRST_LETTER))
+        setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Focus));
+    else if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByFocus())
+        toElement(this)->pseudoStateChanged(CSSSelector::PseudoFocus);
+    else if (computedStyle()->affectedByFocus())
+        setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Focus));
 
     LayoutTheme::theme().controlStateChanged(*layoutObject(), FocusControlState);
 }
@@ -1134,14 +1132,12 @@
 
     // FIXME: Why does this not need to handle the display: none transition like :hover does?
     if (layoutObject()) {
-        if (styleChangeType() < SubtreeStyleChange) {
-            if (computedStyle()->affectedByActive() && computedStyle()->hasPseudoStyle(FIRST_LETTER))
-                setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Active));
-            else if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByActive())
-                toElement(this)->pseudoStateChanged(CSSSelector::PseudoActive);
-            else if (computedStyle()->affectedByActive())
-                setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Active));
-        }
+        if (computedStyle()->affectedByActive() && computedStyle()->hasPseudoStyle(FIRST_LETTER))
+            setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Active));
+        else if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByActive())
+            toElement(this)->pseudoStateChanged(CSSSelector::PseudoActive);
+        else if (computedStyle()->affectedByActive())
+            setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Active));
 
         LayoutTheme::theme().controlStateChanged(*layoutObject(), PressedControlState);
     }
@@ -1165,14 +1161,12 @@
         return;
     }
 
-    if (styleChangeType() < SubtreeStyleChange) {
-        if (computedStyle()->affectedByHover() && computedStyle()->hasPseudoStyle(FIRST_LETTER))
-            setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Hover));
-        else if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByHover())
-            toElement(this)->pseudoStateChanged(CSSSelector::PseudoHover);
-        else if (computedStyle()->affectedByHover())
-            setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Hover));
-    }
+    if (computedStyle()->affectedByHover() && computedStyle()->hasPseudoStyle(FIRST_LETTER))
+        setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Hover));
+    else if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByHover())
+        toElement(this)->pseudoStateChanged(CSSSelector::PseudoHover);
+    else if (computedStyle()->affectedByHover())
+        setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Hover));
 
     LayoutTheme::theme().controlStateChanged(*layoutObject(), HoverControlState);
 }
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 51635775..1e47f442 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -1462,15 +1462,15 @@
     return Range::create(*this);
 }
 
-PassRefPtrWillBeRawPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatToShow, PassRefPtrWillBeRawPtr<NodeFilter> filter, ExceptionState& exceptionState)
+PassRefPtrWillBeRawPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatToShow, PassRefPtrWillBeRawPtr<NodeFilter> filter)
 {
-    // FIXME: It might be a good idea to emit a warning if |whatToShow| contains a bit that is not defined in
-    // NodeFilter.
+    ASSERT(root);
     return NodeIterator::create(root, whatToShow, filter);
 }
 
-PassRefPtrWillBeRawPtr<TreeWalker> Document::createTreeWalker(Node* root, unsigned whatToShow, PassRefPtrWillBeRawPtr<NodeFilter> filter, ExceptionState& exceptionState)
+PassRefPtrWillBeRawPtr<TreeWalker> Document::createTreeWalker(Node* root, unsigned whatToShow, PassRefPtrWillBeRawPtr<NodeFilter> filter)
 {
+    ASSERT(root);
     return TreeWalker::create(root, whatToShow, filter);
 }
 
@@ -1556,6 +1556,16 @@
     styleEngine().styleInvalidator().invalidate(*this);
 }
 
+bool Document::attemptedToDetermineEncodingFromContentSniffing() const
+{
+    return m_encodingData.attemptedToDetermineEncodingFromContentSniffing();
+}
+
+bool Document::encodingWasDetectedFromContentSniffing() const
+{
+    return m_encodingData.encodingWasDetectedFromContentSniffing();
+}
+
 void Document::setupFontBuilder(ComputedStyle& documentStyle)
 {
     FontBuilder fontBuilder(*this);
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index e4af2d6..e864d3f 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -422,8 +422,8 @@
 
     PassRefPtrWillBeRawPtr<Range> createRange();
 
-    PassRefPtrWillBeRawPtr<NodeIterator> createNodeIterator(Node* root, unsigned whatToShow, PassRefPtrWillBeRawPtr<NodeFilter>, ExceptionState&);
-    PassRefPtrWillBeRawPtr<TreeWalker> createTreeWalker(Node* root, unsigned whatToShow, PassRefPtrWillBeRawPtr<NodeFilter>, ExceptionState&);
+    PassRefPtrWillBeRawPtr<NodeIterator> createNodeIterator(Node* root, unsigned whatToShow, PassRefPtrWillBeRawPtr<NodeFilter>);
+    PassRefPtrWillBeRawPtr<TreeWalker> createTreeWalker(Node* root, unsigned whatToShow, PassRefPtrWillBeRawPtr<NodeFilter>);
 
     // Special support for editing
     PassRefPtrWillBeRawPtr<Text> createEditingTextNode(const String&);
@@ -1002,6 +1002,9 @@
 
     void updateStyleInvalidationIfNeeded();
 
+    bool attemptedToDetermineEncodingFromContentSniffing() const;
+    bool encodingWasDetectedFromContentSniffing() const;
+
     DECLARE_VIRTUAL_TRACE();
 
     bool hasSVGFilterElementsRequiringLayerUpdate() const { return m_layerUpdateSVGFilterElements.size(); }
diff --git a/third_party/WebKit/Source/core/dom/Document.idl b/third_party/WebKit/Source/core/dom/Document.idl
index 8c33208..ca81695 100644
--- a/third_party/WebKit/Source/core/dom/Document.idl
+++ b/third_party/WebKit/Source/core/dom/Document.idl
@@ -67,8 +67,8 @@
     [NewObject] Range createRange();
 
     // NodeFilter.SHOW_ALL = 0xFFFFFFFF
-    [NewObject, RaisesException] NodeIterator createNodeIterator(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null);
-    [NewObject, RaisesException] TreeWalker createTreeWalker(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null);
+    [NewObject] NodeIterator createNodeIterator(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null);
+    [NewObject] TreeWalker createTreeWalker(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null);
 
     // FIXME: CDATASection has been removed from the spec. crbug.com/437205
     [RaisesException, MeasureAs=DocumentCreateCDATASection] CDATASection createCDATASection(DOMString data);
diff --git a/third_party/WebKit/Source/core/dom/DocumentEncodingData.cpp b/third_party/WebKit/Source/core/dom/DocumentEncodingData.cpp
index ed5771c4..ad80fb57 100644
--- a/third_party/WebKit/Source/core/dom/DocumentEncodingData.cpp
+++ b/third_party/WebKit/Source/core/dom/DocumentEncodingData.cpp
@@ -38,6 +38,8 @@
 DocumentEncodingData::DocumentEncodingData()
     : m_encoding(UTF8Encoding())
     , m_wasDetectedHeuristically(false)
+    , m_attemptedToDetermineEncodingFromContentSniffing(false)
+    , m_encodingWasDetectedFromContentSniffing(false)
     , m_sawDecodingError(false)
 {
 }
@@ -46,6 +48,8 @@
 {
     m_encoding = decoder.encoding();
     m_wasDetectedHeuristically = decoder.encodingWasDetectedHeuristically();
+    m_attemptedToDetermineEncodingFromContentSniffing = decoder.attemptedToDetermineEncodingFromContentSniffing();
+    m_encodingWasDetectedFromContentSniffing = decoder.encodingWasDetectedFromContentSniffing();
     m_sawDecodingError = decoder.sawError();
 }
 
diff --git a/third_party/WebKit/Source/core/dom/DocumentEncodingData.h b/third_party/WebKit/Source/core/dom/DocumentEncodingData.h
index 6682cc8..e0e6f37 100644
--- a/third_party/WebKit/Source/core/dom/DocumentEncodingData.h
+++ b/third_party/WebKit/Source/core/dom/DocumentEncodingData.h
@@ -48,10 +48,14 @@
     void setEncoding(const WTF::TextEncoding&);
     bool wasDetectedHeuristically() const { return m_wasDetectedHeuristically; }
     bool sawDecodingError() const { return m_sawDecodingError; }
+    bool attemptedToDetermineEncodingFromContentSniffing() const { return m_attemptedToDetermineEncodingFromContentSniffing; }
+    bool encodingWasDetectedFromContentSniffing() const { return m_encodingWasDetectedFromContentSniffing; }
 
 private:
     WTF::TextEncoding m_encoding;
     bool m_wasDetectedHeuristically;
+    bool m_attemptedToDetermineEncodingFromContentSniffing;
+    bool m_encodingWasDetectedFromContentSniffing;
     bool m_sawDecodingError;
 };
 
@@ -62,6 +66,8 @@
 {
     return a.encoding() != b.encoding()
         || a.wasDetectedHeuristically() != b.wasDetectedHeuristically()
+        || a.attemptedToDetermineEncodingFromContentSniffing() != b.attemptedToDetermineEncodingFromContentSniffing()
+        || a.encodingWasDetectedFromContentSniffing() != b.encodingWasDetectedFromContentSniffing()
         || a.sawDecodingError() != b.sawDecodingError();
 }
 
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index 61151db9..575b315 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -1208,7 +1208,7 @@
         AtomicString newId = makeIdForStyleResolution(newValue, document().inQuirksMode());
         if (newId != oldId) {
             elementData()->setIdForStyleResolution(newId);
-            if (inActiveDocument() && styleResolver && styleChangeType() < SubtreeStyleChange)
+            if (inActiveDocument() && styleResolver)
                 document().styleEngine().idChangedForElement(oldId, newId, *this);
         }
     } else if (name == classAttr) {
@@ -1288,7 +1288,7 @@
 void Element::classAttributeChanged(const AtomicString& newClassString)
 {
     StyleResolver* styleResolver = document().styleResolver();
-    bool testShouldInvalidateStyle = inActiveDocument() && styleResolver && styleChangeType() < SubtreeStyleChange;
+    bool testShouldInvalidateStyle = inActiveDocument() && styleResolver;
 
     ASSERT(elementData());
     ClassStringContent classStringContentType = classStringHasClassName(newClassString);
@@ -1548,6 +1548,8 @@
         if (ElementAnimations* elementAnimations = data->elementAnimations())
             elementAnimations->cssAnimations().cancel();
     }
+
+    document().styleEngine().styleInvalidator().clearInvalidation(*this);
 }
 
 void Element::attach(const AttachContext& context)
@@ -1634,8 +1636,6 @@
         document().userActionElements().didDetach(*this);
     }
 
-    document().styleEngine().styleInvalidator().clearInvalidation(*this);
-
     if (svgFilterNeedsLayerUpdate())
         document().unscheduleSVGFilterLayerUpdateHack(*this);
 
@@ -1877,7 +1877,7 @@
     if (document().inStyleRecalc())
         return;
     StyleResolver* styleResolver = document().styleResolver();
-    if (inActiveDocument() && styleResolver && styleChangeType() < SubtreeStyleChange)
+    if (inActiveDocument() && styleResolver)
         document().styleEngine().pseudoStateChangedForElement(pseudo, *this);
 }
 
@@ -2074,8 +2074,6 @@
 
     if (!style && !styleAffectedByEmpty())
         return;
-    if (styleChangeType() >= SubtreeStyleChange)
-        return;
     if (!inActiveDocument())
         return;
     if (!document().styleResolver())
@@ -3133,7 +3131,7 @@
     }
 
     if (oldValue != newValue) {
-        if (inActiveDocument() && document().styleResolver() && styleChangeType() < SubtreeStyleChange)
+        if (inActiveDocument() && document().styleResolver())
             document().styleEngine().attributeChangedForElement(name, *this);
 
         if (isUpgradedCustomElement())
@@ -3585,7 +3583,7 @@
     return true;
 }
 
-void Element::logEventIfIsolatedWorldAndInDocument(const String& eventName, const String& arg1, const String& arg2)
+void Element::logAddElementIfIsolatedWorldAndInDocument(const char element[], const QualifiedName& attr1)
 {
     if (!inDocument())
         return;
@@ -3593,12 +3591,12 @@
     if (!activityLogger)
         return;
     Vector<String, 2> argv;
-    argv.append(arg1);
-    argv.append(arg2);
-    activityLogger->logEvent(eventName, argv.size(), argv.data());
+    argv.append(element);
+    argv.append(fastGetAttribute(attr1));
+    activityLogger->logEvent("blinkAddElement", argv.size(), argv.data());
 }
 
-void Element::logEventIfIsolatedWorldAndInDocument(const String& eventName, const String& arg1, const String& arg2, const String& arg3)
+void Element::logAddElementIfIsolatedWorldAndInDocument(const char element[], const QualifiedName& attr1, const QualifiedName& attr2)
 {
     if (!inDocument())
         return;
@@ -3606,13 +3604,13 @@
     if (!activityLogger)
         return;
     Vector<String, 3> argv;
-    argv.append(arg1);
-    argv.append(arg2);
-    argv.append(arg3);
-    activityLogger->logEvent(eventName, argv.size(), argv.data());
+    argv.append(element);
+    argv.append(fastGetAttribute(attr1));
+    argv.append(fastGetAttribute(attr2));
+    activityLogger->logEvent("blinkAddElement", argv.size(), argv.data());
 }
 
-void Element::logEventIfIsolatedWorldAndInDocument(const String& eventName, const String& arg1, const String& arg2, const String& arg3, const String& arg4)
+void Element::logAddElementIfIsolatedWorldAndInDocument(const char element[], const QualifiedName& attr1, const QualifiedName& attr2, const QualifiedName& attr3)
 {
     if (!inDocument())
         return;
@@ -3620,11 +3618,26 @@
     if (!activityLogger)
         return;
     Vector<String, 4> argv;
-    argv.append(arg1);
-    argv.append(arg2);
-    argv.append(arg3);
-    argv.append(arg4);
-    activityLogger->logEvent(eventName, argv.size(), argv.data());
+    argv.append(element);
+    argv.append(fastGetAttribute(attr1));
+    argv.append(fastGetAttribute(attr2));
+    argv.append(fastGetAttribute(attr3));
+    activityLogger->logEvent("blinkAddElement", argv.size(), argv.data());
+}
+
+void Element::logUpdateAttributeIfIsolatedWorldAndInDocument(const char element[], const QualifiedName& attributeName, const AtomicString& oldValue, const AtomicString& newValue)
+{
+    if (!inDocument())
+        return;
+    V8DOMActivityLogger* activityLogger = V8DOMActivityLogger::currentActivityLoggerIfIsolatedWorld();
+    if (!activityLogger)
+        return;
+    Vector<String, 4> argv;
+    argv.append(element);
+    argv.append(attributeName.toString());
+    argv.append(oldValue);
+    argv.append(newValue);
+    activityLogger->logEvent("blinkSetAttribute", argv.size(), argv.data());
 }
 
 DEFINE_TRACE(Element)
diff --git a/third_party/WebKit/Source/core/dom/Element.h b/third_party/WebKit/Source/core/dom/Element.h
index 55f3688..473da92c 100644
--- a/third_party/WebKit/Source/core/dom/Element.h
+++ b/third_party/WebKit/Source/core/dom/Element.h
@@ -542,9 +542,10 @@
 
     // Helpers for V8DOMActivityLogger::logEvent.  They call logEvent only if
     // the element is inDocument() and the context is an isolated world.
-    void logEventIfIsolatedWorldAndInDocument(const String& eventName, const String& arg1, const String& arg2);
-    void logEventIfIsolatedWorldAndInDocument(const String& eventName, const String& arg1, const String& arg2, const String& arg3);
-    void logEventIfIsolatedWorldAndInDocument(const String& eventName, const String& arg1, const String& arg2, const String& arg3, const String& arg4);
+    void logAddElementIfIsolatedWorldAndInDocument(const char element[], const QualifiedName& attr1);
+    void logAddElementIfIsolatedWorldAndInDocument(const char element[], const QualifiedName& attr1, const QualifiedName& attr2);
+    void logAddElementIfIsolatedWorldAndInDocument(const char element[], const QualifiedName& attr1, const QualifiedName& attr2, const QualifiedName& attr3);
+    void logUpdateAttributeIfIsolatedWorldAndInDocument(const char element[], const QualifiedName& attributeName, const AtomicString& oldValue, const AtomicString& newValue);
 
     DECLARE_VIRTUAL_TRACE();
 
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
index a7b90c67..f3f9a43 100644
--- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
@@ -333,6 +333,19 @@
     return isSVGScriptElement(*element);
 }
 
+void ScriptLoader::logScriptMimetype(ScriptResource* resource, LocalFrame* frame, String mimetype)
+{
+    bool text = mimetype.lower().startsWith("text/");
+    bool application = mimetype.lower().startsWith("application/");
+    bool expectedJs = MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimetype) || (text && isLegacySupportedJavaScriptLanguage(mimetype.substring(5)));
+    bool sameOrigin = m_element->document().securityOrigin()->canRequest(m_resource->url());
+    if (expectedJs) {
+        return;
+    }
+    UseCounter::Feature feature = sameOrigin ? (text ? UseCounter::SameOriginTextScript : application ? UseCounter::SameOriginApplicationScript : UseCounter::SameOriginOtherScript) : (text ? UseCounter::CrossOriginTextScript : application ? UseCounter::CrossOriginApplicationScript : UseCounter::CrossOriginOtherScript);
+    UseCounter::count(frame, feature);
+}
+
 bool ScriptLoader::executeScript(const ScriptSourceCode& sourceCode, double* compilationFinishTime)
 {
     ASSERT(m_alreadyStarted);
@@ -358,15 +371,20 @@
 
     if (m_isExternalScript) {
         ScriptResource* resource = m_resource ? m_resource.get() : sourceCode.resource();
-        if (resource && !resource->mimeTypeAllowedByNosniff()) {
-            contextDocument->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Refused to execute script from '" + resource->url().elidedString() + "' because its MIME type ('" + resource->mimeType() + "') is not executable, and strict MIME type checking is enabled."));
-            return false;
-        }
+        if (resource) {
+            if (!resource->mimeTypeAllowedByNosniff()) {
+                contextDocument->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Refused to execute script from '" + resource->url().elidedString() + "' because its MIME type ('" + resource->mimeType() + "') is not executable, and strict MIME type checking is enabled."));
+                return false;
+            }
 
-        if (resource && resource->mimeType().lower().startsWith("image/")) {
-            contextDocument->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Refused to execute script from '" + resource->url().elidedString() + "' because its MIME type ('" + resource->mimeType() + "') is not executable."));
-            UseCounter::count(frame, UseCounter::BlockedSniffingImageToScript);
-            return false;
+            String mimetype = resource->mimeType();
+            if (mimetype.lower().startsWith("image/")) {
+                contextDocument->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Refused to execute script from '" + resource->url().elidedString() + "' because its MIME type ('" + resource->mimeType() + "') is not executable."));
+                UseCounter::count(frame, UseCounter::BlockedSniffingImageToScript);
+                return false;
+            }
+
+            logScriptMimetype(resource, frame, mimetype);
         }
     }
 
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.h b/third_party/WebKit/Source/core/dom/ScriptLoader.h
index b449c45..6b53a665 100644
--- a/third_party/WebKit/Source/core/dom/ScriptLoader.h
+++ b/third_party/WebKit/Source/core/dom/ScriptLoader.h
@@ -35,7 +35,7 @@
 class Element;
 class ScriptLoaderClient;
 class ScriptSourceCode;
-
+class LocalFrame;
 
 class CORE_EXPORT ScriptLoader : public NoBaseWillBeGarbageCollectedFinalized<ScriptLoader>, private ScriptResourceClient {
     USING_FAST_MALLOC_WILL_BE_REMOVED(ScriptLoader);
@@ -92,6 +92,7 @@
 private:
     bool ignoresLoadRequest() const;
     bool isScriptForEventSupported() const;
+    void logScriptMimetype(ScriptResource*, LocalFrame*, String);
 
     bool fetchScript(const String& sourceUrl, FetchRequest::DeferOption);
 
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
index 62d5adb..9fe6beb 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -338,6 +338,8 @@
     // Always clear the x position used for vertical arrow navigation.
     // It will be restored by the vertical arrow navigation code if necessary.
     m_selectionEditor->resetXPosForVerticalArrowNavigation();
+    RefPtrWillBeRawPtr<LocalFrame> protector(m_frame.get());
+    // This may dispatch a synchronous focus-related events.
     selectFrameElementInParentIfFullySelected();
     notifyLayoutObjectOfSelectionChange(userTriggered);
     // If the selections are same in the DOM tree but not in the composed tree,
@@ -805,7 +807,10 @@
     // Focus on the parent frame, and then select from before this element to after.
     VisibleSelection newSelection(beforeOwnerElement, afterOwnerElement);
     page->focusController().setFocusedFrame(parent);
-    toLocalFrame(parent)->selection().setSelection(newSelection);
+    // setFocusedFrame can dispatch synchronous focus/blur events.  The document
+    // tree might be modified.
+    if (newSelection.isNonOrphanedCaretOrRange())
+        toLocalFrame(parent)->selection().setSelection(newSelection);
 }
 
 void FrameSelection::selectAll()
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp
index 143a285c..58d67b1 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -1502,16 +1502,16 @@
         float delta = elasticOverscroll.width() - m_horizontalScrollbar->elasticOverscroll();
         if (delta != 0) {
             m_horizontalScrollbar->setElasticOverscroll(elasticOverscroll.width());
-            scrollAnimator()->notifyContentAreaScrolled(FloatSize(delta, 0));
-            setScrollbarNeedsPaintInvalidation(m_horizontalScrollbar.get());
+            scrollAnimator().notifyContentAreaScrolled(FloatSize(delta, 0));
+            setScrollbarNeedsPaintInvalidation(HorizontalScrollbar);
         }
     }
     if (m_verticalScrollbar) {
         float delta = elasticOverscroll.height() - m_verticalScrollbar->elasticOverscroll();
         if (delta != 0) {
             m_verticalScrollbar->setElasticOverscroll(elasticOverscroll.height());
-            scrollAnimator()->notifyContentAreaScrolled(FloatSize(0, delta));
-            setScrollbarNeedsPaintInvalidation(m_verticalScrollbar.get());
+            scrollAnimator().notifyContentAreaScrolled(FloatSize(0, delta));
+            setScrollbarNeedsPaintInvalidation(VerticalScrollbar);
         }
     }
 }
@@ -2079,7 +2079,7 @@
 {
     if (Scrollbar* scrollbar = verticalScrollbar()) {
         scrollbar->setTrackNeedsRepaint(true);
-        setScrollbarNeedsPaintInvalidation(scrollbar);
+        setScrollbarNeedsPaintInvalidation(VerticalScrollbar);
     }
 }
 
@@ -2411,6 +2411,9 @@
             if (RuntimeEnabledFeatures::frameTimingSupportEnabled())
                 updateFrameTimingRequestsIfNeeded();
 
+            if (RuntimeEnabledFeatures::slimmingPaintV2Enabled())
+                pushPaintArtifactToCompositor();
+
             ASSERT(!view->hasPendingSelection());
             ASSERT(lifecycle().state() == DocumentLifecycle::PaintInvalidationClean
                 || (RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled() && lifecycle().state() == DocumentLifecycle::PaintClean));
@@ -2479,6 +2482,27 @@
         synchronizedPaintRecursively(child);
 }
 
+void FrameView::pushPaintArtifactToCompositor()
+{
+    ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
+
+    LayoutView* view = layoutView();
+    ASSERT(view);
+
+    // TODO(jbroman): Simplify the path to PaintController.
+    PaintLayer* layer = view->layer();
+    ASSERT(layer);
+    if (!layer->hasCompositedLayerMapping())
+        return;
+    GraphicsLayer* rootGraphicsLayer = layer->compositedLayerMapping()->mainGraphicsLayer();
+    const PaintArtifact& paintArtifact = rootGraphicsLayer->paintController()->paintArtifact();
+
+    Page* page = frame().page();
+    if (!page)
+        return;
+    page->chromeClient().didPaint(paintArtifact);
+}
+
 void FrameView::updateFrameTimingRequestsIfNeeded()
 {
     GraphicsLayerFrameTimingRequests graphicsLayerTimingRequests;
@@ -2954,7 +2978,7 @@
     contentsResized();
 }
 
-void FrameView::didAddScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
+void FrameView::didAddScrollbar(Scrollbar& scrollbar, ScrollbarOrientation orientation)
 {
     ScrollableArea::didAddScrollbar(scrollbar, orientation);
     if (AXObjectCache* cache = axObjectCache())
@@ -2992,10 +3016,10 @@
     if (hasBar) {
         m_horizontalScrollbar = createScrollbar(HorizontalScrollbar);
         addChild(m_horizontalScrollbar.get());
-        didAddScrollbar(m_horizontalScrollbar.get(), HorizontalScrollbar);
+        didAddScrollbar(*m_horizontalScrollbar, HorizontalScrollbar);
         m_horizontalScrollbar->styleChanged();
     } else {
-        willRemoveScrollbar(m_horizontalScrollbar.get(), HorizontalScrollbar);
+        willRemoveScrollbar(*m_horizontalScrollbar, HorizontalScrollbar);
         if (AXObjectCache* cache = axObjectCache())
             cache->remove(m_horizontalScrollbar.get());
         // If the scrollbar has been marked as overlapping the window resizer,
@@ -3020,10 +3044,10 @@
     if (hasBar) {
         m_verticalScrollbar = createScrollbar(VerticalScrollbar);
         addChild(m_verticalScrollbar.get());
-        didAddScrollbar(m_verticalScrollbar.get(), VerticalScrollbar);
+        didAddScrollbar(*m_verticalScrollbar, VerticalScrollbar);
         m_verticalScrollbar->styleChanged();
     } else {
-        willRemoveScrollbar(m_verticalScrollbar.get(), VerticalScrollbar);
+        willRemoveScrollbar(*m_verticalScrollbar, VerticalScrollbar);
         if (AXObjectCache* cache = axObjectCache())
             cache->remove(m_verticalScrollbar.get());
         // If the scrollbar has been marked as overlapping the window resizer,
@@ -3203,9 +3227,9 @@
             height() - m_horizontalScrollbar->height(),
             width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0),
             m_horizontalScrollbar->height());
-        m_horizontalScrollbar->setFrameRect(adjustScrollbarRectForResizer(hBarRect, m_horizontalScrollbar.get()));
+        m_horizontalScrollbar->setFrameRect(adjustScrollbarRectForResizer(hBarRect, *m_horizontalScrollbar));
         if (oldRect != m_horizontalScrollbar->frameRect())
-            setScrollbarNeedsPaintInvalidation(m_horizontalScrollbar.get());
+            setScrollbarNeedsPaintInvalidation(HorizontalScrollbar);
 
         m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth);
         m_horizontalScrollbar->setProportion(clientWidth, contentsWidth());
@@ -3219,9 +3243,9 @@
             0,
             m_verticalScrollbar->width(),
             height() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0));
-        m_verticalScrollbar->setFrameRect(adjustScrollbarRectForResizer(vBarRect, m_verticalScrollbar.get()));
+        m_verticalScrollbar->setFrameRect(adjustScrollbarRectForResizer(vBarRect, *m_verticalScrollbar));
         if (oldRect != m_verticalScrollbar->frameRect())
-            setScrollbarNeedsPaintInvalidation(m_verticalScrollbar.get());
+            setScrollbarNeedsPaintInvalidation(VerticalScrollbar);
 
         m_verticalScrollbar->setEnabled(contentsHeight() > clientHeight);
         m_verticalScrollbar->setProportion(clientHeight, contentsHeight());
@@ -3229,7 +3253,7 @@
     }
 }
 
-IntRect FrameView::adjustScrollbarRectForResizer(const IntRect& rect, Scrollbar* scrollbar)
+IntRect FrameView::adjustScrollbarRectForResizer(const IntRect& rect, Scrollbar& scrollbar)
 {
     // Get our window resizer rect and see if we overlap. Adjust to avoid the overlap
     // if necessary.
@@ -3238,7 +3262,7 @@
     if (!rect.isEmpty() && !windowResizerRect().isEmpty()) {
         IntRect resizerRect = convertFromRootFrame(windowResizerRect());
         if (rect.intersects(resizerRect)) {
-            if (scrollbar->orientation() == HorizontalScrollbar) {
+            if (scrollbar.orientation() == HorizontalScrollbar) {
                 int overlap = rect.maxX() - resizerRect.x();
                 if (overlap > 0 && resizerRect.maxX() >= rect.maxX()) {
                     adjustedRect.setWidth(rect.width() - overlap);
@@ -3253,8 +3277,8 @@
             }
         }
     }
-    if (overlapsResizer != scrollbar->overlapsResizer()) {
-        scrollbar->setOverlapsResizer(overlapsResizer);
+    if (overlapsResizer != scrollbar.overlapsResizer()) {
+        scrollbar.setOverlapsResizer(overlapsResizer);
         adjustScrollbarsAvoidingResizerCount(overlapsResizer ? 1 : -1);
     }
     return adjustedRect;
@@ -3661,12 +3685,12 @@
     return ScrollBehaviorInstant;
 }
 
-void FrameView::paint(GraphicsContext* context, const CullRect& cullRect) const
+void FrameView::paint(GraphicsContext& context, const CullRect& cullRect) const
 {
     paint(context, GlobalPaintNormalPhase, cullRect);
 }
 
-void FrameView::paint(GraphicsContext* context, const GlobalPaintFlags globalPaintFlags, const CullRect& cullRect) const
+void FrameView::paint(GraphicsContext& context, const GlobalPaintFlags globalPaintFlags, const CullRect& cullRect) const
 {
     // TODO(skyostil): Remove this early-out in favor of painting cached scrollbars.
     if (shouldThrottleRendering())
@@ -3674,7 +3698,7 @@
     FramePainter(*this).paint(context, globalPaintFlags, cullRect);
 }
 
-void FrameView::paintContents(GraphicsContext* context, const GlobalPaintFlags globalPaintFlags, const IntRect& damageRect) const
+void FrameView::paintContents(GraphicsContext& context, const GlobalPaintFlags globalPaintFlags, const IntRect& damageRect) const
 {
     if (shouldThrottleRendering())
         return;
@@ -3709,36 +3733,36 @@
         || (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0);
 }
 
-IntRect FrameView::convertFromScrollbarToContainingWidget(const Scrollbar* scrollbar, const IntRect& localRect) const
+IntRect FrameView::convertFromScrollbarToContainingWidget(const Scrollbar& scrollbar, const IntRect& localRect) const
 {
     // Scrollbars won't be transformed within us
     IntRect newRect = localRect;
-    newRect.moveBy(scrollbar->location());
+    newRect.moveBy(scrollbar.location());
     return newRect;
 }
 
-IntRect FrameView::convertFromContainingWidgetToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
+IntRect FrameView::convertFromContainingWidgetToScrollbar(const Scrollbar& scrollbar, const IntRect& parentRect) const
 {
     IntRect newRect = parentRect;
     // Scrollbars won't be transformed within us
-    newRect.moveBy(-scrollbar->location());
+    newRect.moveBy(-scrollbar.location());
     return newRect;
 }
 
 // FIXME: test these on windows
-IntPoint FrameView::convertFromScrollbarToContainingWidget(const Scrollbar* scrollbar, const IntPoint& localPoint) const
+IntPoint FrameView::convertFromScrollbarToContainingWidget(const Scrollbar& scrollbar, const IntPoint& localPoint) const
 {
     // Scrollbars won't be transformed within us
     IntPoint newPoint = localPoint;
-    newPoint.moveBy(scrollbar->location());
+    newPoint.moveBy(scrollbar.location());
     return newPoint;
 }
 
-IntPoint FrameView::convertFromContainingWidgetToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
+IntPoint FrameView::convertFromContainingWidgetToScrollbar(const Scrollbar& scrollbar, const IntPoint& parentPoint) const
 {
     IntPoint newPoint = parentPoint;
     // Scrollbars won't be transformed within us
-    newPoint.moveBy(-scrollbar->location());
+    newPoint.moveBy(-scrollbar.location());
     return newPoint;
 }
 
diff --git a/third_party/WebKit/Source/core/frame/FrameView.h b/third_party/WebKit/Source/core/frame/FrameView.h
index ebfc224a..adcc3388 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.h
+++ b/third_party/WebKit/Source/core/frame/FrameView.h
@@ -38,6 +38,7 @@
 #include "platform/geometry/IntRect.h"
 #include "platform/geometry/LayoutRect.h"
 #include "platform/graphics/Color.h"
+#include "platform/graphics/paint/ClipPaintPropertyNode.h"
 #include "platform/graphics/paint/TransformPaintPropertyNode.h"
 #include "platform/scroll/ScrollTypes.h"
 #include "platform/scroll/Scrollbar.h"
@@ -323,7 +324,7 @@
     bool isActive() const override;
 
     // Override scrollbar notifications to update the AXObject cache.
-    void didAddScrollbar(Scrollbar*, ScrollbarOrientation) override;
+    void didAddScrollbar(Scrollbar&, ScrollbarOrientation) override;
 
     // FIXME: This should probably be renamed as the 'inSubtreeLayout' parameter
     // passed around the FrameView layout methods can be true while this returns
@@ -511,9 +512,9 @@
     }
 
     // Widget override. Handles painting of the contents of the view as well as the scrollbars.
-    void paint(GraphicsContext*, const CullRect&) const override;
-    void paint(GraphicsContext*, const GlobalPaintFlags, const CullRect&) const;
-    void paintContents(GraphicsContext*, const GlobalPaintFlags, const IntRect& damageRect) const;
+    void paint(GraphicsContext&, const CullRect&) const override;
+    void paint(GraphicsContext&, const GlobalPaintFlags, const CullRect&) const;
+    void paintContents(GraphicsContext&, const GlobalPaintFlags, const IntRect& damageRect) const;
 
     // Widget overrides to ensure that our children's visibility status is kept up to date when we get shown and hidden.
     void show() override;
@@ -524,10 +525,10 @@
     bool scrollbarCornerPresent() const;
     IntRect scrollCornerRect() const override;
 
-    IntRect convertFromScrollbarToContainingWidget(const Scrollbar*, const IntRect&) const override;
-    IntRect convertFromContainingWidgetToScrollbar(const Scrollbar*, const IntRect&) const override;
-    IntPoint convertFromScrollbarToContainingWidget(const Scrollbar*, const IntPoint&) const override;
-    IntPoint convertFromContainingWidgetToScrollbar(const Scrollbar*, const IntPoint&) const override;
+    IntRect convertFromScrollbarToContainingWidget(const Scrollbar&, const IntRect&) const override;
+    IntRect convertFromContainingWidgetToScrollbar(const Scrollbar&, const IntRect&) const override;
+    IntPoint convertFromScrollbarToContainingWidget(const Scrollbar&, const IntPoint&) const override;
+    IntPoint convertFromContainingWidgetToScrollbar(const Scrollbar&, const IntPoint&) const override;
 
     bool isFrameView() const override { return true; }
 
@@ -575,6 +576,9 @@
     void setScrollTranslation(PassRefPtr<TransformPaintPropertyNode> scrollTranslation) { m_scrollTranslation = scrollTranslation; }
     const TransformPaintPropertyNode* scrollTranslation() const { return m_scrollTranslation.get(); }
 
+    void setContentClip(PassRefPtr<ClipPaintPropertyNode> contentClip) { m_contentClip = contentClip; }
+    const ClipPaintPropertyNode* contentClip() const { return m_contentClip.get(); }
+
     // TODO(ojan): Merge this with IntersectionObserver once it lands.
     IntRect computeVisibleArea();
 
@@ -601,7 +605,7 @@
     };
     void computeScrollbarExistence(bool& newHasHorizontalScrollbar, bool& newHasVerticalScrollbar, const IntSize& docSize, ComputeScrollbarExistenceOption = FirstPass) const;
     void updateScrollbarGeometry();
-    IntRect adjustScrollbarRectForResizer(const IntRect&, Scrollbar*);
+    IntRect adjustScrollbarRectForResizer(const IntRect&, Scrollbar&);
 
     // Called to update the scrollbars to accurately reflect the state of the view.
     void updateScrollbars(const DoubleSize& desiredOffset);
@@ -639,6 +643,8 @@
     void synchronizedPaint();
     void synchronizedPaintRecursively(GraphicsLayer*);
 
+    void pushPaintArtifactToCompositor();
+
     void reset();
     void init();
 
@@ -881,9 +887,13 @@
     // Paint properties for SPv2 Only.
     // The hierarchy of transform subtree created by a FrameView.
     // [ preTranslation ]               The offset from Widget::frameRect. Establishes viewport.
-    //     +---[ scrollTranslation ]    Frame scrolling. This is going away in favor of Settings::rootLayerScrolls.
+    //     +---[ scrollTranslation ]    Frame scrolling.
+    //                                  TODO(trchen): This is going away in favor of Settings::rootLayerScrolls.
     RefPtr<TransformPaintPropertyNode> m_preTranslation;
     RefPtr<TransformPaintPropertyNode> m_scrollTranslation;
+    // The content clip clips the document (= LayoutView) but not the scrollbars.
+    // TODO(trchen): Going away in favor of Settings::rootLayerScrolls too.
+    RefPtr<ClipPaintPropertyNode> m_contentClip;
 };
 
 inline void FrameView::incrementVisuallyNonEmptyCharacterCount(unsigned count)
diff --git a/third_party/WebKit/Source/core/frame/FrameViewDidPaintTest.cpp b/third_party/WebKit/Source/core/frame/FrameViewDidPaintTest.cpp
new file mode 100644
index 0000000..5ddc236
--- /dev/null
+++ b/third_party/WebKit/Source/core/frame/FrameViewDidPaintTest.cpp
@@ -0,0 +1,94 @@
+// 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/frame/FrameView.h"
+
+#include "bindings/core/v8/ExceptionStatePlaceholder.h"
+#include "core/frame/Settings.h"
+#include "core/html/HTMLElement.h"
+#include "core/loader/EmptyClients.h"
+#include "core/page/Page.h"
+#include "core/testing/DummyPageHolder.h"
+#include "platform/RuntimeEnabledFeatures.h"
+#include "platform/geometry/IntSize.h"
+#include "platform/graphics/paint/PaintArtifact.h"
+#include "platform/graphics/test/FakeGraphicsLayerFactory.h"
+#include "platform/heap/Handle.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "wtf/OwnPtr.h"
+
+// This test ensures that FrameView informs the ChromeClient of changes to the
+// paint artifact so that they can be shown to the user (e.g. via the
+// compositor).
+
+using testing::_;
+
+namespace blink {
+namespace {
+
+class MockChromeClient : public EmptyChromeClient {
+public:
+    // ChromeClient
+    GraphicsLayerFactory* graphicsLayerFactory() const override
+    {
+        return FakeGraphicsLayerFactory::instance();
+    }
+    MOCK_METHOD1(didPaint, void(const PaintArtifact&));
+    MOCK_METHOD2(attachRootGraphicsLayer, void(GraphicsLayer*, LocalFrame* localRoot));
+};
+
+class FrameViewPaintTest : public testing::Test {
+protected:
+    FrameViewPaintTest()
+        : m_chromeClient(adoptPtrWillBeNoop(new MockChromeClient))
+    {
+        // We shouldn't attach a root graphics layer. In this mode, that's not
+        // our responsibility.
+        EXPECT_CALL(chromeClient(), attachRootGraphicsLayer(_, _)).Times(0);
+    }
+
+    void SetUp() override
+    {
+        RuntimeEnabledFeatures::setSlimmingPaintV2Enabled(true);
+        Page::PageClients clients;
+        fillWithEmptyClients(clients);
+        clients.chromeClient = m_chromeClient.get();
+        m_pageHolder = DummyPageHolder::create(IntSize(800, 600), &clients);
+        m_pageHolder->page().settings().setAcceleratedCompositingEnabled(true);
+    }
+
+    void TearDown() override
+    {
+        m_featuresBackup.restore();
+    }
+
+    Document& document() { return m_pageHolder->document(); }
+    MockChromeClient& chromeClient() { return *m_chromeClient; }
+
+private:
+    RuntimeEnabledFeatures::Backup m_featuresBackup;
+    OwnPtrWillBePersistent<MockChromeClient> m_chromeClient;
+    OwnPtr<DummyPageHolder> m_pageHolder;
+};
+
+TEST_F(FrameViewPaintTest, PaintOnce)
+{
+    EXPECT_CALL(chromeClient(), didPaint(_));
+    document().body()->setInnerHTML("Hello world", ASSERT_NO_EXCEPTION);
+    document().view()->updateAllLifecyclePhases();
+}
+
+TEST_F(FrameViewPaintTest, PaintAndRepaint)
+{
+    EXPECT_CALL(chromeClient(), didPaint(_)).Times(2);
+    document().body()->setInnerHTML("Hello", ASSERT_NO_EXCEPTION);
+    document().view()->updateAllLifecyclePhases();
+    document().body()->setInnerHTML("Hello world", ASSERT_NO_EXCEPTION);
+    document().view()->updateAllLifecyclePhases();
+}
+
+} // namespace
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/History.cpp b/third_party/WebKit/Source/core/frame/History.cpp
index 12d0544..c870118 100644
--- a/third_party/WebKit/Source/core/frame/History.cpp
+++ b/third_party/WebKit/Source/core/frame/History.cpp
@@ -43,6 +43,27 @@
 
 namespace blink {
 
+namespace {
+
+bool equalIgnoringPathQueryAndFragment(const KURL& a, const KURL& b)
+{
+    int aLength = a.pathStart();
+    int bLength = b.pathStart();
+
+    if (aLength != bLength)
+        return false;
+
+    const String& aString = a.string();
+    const String& bString = b.string();
+    for (int i = 0; i < aLength; ++i) {
+        if (aString[i] != bString[i])
+            return false;
+    }
+    return true;
+}
+
+}  // namespace
+
 History::History(LocalFrame* frame)
     : DOMWindowProperty(frame)
     , m_lastStateObjectRequested(nullptr)
@@ -162,15 +183,38 @@
     return KURL(document->baseURL(), urlString);
 }
 
+bool History::canChangeToUrl(const KURL& url)
+{
+    if (!url.isValid())
+        return false;
+
+    Document* document = m_frame->document();
+    SecurityOrigin* origin = document->securityOrigin();
+    if (origin->isGrantedUniversalAccess())
+        return true;
+
+    if (origin->isUnique())
+        return false;
+
+    if (!equalIgnoringPathQueryAndFragment(url, document->url()))
+        return false;
+
+    RefPtr<SecurityOrigin> requestedOrigin = SecurityOrigin::create(url);
+    if (requestedOrigin->isUnique() || !requestedOrigin->isSameSchemeHostPort(origin))
+        return false;
+
+    return true;
+}
+
 void History::stateObjectAdded(PassRefPtr<SerializedScriptValue> data, const String& /* title */, const String& urlString, HistoryScrollRestorationType restorationType, FrameLoadType type, ExceptionState& exceptionState)
 {
     if (!m_frame || !m_frame->page() || !m_frame->loader().documentLoader())
         return;
 
     KURL fullURL = urlForState(urlString);
-    if (!fullURL.isValid() || !m_frame->document()->securityOrigin()->canRequest(fullURL)) {
+    if (!canChangeToUrl(fullURL)) {
         // We can safely expose the URL to JavaScript, as a) no redirection takes place: JavaScript already had this URL, b) JavaScript can only access a same-origin History object.
-        exceptionState.throwSecurityError("A history state object with URL '" + fullURL.elidedString() + "' cannot be created in a document with origin '" + m_frame->document()->securityOrigin()->toString() + "'.");
+        exceptionState.throwSecurityError("A history state object with URL '" + fullURL.elidedString() + "' cannot be created in a document with origin '" + m_frame->document()->securityOrigin()->toString() + "' and URL '" + m_frame->document()->url().elidedString() + "'.");
         return;
     }
 
diff --git a/third_party/WebKit/Source/core/frame/History.h b/third_party/WebKit/Source/core/frame/History.h
index 80b5fb6..626f64ac 100644
--- a/third_party/WebKit/Source/core/frame/History.h
+++ b/third_party/WebKit/Source/core/frame/History.h
@@ -79,6 +79,7 @@
     explicit History(LocalFrame*);
 
     KURL urlForState(const String& url);
+    bool canChangeToUrl(const KURL& url);
 
     void stateObjectAdded(PassRefPtr<SerializedScriptValue>, const String& title, const String& url, HistoryScrollRestorationType, FrameLoadType, ExceptionState&);
     SerializedScriptValue* stateInternal() const;
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.cpp b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
index 549efa6..195df532 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrame.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
@@ -619,7 +619,7 @@
 }
 
 PassOwnPtr<DragImage> LocalFrame::paintIntoDragImage(
-    const DisplayItemClientWrapper& displayItemClient,
+    const DisplayItemClient& displayItemClient,
     RespectImageOrientationEnum shouldRespectImageOrientation,
     const GlobalPaintFlags globalPaintFlags, IntRect paintingRect, float opacity)
 {
@@ -643,7 +643,7 @@
         transform.translate(-paintingRect.x(), -paintingRect.y());
         TransformRecorder transformRecorder(paintContext, displayItemClient, transform);
 
-        m_view->paintContents(&paintContext, globalPaintFlags, paintingRect);
+        m_view->paintContents(paintContext, globalPaintFlags, paintingRect);
 
     }
     RefPtr<const SkPicture> recording = pictureBuilder.endRecording();
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.h b/third_party/WebKit/Source/core/frame/LocalFrame.h
index 1ec0848e..8c6d3c2a 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrame.h
+++ b/third_party/WebKit/Source/core/frame/LocalFrame.h
@@ -76,7 +76,7 @@
 class WebFrameScheduler;
 template <typename Strategy> class PositionWithAffinityTemplate;
 
-class CORE_EXPORT LocalFrame : public Frame, public LocalFrameLifecycleNotifier, public WillBeHeapSupplementable<LocalFrame> {
+class CORE_EXPORT LocalFrame : public Frame, public LocalFrameLifecycleNotifier, public WillBeHeapSupplementable<LocalFrame>, public DisplayItemClient {
     WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(LocalFrame);
 public:
     static PassRefPtrWillBeRawPtr<LocalFrame> create(FrameLoaderClient*, FrameHost*, FrameOwner*);
@@ -179,8 +179,8 @@
     void unregisterPluginElement(HTMLPlugInElement*);
     void clearWeakMembers(Visitor*);
 #endif
-    DisplayItemClient displayItemClient() const { return toDisplayItemClient(this); }
-    String debugName() const { return "LocalFrame"; }
+
+    String debugName() const final { return "LocalFrame"; }
 
     bool shouldThrottleRendering() const;
 
@@ -204,7 +204,7 @@
 
     // Paints the area for the given rect into a DragImage, with the given displayItemClient id attached.
     // The rect is in the coordinate space of the frame.
-    PassOwnPtr<DragImage> paintIntoDragImage(const DisplayItemClientWrapper&,
+    PassOwnPtr<DragImage> paintIntoDragImage(const DisplayItemClient&,
         RespectImageOrientationEnum shouldRespectImageOrientation, const GlobalPaintFlags,
         IntRect paintingRect, float opacity = 1);
 
diff --git a/third_party/WebKit/Source/core/frame/RootFrameViewport.cpp b/third_party/WebKit/Source/core/frame/RootFrameViewport.cpp
index 6bc56742..7f4963a 100644
--- a/third_party/WebKit/Source/core/frame/RootFrameViewport.cpp
+++ b/third_party/WebKit/Source/core/frame/RootFrameViewport.cpp
@@ -22,12 +22,12 @@
 
 void RootFrameViewport::updateScrollAnimator()
 {
-    scrollAnimator()->setCurrentPosition(toFloatPoint(scrollOffsetFromScrollAnimators()));
+    scrollAnimator().setCurrentPosition(toFloatPoint(scrollOffsetFromScrollAnimators()));
 }
 
 DoublePoint RootFrameViewport::scrollOffsetFromScrollAnimators() const
 {
-    return visualViewport().scrollAnimator()->currentPosition() + layoutViewport().scrollAnimator()->currentPosition();
+    return visualViewport().scrollAnimator().currentPosition() + layoutViewport().scrollAnimator().currentPosition();
 }
 
 DoubleRect RootFrameViewport::visibleContentRectDouble(IncludeScrollbarsInRect scrollbarInclusion) const
@@ -101,7 +101,7 @@
     // ScrollAnimatorBase::currentPosition and construct a LayoutRect from that.
 
     LayoutRect frameRectInContent = LayoutRect(
-        layoutViewport().scrollAnimator()->currentPosition(),
+        layoutViewport().scrollAnimator().currentPosition(),
         layoutViewport().visibleContentRect().size());
     LayoutRect visualRectInContent = LayoutRect(
         scrollOffsetFromScrollAnimators(),
@@ -144,19 +144,19 @@
     ScrollableArea& primary = !m_invertScrollOrder ? layoutViewport() : visualViewport();
     ScrollableArea& secondary = !m_invertScrollOrder ? visualViewport() : layoutViewport();
 
-    DoublePoint targetPosition = primary.clampScrollPosition(primary.scrollAnimator()->currentPosition() + delta);
+    DoublePoint targetPosition = primary.clampScrollPosition(primary.scrollAnimator().currentPosition() + delta);
     primary.setScrollPosition(targetPosition, scrollType, behavior);
 
     // Scroll the secondary viewport if all of the scroll was not applied to the
     // primary viewport.
-    DoublePoint updatedPosition = secondary.scrollAnimator()->currentPosition() + FloatPoint(targetPosition);
+    DoublePoint updatedPosition = secondary.scrollAnimator().currentPosition() + FloatPoint(targetPosition);
     DoubleSize applied = updatedPosition - oldPosition;
     delta -= applied;
 
     if (delta.isZero())
         return;
 
-    targetPosition = secondary.clampScrollPosition(secondary.scrollAnimator()->currentPosition() + delta);
+    targetPosition = secondary.clampScrollPosition(secondary.scrollAnimator().currentPosition() + delta);
     secondary.setScrollPosition(targetPosition, scrollType, behavior);
 }
 
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.cpp b/third_party/WebKit/Source/core/frame/UseCounter.cpp
index 63f6db30..504334b 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.cpp
+++ b/third_party/WebKit/Source/core/frame/UseCounter.cpp
@@ -933,9 +933,6 @@
     case PrefixedPerformanceResourceTimingBufferFull:
         return replacedBy("Performance.onwebkitresourcetimingbufferfull", "Performance.onresourcetimingbufferfull");
 
-    case HeaderValueNotMatchingRFC7230:
-        return "Header values not matching to RFC 7230, will be deprecated (see: https://www.chromestatus.com/feature/6457425448140800).";
-
     case BluetoothDeviceInstanceId:
         return replacedBy("BluetoothDevice.instanceID", "BluetoothDevice.id");
 
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index 74ee5cc0..df660e2 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -794,7 +794,6 @@
         HTMLImportsHasStyleSheets = 940,
         WebkitTextInClipProperty = 941,
         WebkitTextInColorProperty = 942,
-        HeaderValueNotMatchingRFC7230 = 943,
         ClipPathOfPositionedElement = 944,
         ClipCssOfPositionedElement = 945,
         NetInfoType = 946,
@@ -921,6 +920,22 @@
         CSSSelectorInternalMediaControlsCastButton = 1063,
         CSSSelectorInternalMediaControlsOverlayCastButton = 1064,
         CSSSelectorInternalPseudoSpatialNavigationFocus = 1065,
+        SameOriginTextScript = 1066,
+        SameOriginApplicationScript = 1067,
+        SameOriginOtherScript = 1068,
+        CrossOriginTextScript = 1069,
+        CrossOriginApplicationScript = 1070,
+        CrossOriginOtherScript = 1071,
+        SVG1DOMSVGTests = 1072,
+        V8SVGViewElement_ViewTarget_AttributeGetter = 1073,
+        DisableRemotePlaybackAttribute = 1074,
+        V8SloppyMode = 1075,
+        V8StrictMode = 1076,
+        V8StrongMode = 1077,
+        AudioNodeConnectToAudioNode = 1078,
+        AudioNodeConnectToAudioParam = 1079,
+        AudioNodeDisconnectFromAudioNode = 1080,
+        AudioNodeDisconnectFromAudioParam = 1081,
 
         // 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/VisualViewport.cpp b/third_party/WebKit/Source/core/frame/VisualViewport.cpp
index b13c3b0..80b1d295 100644
--- a/third_party/WebKit/Source/core/frame/VisualViewport.cpp
+++ b/third_party/WebKit/Source/core/frame/VisualViewport.cpp
@@ -210,7 +210,7 @@
 
     if (clampedOffset != m_offset) {
         m_offset = clampedOffset;
-        scrollAnimator()->setCurrentPosition(m_offset);
+        scrollAnimator().setCurrentPosition(m_offset);
 
         // SVG runs with accelerated compositing disabled so no ScrollingCoordinator.
         if (ScrollingCoordinator* coordinator = frameHost().page().scrollingCoordinator())
@@ -364,10 +364,10 @@
     OwnPtr<WebScrollbarLayer>& webScrollbarLayer = isHorizontal ?
         m_webOverlayScrollbarHorizontal : m_webOverlayScrollbarVertical;
 
-    ScrollbarTheme* theme = ScrollbarThemeOverlay::mobileTheme();
-    int thumbThickness = theme->thumbThickness(0);
-    int scrollbarThickness = theme->scrollbarThickness(RegularScrollbar);
-    int scrollbarMargin = theme->scrollbarMargin();
+    ScrollbarThemeOverlay& theme = ScrollbarThemeOverlay::mobileTheme();
+    int thumbThickness = theme.thumbThickness();
+    int scrollbarThickness = theme.scrollbarThickness(RegularScrollbar);
+    int scrollbarMargin = theme.scrollbarMargin();
 
     if (!webScrollbarLayer) {
         ScrollingCoordinator* coordinator = frameHost().page().scrollingCoordinator();
diff --git a/third_party/WebKit/Source/core/html/HTMLAnchorElement.cpp b/third_party/WebKit/Source/core/html/HTMLAnchorElement.cpp
index 5f8f096..45c444fa 100644
--- a/third_party/WebKit/Source/core/html/HTMLAnchorElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLAnchorElement.cpp
@@ -199,7 +199,7 @@
             }
         }
         invalidateCachedVisitedLinkHash();
-        logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "a", hrefAttr.toString(), oldValue, value);
+        logUpdateAttributeIfIsolatedWorldAndInDocument("a", hrefAttr, oldValue, value);
     } else if (name == nameAttr || name == titleAttr) {
         // Do nothing.
     } else if (name == relAttr) {
@@ -386,7 +386,7 @@
 Node::InsertionNotificationRequest HTMLAnchorElement::insertedInto(ContainerNode* insertionPoint)
 {
     InsertionNotificationRequest request = HTMLElement::insertedInto(insertionPoint);
-    logEventIfIsolatedWorldAndInDocument("blinkAddElement", "a", fastGetAttribute(hrefAttr));
+    logAddElementIfIsolatedWorldAndInDocument("a", hrefAttr);
     return request;
 }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLAttributeNames.in b/third_party/WebKit/Source/core/html/HTMLAttributeNames.in
index e1a8d84a..2558df9 100644
--- a/third_party/WebKit/Source/core/html/HTMLAttributeNames.in
+++ b/third_party/WebKit/Source/core/html/HTMLAttributeNames.in
@@ -97,6 +97,7 @@
 direction
 dirname
 disabled
+disableremoteplayback
 download
 draggable
 webkitdropzone
diff --git a/third_party/WebKit/Source/core/html/HTMLButtonElement.cpp b/third_party/WebKit/Source/core/html/HTMLButtonElement.cpp
index 0d81d0e..b62d0e8 100644
--- a/third_party/WebKit/Source/core/html/HTMLButtonElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLButtonElement.cpp
@@ -104,7 +104,7 @@
         setNeedsWillValidateCheck();
     } else {
         if (name == formactionAttr)
-            logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "button", formactionAttr.toString(), oldValue, value);
+            logUpdateAttributeIfIsolatedWorldAndInDocument("button", formactionAttr, oldValue, value);
         HTMLFormControlElement::parseAttribute(name, oldValue, value);
     }
 }
@@ -216,7 +216,7 @@
 Node::InsertionNotificationRequest HTMLButtonElement::insertedInto(ContainerNode* insertionPoint)
 {
     InsertionNotificationRequest request = HTMLFormControlElement::insertedInto(insertionPoint);
-    logEventIfIsolatedWorldAndInDocument("blinkAddElement", "button", fastGetAttribute(typeAttr), fastGetAttribute(formmethodAttr), fastGetAttribute(formactionAttr));
+    logAddElementIfIsolatedWorldAndInDocument("button", typeAttr, formmethodAttr, formactionAttr);
     return request;
 }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLFormElement.cpp b/third_party/WebKit/Source/core/html/HTMLFormElement.cpp
index ee77275db..df13f4ae 100644
--- a/third_party/WebKit/Source/core/html/HTMLFormElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFormElement.cpp
@@ -152,7 +152,7 @@
 Node::InsertionNotificationRequest HTMLFormElement::insertedInto(ContainerNode* insertionPoint)
 {
     HTMLElement::insertedInto(insertionPoint);
-    logEventIfIsolatedWorldAndInDocument("blinkAddElement", "form", fastGetAttribute(methodAttr), fastGetAttribute(actionAttr));
+    logAddElementIfIsolatedWorldAndInDocument("form", methodAttr, actionAttr);
     if (insertionPoint->inDocument())
         this->document().didAssociateFormControl(this);
     return InsertionDone;
@@ -508,7 +508,7 @@
         KURL actionURL = document().completeURL(m_attributes.action().isEmpty() ? document().url().string() : m_attributes.action());
         if (MixedContentChecker::isMixedFormAction(document().frame(), actionURL))
             UseCounter::count(document().frame(), UseCounter::MixedContentFormPresent);
-        logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "form", actionAttr.toString(), oldValue, value);
+        logUpdateAttributeIfIsolatedWorldAndInDocument("form", actionAttr, oldValue, value);
     } else if (name == targetAttr) {
         m_attributes.setTarget(value);
     } else if (name == methodAttr) {
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
index 4ccd90eec..43abe48 100644
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
@@ -110,7 +110,7 @@
             SecurityPolicy::referrerPolicyFromString(value, &m_referrerPolicy);
     } else {
         if (name == srcAttr)
-            logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "iframe", srcAttr.toString(), oldValue, value);
+            logUpdateAttributeIfIsolatedWorldAndInDocument("iframe", srcAttr, oldValue, value);
         HTMLFrameElementBase::parseAttribute(name, oldValue, value);
     }
 }
@@ -130,7 +130,7 @@
     InsertionNotificationRequest result = HTMLFrameElementBase::insertedInto(insertionPoint);
     if (insertionPoint->inDocument() && document().isHTMLDocument() && !insertionPoint->isInShadowTree())
         toHTMLDocument(document()).addExtraNamedItem(m_name);
-    logEventIfIsolatedWorldAndInDocument("blinkAddElement", "iframe", fastGetAttribute(srcAttr));
+    logAddElementIfIsolatedWorldAndInDocument("iframe", srcAttr);
     return result;
 }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
index b2ee9ac..78231df 100644
--- a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
@@ -776,7 +776,7 @@
         UseCounter::count(document(), UseCounter::PrefixedDirectoryAttribute);
     } else {
         if (name == formactionAttr)
-            logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "input", formactionAttr.toString(), oldValue, value);
+            logUpdateAttributeIfIsolatedWorldAndInDocument("input", formactionAttr, oldValue, value);
         HTMLTextFormControlElement::parseAttribute(name, oldValue, value);
     }
     m_inputTypeView->attributeChanged();
@@ -1511,7 +1511,7 @@
     if (insertionPoint->inDocument() && !form())
         addToRadioButtonGroup();
     resetListAttributeTargetObserver();
-    logEventIfIsolatedWorldAndInDocument("blinkAddElement", "input", fastGetAttribute(typeAttr), fastGetAttribute(formactionAttr));
+    logAddElementIfIsolatedWorldAndInDocument("input", typeAttr, formactionAttr);
     return InsertionShouldCallDidNotifySubtreeInsertions;
 }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp b/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
index 7d27e7c..56104327 100644
--- a/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
@@ -168,7 +168,7 @@
         process();
     } else if (name == hrefAttr) {
         // Log href attribute before logging resource fetching in process().
-        logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "link", hrefAttr.toString(), oldValue, value);
+        logUpdateAttributeIfIsolatedWorldAndInDocument("link", hrefAttr, oldValue, value);
         process();
     } else if (name == typeAttr) {
         m_type = value;
@@ -261,7 +261,7 @@
 Node::InsertionNotificationRequest HTMLLinkElement::insertedInto(ContainerNode* insertionPoint)
 {
     HTMLElement::insertedInto(insertionPoint);
-    logEventIfIsolatedWorldAndInDocument("blinkAddElement", "link", fastGetAttribute(relAttr), fastGetAttribute(hrefAttr));
+    logAddElementIfIsolatedWorldAndInDocument("link", relAttr, hrefAttr);
     if (!insertionPoint->inDocument())
         return InsertionDone;
 
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
index b723253..db1f624d9 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -508,6 +508,8 @@
         configureMediaControls();
     } else if (name == preloadAttr) {
         setPlayerPreload();
+    } else if (name == disableremoteplaybackAttr) {
+        UseCounter::count(document(), UseCounter::DisableRemotePlaybackAttribute);
     } else {
         HTMLElement::parseAttribute(name, oldValue, value);
     }
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.h b/third_party/WebKit/Source/core/html/HTMLMediaElement.h
index 45d33451..1e6910b 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.h
@@ -622,6 +622,7 @@
     friend class Internals;
     friend class TrackDisplayUpdateScope;
     friend class AutoplayExperimentHelper;
+    friend class MediaControlsTest;
 
     AutoplayExperimentHelper m_autoplayHelper;
 
diff --git a/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp b/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp
index 8594640e7..07ba7a7 100644
--- a/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp
@@ -50,7 +50,6 @@
 
 HTMLOptionElement::HTMLOptionElement(Document& document)
     : HTMLElement(optionTag, document)
-    , m_disabled(false)
     , m_isSelected(false)
 {
     setHasCustomStyleCallbacks();
@@ -204,9 +203,7 @@
         if (HTMLDataListElement* dataList = ownerDataListElement())
             dataList->optionElementChildrenChanged();
     } else if (name == disabledAttr) {
-        bool oldDisabled = m_disabled;
-        m_disabled = !value.isNull();
-        if (oldDisabled != m_disabled) {
+        if (oldValue.isNull() != value.isNull()) {
             pseudoStateChanged(CSSSelector::PseudoDisabled);
             pseudoStateChanged(CSSSelector::PseudoEnabled);
             if (layoutObject())
@@ -368,6 +365,11 @@
     return displayLabel();
 }
 
+bool HTMLOptionElement::ownElementDisabled() const
+{
+    return fastHasAttribute(disabledAttr);
+}
+
 bool HTMLOptionElement::isDisabledFormControl() const
 {
     if (ownElementDisabled())
diff --git a/third_party/WebKit/Source/core/html/HTMLOptionElement.h b/third_party/WebKit/Source/core/html/HTMLOptionElement.h
index cb509cf..6202ec4 100644
--- a/third_party/WebKit/Source/core/html/HTMLOptionElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLOptionElement.h
@@ -67,7 +67,7 @@
     String label() const;
     void setLabel(const AtomicString&);
 
-    bool ownElementDisabled() const { return m_disabled; }
+    bool ownElementDisabled() const;
 
     bool isDisabledFormControl() const override;
 
@@ -108,7 +108,6 @@
 
     void updateLabel();
 
-    bool m_disabled;
     // Represents 'selectedness'.
     // https://html.spec.whatwg.org/multipage/forms.html#concept-option-selectedness
     bool m_isSelected;
diff --git a/third_party/WebKit/Source/core/html/HTMLScriptElement.cpp b/third_party/WebKit/Source/core/html/HTMLScriptElement.cpp
index 3284714..040685b6 100644
--- a/third_party/WebKit/Source/core/html/HTMLScriptElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLScriptElement.cpp
@@ -81,7 +81,7 @@
 {
     if (name == srcAttr) {
         m_loader->handleSourceAttribute(value);
-        logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "script", srcAttr.toString(), oldValue, value);
+        logUpdateAttributeIfIsolatedWorldAndInDocument("script", srcAttr, oldValue, value);
     } else if (name == asyncAttr) {
         m_loader->handleAsyncAttribute();
     } else {
@@ -94,7 +94,7 @@
     if (insertionPoint->inDocument() && hasSourceAttribute() && !loader()->isScriptTypeSupported(ScriptLoader::DisallowLegacyTypeInTypeAttribute))
         UseCounter::count(document(), UseCounter::ScriptElementWithInvalidTypeHasSrc);
     HTMLElement::insertedInto(insertionPoint);
-    logEventIfIsolatedWorldAndInDocument("blinkAddElement", "script", fastGetAttribute(srcAttr));
+    logAddElementIfIsolatedWorldAndInDocument("script", srcAttr);
     return InsertionShouldCallDidNotifySubtreeInsertions;
 }
 
diff --git a/third_party/WebKit/Source/core/html/parser/TextResourceDecoder.cpp b/third_party/WebKit/Source/core/html/parser/TextResourceDecoder.cpp
index 7c483538..7b74f86 100644
--- a/third_party/WebKit/Source/core/html/parser/TextResourceDecoder.cpp
+++ b/third_party/WebKit/Source/core/html/parser/TextResourceDecoder.cpp
@@ -19,7 +19,6 @@
     Boston, MA 02110-1301, USA.
 */
 
-
 #include "config.h"
 #include "core/html/parser/TextResourceDecoder.h"
 
@@ -401,9 +400,7 @@
         checkForMetaCharset(dataForDecode, lengthForDecode);
 
     if (shouldAutoDetect()) {
-        WTF::TextEncoding detectedEncoding;
-        if (detectTextEncoding(data, len, m_hintEncoding, &detectedEncoding))
-            setEncoding(detectedEncoding, EncodingFromContentSniffing);
+        detectTextEncoding(data, len);
     }
 
     ASSERT(m_encoding.isValid());
@@ -417,6 +414,16 @@
     return result;
 }
 
+void TextResourceDecoder::detectTextEncoding(const char* data, size_t len)
+{
+    WTF::TextEncoding detectedEncoding;
+    bool detected = blink::detectTextEncoding(data, len, m_hintEncoding, &detectedEncoding);
+    if (detected && detectedEncoding != encoding())
+        setEncoding(detectedEncoding, EncodingFromContentSniffing);
+    else
+        setEncoding(detectedEncoding, DefaultEncodingAttemptedSniffing);
+}
+
 String TextResourceDecoder::flush()
 {
     // If we can not identify the encoding even after a document is completely
@@ -424,9 +431,7 @@
     // autodetection is satisfied.
     if (m_buffer.size() && shouldAutoDetect()
         && ((!m_checkedForXMLCharset && (m_contentType == HTMLContent || m_contentType == XMLContent)) || (!m_checkedForCSSCharset && (m_contentType == CSSContent)))) {
-        WTF::TextEncoding detectedEncoding;
-        if (detectTextEncoding(m_buffer.data(), m_buffer.size(), m_hintEncoding, &detectedEncoding))
-            setEncoding(detectedEncoding, EncodingFromContentSniffing);
+        detectTextEncoding(m_buffer.data(), m_buffer.size());
     }
 
     if (!m_codec)
diff --git a/third_party/WebKit/Source/core/html/parser/TextResourceDecoder.h b/third_party/WebKit/Source/core/html/parser/TextResourceDecoder.h
index 2539cc8..ad167e2a 100644
--- a/third_party/WebKit/Source/core/html/parser/TextResourceDecoder.h
+++ b/third_party/WebKit/Source/core/html/parser/TextResourceDecoder.h
@@ -37,6 +37,7 @@
 public:
     enum EncodingSource {
         DefaultEncoding,
+        DefaultEncodingAttemptedSniffing,
         AutoDetectedEncoding,
         EncodingFromContentSniffing,
         EncodingFromXMLHeader,
@@ -57,6 +58,18 @@
     bool encodingWasDetectedHeuristically() const
     {
         return m_source == AutoDetectedEncoding
+            || m_source == EncodingFromContentSniffing
+            || m_source == DefaultEncodingAttemptedSniffing;
+    }
+
+    bool encodingWasDetectedFromContentSniffing() const
+    {
+        return m_source == EncodingFromContentSniffing;
+    }
+
+    bool attemptedToDetermineEncodingFromContentSniffing() const
+    {
+        return m_source == DefaultEncodingAttemptedSniffing
             || m_source == EncodingFromContentSniffing;
     }
 
@@ -83,6 +96,7 @@
     bool checkForXMLCharset(const char*, size_t, bool& movedDataToBuffer);
     void checkForMetaCharset(const char*, size_t);
     bool shouldAutoDetect() const;
+    void detectTextEncoding(const char*, size_t);
 
     ContentType m_contentType;
     WTF::TextEncoding m_encoding;
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControlElements.cpp b/third_party/WebKit/Source/core/html/shadow/MediaControlElements.cpp
index a5847b9..39072ac 100644
--- a/third_party/WebKit/Source/core/html/shadow/MediaControlElements.cpp
+++ b/third_party/WebKit/Source/core/html/shadow/MediaControlElements.cpp
@@ -229,8 +229,8 @@
     // (if the other requirements are right) even if JavaScript is doing its own handling of the event.
     // Doing it in preDispatchEventHandler prevents any interference from JavaScript.
     // Note that we can't simply test for click, since JS handling of touch events can prevent their translation to click events.
-    if (event && (event->type() == EventTypeNames::click || event->type() == EventTypeNames::touchstart) && mediaElement().hasRemoteRoutes() && !mediaElement().shouldShowControls())
-        mediaControls().showOverlayCastButton();
+    if (event && (event->type() == EventTypeNames::click || event->type() == EventTypeNames::touchstart))
+        mediaControls().showOverlayCastButtonIfNeeded();
     return MediaControlDivElement::preDispatchEventHandler(event);
 }
 
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp b/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp
index c508491..f0c2d40 100644
--- a/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp
+++ b/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp
@@ -61,6 +61,11 @@
     return true;
 }
 
+static bool shouldShowCastButton(HTMLMediaElement& mediaElement)
+{
+    return !mediaElement.fastHasAttribute(HTMLNames::disableremoteplaybackAttr) && mediaElement.hasRemoteRoutes();
+}
+
 static bool preferHiddenVolumeControls(const Document& document)
 {
     return !document.settings() || document.settings()->preferHiddenVolumeControls();
@@ -455,43 +460,47 @@
 
 void MediaControls::refreshCastButtonVisibilityWithoutUpdate()
 {
-    if (mediaElement().hasRemoteRoutes()) {
-        // The reason for the autoplay test is that some pages (e.g. vimeo.com) have an autoplay background video, which
-        // doesn't autoplay on Chrome for Android (we prevent it) so starts paused. In such cases we don't want to automatically
-        // show the cast button, since it looks strange and is unlikely to correspond with anything the user wants to do.
-        // If a user does want to cast a paused autoplay video then they can still do so by touching or clicking on the
-        // video, which will cause the cast button to appear.
-        if (!mediaElement().shouldShowControls() && !mediaElement().autoplay() && mediaElement().paused()) {
-            // Note that this is a case where we add the overlay cast button
-            // without wanting the panel cast button.  We depend on the fact
-            // that computeWhichControlsFit() won't change overlay cast button
-            // visibility in the case where the cast button isn't wanted.
-            // We don't call compute...() here, but it will be called as
-            // non-cast changes (e.g., resize) occur.  If the panel button
-            // is shown, however, compute...() will take control of the
-            // overlay cast button if it needs to hide it from the panel.
-            m_overlayCastButton->tryShowOverlay();
-            m_castButton->setIsWanted(false);
-        } else if (mediaElement().shouldShowControls()) {
-            m_overlayCastButton->setIsWanted(false);
-            m_castButton->setIsWanted(true);
-            // Check that the cast button actually fits on the bar.  For the
-            // newMediaPlaybackUiEnabled case, we let computeWhichControlsFit()
-            // handle this.
-            if ( !RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()
-                && m_fullScreenButton->getBoundingClientRect()->right() > m_panel->getBoundingClientRect()->right()) {
-                m_castButton->setIsWanted(false);
-                m_overlayCastButton->tryShowOverlay();
-            }
-        }
-    } else {
+    if (!shouldShowCastButton(mediaElement())) {
         m_castButton->setIsWanted(false);
         m_overlayCastButton->setIsWanted(false);
+        return;
+    }
+
+    // The reason for the autoplay test is that some pages (e.g. vimeo.com) have an autoplay background video, which
+    // doesn't autoplay on Chrome for Android (we prevent it) so starts paused. In such cases we don't want to automatically
+    // show the cast button, since it looks strange and is unlikely to correspond with anything the user wants to do.
+    // If a user does want to cast a paused autoplay video then they can still do so by touching or clicking on the
+    // video, which will cause the cast button to appear.
+    if (!mediaElement().shouldShowControls() && !mediaElement().autoplay() && mediaElement().paused()) {
+        // Note that this is a case where we add the overlay cast button
+        // without wanting the panel cast button.  We depend on the fact
+        // that computeWhichControlsFit() won't change overlay cast button
+        // visibility in the case where the cast button isn't wanted.
+        // We don't call compute...() here, but it will be called as
+        // non-cast changes (e.g., resize) occur.  If the panel button
+        // is shown, however, compute...() will take control of the
+        // overlay cast button if it needs to hide it from the panel.
+        m_overlayCastButton->tryShowOverlay();
+        m_castButton->setIsWanted(false);
+    } else if (mediaElement().shouldShowControls()) {
+        m_overlayCastButton->setIsWanted(false);
+        m_castButton->setIsWanted(true);
+        // Check that the cast button actually fits on the bar.  For the
+        // newMediaPlaybackUiEnabled case, we let computeWhichControlsFit()
+        // handle this.
+        if ( !RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()
+            && m_fullScreenButton->getBoundingClientRect()->right() > m_panel->getBoundingClientRect()->right()) {
+            m_castButton->setIsWanted(false);
+            m_overlayCastButton->tryShowOverlay();
+        }
     }
 }
 
-void MediaControls::showOverlayCastButton()
+void MediaControls::showOverlayCastButtonIfNeeded()
 {
+    if (mediaElement().shouldShowControls() || !shouldShowCastButton(mediaElement()))
+        return;
+
     m_overlayCastButton->tryShowOverlay();
     resetHideMediaControlsTimer();
 }
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControls.h b/third_party/WebKit/Source/core/html/shadow/MediaControls.h
index 8ff1320d..279ae8b 100644
--- a/third_party/WebKit/Source/core/html/shadow/MediaControls.h
+++ b/third_party/WebKit/Source/core/html/shadow/MediaControls.h
@@ -66,7 +66,7 @@
     void startedCasting();
     void stoppedCasting();
     void refreshCastButtonVisibility();
-    void showOverlayCastButton();
+    void showOverlayCastButtonIfNeeded();
     // Update cast button visibility, but don't try to update our panel
     // button visibility for space.
     void refreshCastButtonVisibilityWithoutUpdate();
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControlsTest.cpp b/third_party/WebKit/Source/core/html/shadow/MediaControlsTest.cpp
index b94fc84..8ef1ad20 100644
--- a/third_party/WebKit/Source/core/html/shadow/MediaControlsTest.cpp
+++ b/third_party/WebKit/Source/core/html/shadow/MediaControlsTest.cpp
@@ -9,6 +9,7 @@
 #include "core/css/StylePropertySet.h"
 #include "core/dom/Document.h"
 #include "core/dom/ElementTraversal.h"
+#include "core/frame/Settings.h"
 #include "core/html/HTMLVideoElement.h"
 #include "core/testing/DummyPageHolder.h"
 #include "platform/heap/Handle.h"
@@ -21,7 +22,7 @@
 Element* getElementByShadowPseudoId(Node& rootNode, const char* shadowPseudoId)
 {
     for (Element& element : ElementTraversal::descendantsOf(rootNode)) {
-        if (element.fastGetAttribute(HTMLNames::pseudoAttr) == shadowPseudoId)
+        if (element.shadowPseudoId() == shadowPseudoId)
             return &element;
     }
     return nullptr;
@@ -58,9 +59,18 @@
     {
         m_pageHolder = DummyPageHolder::create(IntSize(800, 600));
         Document& document = this->document();
-        document.write("<video controls>");
+
+        document.write("<video>");
         HTMLVideoElement& video = toHTMLVideoElement(*document.querySelector("video", ASSERT_NO_EXCEPTION));
         m_mediaControls = video.mediaControls();
+
+        // If scripts are not enabled, controls will always be shown.
+        m_pageHolder->frame().settings()->setScriptEnabled(true);
+    }
+
+    void simulateRouteAvailabe()
+    {
+        m_mediaControls->mediaElement().remoteRouteAvailabilityChanged(true);
     }
 
     MediaControls& mediaControls() { return *m_mediaControls; }
@@ -73,6 +83,8 @@
 
 TEST_F(MediaControlsTest, HideAndShow)
 {
+    mediaControls().mediaElement().setBooleanAttribute(HTMLNames::controlsAttr, true);
+
     Element* panel = getElementByShadowPseudoId(mediaControls(), "-webkit-media-controls-panel");
     ASSERT_NE(nullptr, panel);
 
@@ -85,6 +97,8 @@
 
 TEST_F(MediaControlsTest, Reset)
 {
+    mediaControls().mediaElement().setBooleanAttribute(HTMLNames::controlsAttr, true);
+
     Element* panel = getElementByShadowPseudoId(mediaControls(), "-webkit-media-controls-panel");
     ASSERT_NE(nullptr, panel);
 
@@ -95,6 +109,8 @@
 
 TEST_F(MediaControlsTest, HideAndReset)
 {
+    mediaControls().mediaElement().setBooleanAttribute(HTMLNames::controlsAttr, true);
+
     Element* panel = getElementByShadowPseudoId(mediaControls(), "-webkit-media-controls-panel");
     ASSERT_NE(nullptr, panel);
 
@@ -116,4 +132,56 @@
     ASSERT_EQ(oldResolverCount, newResolverCount);
 }
 
+TEST_F(MediaControlsTest, CastButtonRequiresRoute)
+{
+    mediaControls().mediaElement().setBooleanAttribute(HTMLNames::controlsAttr, true);
+
+    Element* castButton = getElementByShadowPseudoId(mediaControls(), "-internal-media-controls-cast-button");
+    ASSERT_NE(nullptr, castButton);
+
+    ASSERT_FALSE(isElementVisible(*castButton));
+
+    simulateRouteAvailabe();
+    ASSERT_TRUE(isElementVisible(*castButton));
+}
+
+TEST_F(MediaControlsTest, CastButtonDisableRemotePlaybackAttr)
+{
+    mediaControls().mediaElement().setBooleanAttribute(HTMLNames::controlsAttr, true);
+
+    Element* castButton = getElementByShadowPseudoId(mediaControls(), "-internal-media-controls-cast-button");
+    ASSERT_NE(nullptr, castButton);
+
+    mediaControls().mediaElement().setBooleanAttribute(HTMLNames::disableremoteplaybackAttr, true);
+    simulateRouteAvailabe();
+    ASSERT_FALSE(isElementVisible(*castButton));
+
+    mediaControls().mediaElement().setBooleanAttribute(HTMLNames::disableremoteplaybackAttr, false);
+    mediaControls().reset();
+    ASSERT_TRUE(isElementVisible(*castButton));
+}
+
+TEST_F(MediaControlsTest, CastOverlayDefault)
+{
+    Element* castOverlayButton = getElementByShadowPseudoId(mediaControls(), "-internal-media-controls-overlay-cast-button");
+    ASSERT_NE(nullptr, castOverlayButton);
+
+    simulateRouteAvailabe();
+    ASSERT_TRUE(isElementVisible(*castOverlayButton));
+}
+
+TEST_F(MediaControlsTest, CastOverlayDisableRemotePlaybackAttr)
+{
+    Element* castOverlayButton = getElementByShadowPseudoId(mediaControls(), "-internal-media-controls-overlay-cast-button");
+    ASSERT_NE(nullptr, castOverlayButton);
+
+    mediaControls().mediaElement().setBooleanAttribute(HTMLNames::disableremoteplaybackAttr, true);
+    simulateRouteAvailabe();
+    ASSERT_FALSE(isElementVisible(*castOverlayButton));
+
+    mediaControls().mediaElement().setBooleanAttribute(HTMLNames::disableremoteplaybackAttr, false);
+    mediaControls().reset();
+    ASSERT_TRUE(isElementVisible(*castOverlayButton));
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/shadow/SpinButtonElement.cpp b/third_party/WebKit/Source/core/html/shadow/SpinButtonElement.cpp
index d316b182..718adba 100644
--- a/third_party/WebKit/Source/core/html/shadow/SpinButtonElement.cpp
+++ b/third_party/WebKit/Source/core/html/shadow/SpinButtonElement.cpp
@@ -216,8 +216,8 @@
 void SpinButtonElement::startRepeatingTimer()
 {
     m_pressStartingState = m_upDownState;
-    ScrollbarTheme* theme = ScrollbarTheme::theme();
-    m_repeatingTimer.start(theme->initialAutoscrollTimerDelay(), theme->autoscrollTimerDelay(), BLINK_FROM_HERE);
+    ScrollbarTheme& theme = ScrollbarTheme::theme();
+    m_repeatingTimer.start(theme.initialAutoscrollTimerDelay(), theme.autoscrollTimerDelay(), BLINK_FROM_HERE);
 }
 
 void SpinButtonElement::stopRepeatingTimer()
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp
index e18894fb..b6d8cd4b 100644
--- a/third_party/WebKit/Source/core/input/EventHandler.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -1062,12 +1062,10 @@
             m_resizeScrollableArea = layer->scrollableArea();
             m_resizeScrollableArea->setInResizeMode(true);
             m_offsetFromResizeCorner = LayoutSize(m_resizeScrollableArea->offsetFromResizeCorner(p));
-            invalidateClick();
             return WebInputEventResult::HandledSystem;
         }
     }
 
-
     // m_selectionInitiationState is initialized after dispatching mousedown
     // event in order not to keep the selection by DOM APIs Because we can't
     // give the user the chance to handle the selection by user action like
@@ -2225,7 +2223,7 @@
     PlatformMouseEvent fakeMouseMove(gestureEvent.position(), gestureEvent.globalPosition(),
         NoButton, PlatformEvent::MouseMoved, /* clickCount */ 0,
         static_cast<PlatformEvent::Modifiers>(modifiers),
-        PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
+        PlatformMouseEvent::FromTouch, gestureEvent.timestamp(), WebPointerProperties::PointerType::Mouse);
     dispatchMouseEvent(EventTypeNames::mousemove, currentHitTest.innerNode(), 0, fakeMouseMove);
 
     // Do a new hit-test in case the mousemove event changed the DOM.
@@ -2254,7 +2252,7 @@
     PlatformMouseEvent fakeMouseDown(gestureEvent.position(), gestureEvent.globalPosition(),
         LeftButton, PlatformEvent::MousePressed, gestureEvent.tapCount(),
         static_cast<PlatformEvent::Modifiers>(modifiers | PlatformEvent::LeftButtonDown),
-        PlatformMouseEvent::FromTouch,  gestureEvent.timestamp());
+        PlatformMouseEvent::FromTouch,  gestureEvent.timestamp(), WebPointerProperties::PointerType::Mouse);
     WebInputEventResult mouseDownEventResult = dispatchMouseEvent(EventTypeNames::mousedown, currentHitTest.innerNode(), gestureEvent.tapCount(), fakeMouseDown);
     selectionController().initializeSelectionState();
     if (mouseDownEventResult == WebInputEventResult::NotHandled)
@@ -2280,7 +2278,7 @@
     PlatformMouseEvent fakeMouseUp(gestureEvent.position(), gestureEvent.globalPosition(),
         LeftButton, PlatformEvent::MouseReleased, gestureEvent.tapCount(),
         static_cast<PlatformEvent::Modifiers>(modifiers),
-        PlatformMouseEvent::FromTouch,  gestureEvent.timestamp());
+        PlatformMouseEvent::FromTouch,  gestureEvent.timestamp(), WebPointerProperties::PointerType::Mouse);
     WebInputEventResult mouseUpEventResult = dispatchMouseEvent(EventTypeNames::mouseup, currentHitTest.innerNode(), gestureEvent.tapCount(), fakeMouseUp);
 
     WebInputEventResult clickEventResult = WebInputEventResult::NotHandled;
@@ -2327,12 +2325,12 @@
     if (m_frame->settings() && m_frame->settings()->touchDragDropEnabled() && m_frame->view()) {
         PlatformMouseEvent mouseDownEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, 1,
             static_cast<PlatformEvent::Modifiers>(modifiers | PlatformEvent::LeftButtonDown),
-            PlatformMouseEvent::FromTouch, WTF::monotonicallyIncreasingTime());
+            PlatformMouseEvent::FromTouch, WTF::monotonicallyIncreasingTime(), WebPointerProperties::PointerType::Mouse);
         m_mouseDown = mouseDownEvent;
 
         PlatformMouseEvent mouseDragEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseMoved, 1,
             static_cast<PlatformEvent::Modifiers>(modifiers | PlatformEvent::LeftButtonDown),
-            PlatformMouseEvent::FromTouch, WTF::monotonicallyIncreasingTime());
+            PlatformMouseEvent::FromTouch, WTF::monotonicallyIncreasingTime(), WebPointerProperties::PointerType::Mouse);
         HitTestRequest request(HitTestRequest::ReadOnly);
         MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseDragEvent);
         m_mouseDownMayStartDrag = true;
@@ -2772,7 +2770,7 @@
     PlatformMouseEvent fakeMouseMove(gestureEvent.position(), gestureEvent.globalPosition(),
         NoButton, PlatformEvent::MouseMoved, /* clickCount */ 0,
         static_cast<PlatformEvent::Modifiers>(modifiers),
-        PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
+        PlatformMouseEvent::FromTouch, gestureEvent.timestamp(), WebPointerProperties::PointerType::Mouse);
 
     // Update the mouseout/mouseleave event
     size_t indexExitedFrameChain = exitedFrameChain.size();
@@ -3006,7 +3004,10 @@
     if (m_frame->settings() && m_frame->settings()->showContextMenuOnMouseUp())
         eventType = PlatformEvent::MouseReleased;
 
-    PlatformMouseEvent mouseEvent(locationInRootFrame, globalPosition, RightButton, eventType, 1, PlatformEvent::NoModifiers, PlatformMouseEvent::RealOrIndistinguishable, WTF::monotonicallyIncreasingTime());
+    PlatformMouseEvent mouseEvent(locationInRootFrame, globalPosition,
+        RightButton, eventType, 1,
+        PlatformEvent::NoModifiers, PlatformMouseEvent::RealOrIndistinguishable,
+        WTF::monotonicallyIncreasingTime(), WebPointerProperties::PointerType::Mouse);
 
     return sendContextMenuEvent(mouseEvent, overrideTargetElement);
 }
@@ -3020,7 +3021,7 @@
     PlatformMouseEvent fakeMouseMove(gestureEvent.position(), gestureEvent.globalPosition(),
         NoButton, PlatformEvent::MouseMoved, /* clickCount */ 0,
         static_cast<PlatformEvent::Modifiers>(modifiers),
-        PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
+        PlatformMouseEvent::FromTouch, gestureEvent.timestamp(), WebPointerProperties::PointerType::Mouse);
     dispatchMouseEvent(EventTypeNames::mousemove, targetedEvent.hitTestResult().innerNode(), 0, fakeMouseMove);
 
     PlatformEvent::Type eventType = PlatformEvent::MousePressed;
@@ -3032,7 +3033,7 @@
 
     PlatformMouseEvent mouseEvent(targetedEvent.event().position(), targetedEvent.event().globalPosition(), RightButton, eventType, 1,
         static_cast<PlatformEvent::Modifiers>(modifiers),
-        PlatformMouseEvent::FromTouch, WTF::monotonicallyIncreasingTime());
+        PlatformMouseEvent::FromTouch, WTF::monotonicallyIncreasingTime(), WebPointerProperties::PointerType::Mouse);
     // To simulate right-click behavior, we send a right mouse down and then
     // context menu event.
     // FIXME: Send HitTestResults to avoid redundant hit tests.
@@ -3115,7 +3116,7 @@
     if (!isCursorVisible())
         return;
 
-    PlatformMouseEvent fakeMouseMoveEvent(m_lastKnownMousePosition, m_lastKnownMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, PlatformKeyboardEvent::getCurrentModifierState(), PlatformMouseEvent::RealOrIndistinguishable, monotonicallyIncreasingTime());
+    PlatformMouseEvent fakeMouseMoveEvent(m_lastKnownMousePosition, m_lastKnownMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, PlatformKeyboardEvent::getCurrentModifierState(), PlatformMouseEvent::RealOrIndistinguishable, monotonicallyIncreasingTime(), WebPointerProperties::PointerType::Mouse);
     handleMouseMoveEvent(fakeMouseMoveEvent);
 }
 
diff --git a/third_party/WebKit/Source/core/inspector/InjectedScriptSource.js b/third_party/WebKit/Source/core/inspector/InjectedScriptSource.js
index 5c76040..69faa63 100644
--- a/third_party/WebKit/Source/core/inspector/InjectedScriptSource.js
+++ b/third_party/WebKit/Source/core/inspector/InjectedScriptSource.js
@@ -170,6 +170,8 @@
         return false;
     try {
         if (typeof obj.splice === "function") {
+            if (!InjectedScriptHost.suppressWarningsAndCallFunction(Object.prototype.hasOwnProperty, obj, ["length"]))
+                return false;
             var len = obj.length;
             return typeof len === "number" && isUInt32(len);
         }
diff --git a/third_party/WebKit/Source/core/inspector/v8/V8InjectedScriptHost.cpp b/third_party/WebKit/Source/core/inspector/v8/V8InjectedScriptHost.cpp
index d479218..ca8c39cf 100644
--- a/third_party/WebKit/Source/core/inspector/v8/V8InjectedScriptHost.cpp
+++ b/third_party/WebKit/Source/core/inspector/v8/V8InjectedScriptHost.cpp
@@ -80,21 +80,6 @@
     v8::Local<v8::Object> object = info[0].As<v8::Object>();
     v8::Local<v8::String> result = object->GetConstructorName();
 
-    if (!result.IsEmpty() && toCoreStringWithUndefinedOrNullCheck(result) == "Object") {
-        v8::Local<v8::String> constructorSymbol = v8AtomicString(info.GetIsolate(), "constructor");
-        if (object->HasRealNamedProperty(constructorSymbol) && !object->HasRealNamedCallbackProperty(constructorSymbol)) {
-            v8::TryCatch tryCatch(info.GetIsolate());
-            v8::Local<v8::Value> constructor = object->GetRealNamedProperty(constructorSymbol);
-            if (!constructor.IsEmpty() && constructor->IsFunction()) {
-                v8::Local<v8::String> constructorName = functionDisplayName(v8::Local<v8::Function>::Cast(constructor));
-                if (!constructorName.IsEmpty() && !tryCatch.HasCaught())
-                    result = constructorName;
-            }
-        }
-        if (toCoreStringWithUndefinedOrNullCheck(result) == "Object" && object->IsFunction())
-            result = v8AtomicString(info.GetIsolate(), "Function");
-    }
-
     v8SetReturnValue(info, result);
 }
 
diff --git a/third_party/WebKit/Source/core/layout/ColumnBalancer.cpp b/third_party/WebKit/Source/core/layout/ColumnBalancer.cpp
index 29bfd96..6bc6a5d 100644
--- a/third_party/WebKit/Source/core/layout/ColumnBalancer.cpp
+++ b/third_party/WebKit/Source/core/layout/ColumnBalancer.cpp
@@ -98,29 +98,38 @@
 
 void InitialColumnHeightFinder::examineBoxAfterEntering(const LayoutBox& box)
 {
-    ASSERT(isFirstAfterBreak(flowThreadOffset()) || !box.paginationStrut());
-    if (box.hasForcedBreakBefore()) {
-        addContentRun(flowThreadOffset());
-    } else if (isFirstAfterBreak(flowThreadOffset())) {
-        // This box is first after a soft break.
-        recordStrutBeforeOffset(flowThreadOffset(), box.paginationStrut());
+    if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) {
+        ASSERT(isFirstAfterBreak(flowThreadOffset()) || !box.paginationStrut());
+        if (box.hasForcedBreakBefore()) {
+            addContentRun(flowThreadOffset());
+        } else if (isFirstAfterBreak(flowThreadOffset())) {
+            // This box is first after a soft break.
+            recordStrutBeforeOffset(flowThreadOffset(), box.paginationStrut());
+        }
     }
 
-    if (box.hasForcedBreakAfter())
-        addContentRun(flowThreadOffset() + box.logicalHeight());
+    if (box.hasForcedBreakAfter()) {
+        LayoutUnit logicalBottomInFlowThread = flowThreadOffset() + box.logicalHeight();
+        if (isLogicalBottomWithinBounds(logicalBottomInFlowThread))
+            addContentRun(logicalBottomInFlowThread);
+    }
 
     if (box.paginationBreakability() != LayoutBox::AllowAnyBreaks) {
         LayoutUnit unsplittableLogicalHeight = box.logicalHeight();
         if (box.isFloating())
             unsplittableLogicalHeight += box.marginBefore() + box.marginAfter();
         m_tallestUnbreakableLogicalHeight = std::max(m_tallestUnbreakableLogicalHeight, unsplittableLogicalHeight);
-    } else if (box.isLayoutBlockFlow()) {
-        if (LayoutMultiColumnFlowThread* innerFlowThread = toLayoutBlockFlow(box).multiColumnFlowThread()) {
-            LayoutUnit offsetInInnerFlowThread = flowThreadOffset() - innerFlowThread->blockOffsetInEnclosingFlowThread();
-            LayoutUnit innerUnbreakableHeight = innerFlowThread->tallestUnbreakableLogicalHeight(offsetInInnerFlowThread);
-            m_tallestUnbreakableLogicalHeight = std::max(m_tallestUnbreakableLogicalHeight, innerUnbreakableHeight);
-        }
+        return;
     }
+    // Need to examine inner multicol containers to find their tallest unbreakable piece of content.
+    if (!box.isLayoutBlockFlow())
+        return;
+    LayoutMultiColumnFlowThread* innerFlowThread = toLayoutBlockFlow(box).multiColumnFlowThread();
+    if (!innerFlowThread || innerFlowThread->isLayoutPagedFlowThread())
+        return;
+    LayoutUnit offsetInInnerFlowThread = flowThreadOffset() - innerFlowThread->blockOffsetInEnclosingFragmentationContext();
+    LayoutUnit innerUnbreakableHeight = innerFlowThread->tallestUnbreakableLogicalHeight(offsetInInnerFlowThread);
+    m_tallestUnbreakableLogicalHeight = std::max(m_tallestUnbreakableLogicalHeight, innerUnbreakableHeight);
 }
 
 void InitialColumnHeightFinder::examineBoxBeforeLeaving(const LayoutBox& box)
@@ -144,7 +153,7 @@
     LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop;
     LayoutUnit minimumLogialHeight = columnLogicalHeightRequirementForLine(line.block().styleRef(), line);
     m_tallestUnbreakableLogicalHeight = std::max(m_tallestUnbreakableLogicalHeight, minimumLogialHeight);
-    ASSERT(isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut());
+    ASSERT(isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut() || !isLogicalTopWithinBounds(lineTopInFlowThread - line.paginationStrut()));
     if (isFirstAfterBreak(lineTopInFlowThread))
         recordStrutBeforeOffset(lineTopInFlowThread, line.paginationStrut());
 }
@@ -235,34 +244,37 @@
 
 void MinimumSpaceShortageFinder::examineBoxAfterEntering(const LayoutBox& box)
 {
-    if (box.hasForcedBreakBefore())
-        m_forcedBreaksCount++;
-    if (box.hasForcedBreakAfter())
-        m_forcedBreaksCount++;
+    LayoutBox::PaginationBreakability breakability = box.paginationBreakability();
 
     // Look for breaks before the child box.
-    bool isFirstAfterBreak = this->isFirstAfterBreak(flowThreadOffset());
-    ASSERT(isFirstAfterBreak || !box.paginationStrut());
-    LayoutBox::PaginationBreakability breakability = box.paginationBreakability();
-    if (isFirstAfterBreak && !box.hasForcedBreakBefore()) {
-        // This box is first after a soft break.
-        LayoutUnit strut = box.paginationStrut();
-        // Figure out how much more space we would need to prevent it from being pushed to the next column.
-        recordSpaceShortage(box.logicalHeight() - strut);
-        if (breakability != LayoutBox::ForbidBreaks && m_pendingStrut == LayoutUnit::min()) {
-            // We now want to look for the first piece of unbreakable content (e.g. a line or a
-            // block-displayed image) inside this block. That ought to be a good candidate for
-            // minimum space shortage; a much better one than reporting space shortage for the
-            // entire block (which we'll also do (further down), in case we couldn't find anything
-            // more suitable).
-            m_pendingStrut = strut;
+    if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) {
+        ASSERT(isFirstAfterBreak(flowThreadOffset()) || !box.paginationStrut());
+        if (box.hasForcedBreakBefore()) {
+            m_forcedBreaksCount++;
+        } else if (isFirstAfterBreak(flowThreadOffset())) {
+            // This box is first after a soft break.
+            LayoutUnit strut = box.paginationStrut();
+            // Figure out how much more space we would need to prevent it from being pushed to the next column.
+            recordSpaceShortage(box.logicalHeight() - strut);
+            if (breakability != LayoutBox::ForbidBreaks && m_pendingStrut == LayoutUnit::min()) {
+                // We now want to look for the first piece of unbreakable content (e.g. a line or a
+                // block-displayed image) inside this block. That ought to be a good candidate for
+                // minimum space shortage; a much better one than reporting space shortage for the
+                // entire block (which we'll also do (further down), in case we couldn't find anything
+                // more suitable).
+                m_pendingStrut = strut;
+            }
         }
     }
 
+    if (box.hasForcedBreakAfter() && isLogicalBottomWithinBounds(flowThreadOffset() + box.logicalHeight()))
+        m_forcedBreaksCount++;
+
     if (breakability != LayoutBox::ForbidBreaks) {
         // See if this breakable box crosses column boundaries.
         LayoutUnit bottomInFlowThread = flowThreadOffset() + box.logicalHeight();
-        if (isFirstAfterBreak || group().columnLogicalTopForOffset(flowThreadOffset()) != group().columnLogicalTopForOffset(bottomInFlowThread)) {
+        if (isFirstAfterBreak(flowThreadOffset())
+            || group().columnLogicalTopForOffset(flowThreadOffset()) != group().columnLogicalTopForOffset(bottomInFlowThread)) {
             // If the child crosses a column boundary, record space shortage, in case nothing
             // inside it has already done so. The column balancer needs to know by how much it
             // has to stretch the columns to make more content fit. If no breaks are reported
@@ -277,7 +289,7 @@
     if (!box.isLayoutBlockFlow())
         return;
     LayoutMultiColumnFlowThread* flowThread = toLayoutBlockFlow(box).multiColumnFlowThread();
-    if (!flowThread)
+    if (!flowThread || flowThread->isLayoutPagedFlowThread())
         return;
     for (const LayoutMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet()) {
         for (const MultiColumnFragmentainerGroup& row : columnSet->fragmentainerGroups()) {
@@ -314,7 +326,7 @@
         m_pendingStrut = LayoutUnit::min();
         return;
     }
-    ASSERT(isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut());
+    ASSERT(isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut() || !isLogicalTopWithinBounds(lineTopInFlowThread - line.paginationStrut()));
     if (isFirstAfterBreak(lineTopInFlowThread))
         recordSpaceShortage(lineHeight - line.paginationStrut());
 }
diff --git a/third_party/WebKit/Source/core/layout/ColumnBalancer.h b/third_party/WebKit/Source/core/layout/ColumnBalancer.h
index 9bf1dacc..f78e191 100644
--- a/third_party/WebKit/Source/core/layout/ColumnBalancer.h
+++ b/third_party/WebKit/Source/core/layout/ColumnBalancer.h
@@ -19,13 +19,26 @@
     LayoutUnit flowThreadOffset() const { return m_flowThreadOffset; }
 
     // Return true if the specified offset is at the top of a column, as long as it's not the first
-    // column in the multicol container.
+    // column in the fragmentainer group.
     bool isFirstAfterBreak(LayoutUnit flowThreadOffset) const
     {
         if (flowThreadOffset != m_group.columnLogicalTopForOffset(flowThreadOffset))
             return false; // Not at the top of a column.
-        // The first column in the first group isn't after any break.
-        return flowThreadOffset > m_group.logicalTopInFlowThread() || !m_group.isFirstGroup();
+        // The first column in the fragmentainer group is either not after any break at all, or
+        // after a break that belongs to the previous fragmentainer group.
+        return flowThreadOffset > m_group.logicalTopInFlowThread();
+    }
+
+    bool isLogicalTopWithinBounds(LayoutUnit logicalTopInFlowThread) const
+    {
+        return (m_group.isFirstGroup() || logicalTopInFlowThread >= m_group.logicalTopInFlowThread())
+            && (m_group.isLastGroup() || logicalTopInFlowThread < m_group.logicalBottomInFlowThread());
+    }
+
+    bool isLogicalBottomWithinBounds(LayoutUnit logicalBottomInFlowThread) const
+    {
+        return (m_group.isFirstGroup() || logicalBottomInFlowThread > m_group.logicalTopInFlowThread())
+            && (m_group.isLastGroup() || logicalBottomInFlowThread <= m_group.logicalBottomInFlowThread());
     }
 
     // Examine and collect column balancing data from a layout box that has been found to intersect
diff --git a/third_party/WebKit/Source/core/layout/FragmentationContext.h b/third_party/WebKit/Source/core/layout/FragmentationContext.h
new file mode 100644
index 0000000..dd8d8ff7
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/FragmentationContext.h
@@ -0,0 +1,53 @@
+// 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 FragmentationContext_h
+#define FragmentationContext_h
+
+#include "core/CoreExport.h"
+#include "platform/LayoutUnit.h"
+#include "platform/geometry/LayoutSize.h"
+
+namespace blink {
+
+// A fragmentation context is either established by a multicol container, or by pages when
+// printing. A fragmentation context consists of a series of fragmentainers. A fragmentainer is
+// simply a column or page, depending on the type of fragmentation context. [1]
+//
+// A couple of methods here take a |blockOffset| parameter. This is the offset from the start of the
+// fragmentation context, pretending that everything is laid out in one single strip (and not sliced
+// into pages or columns). In multicol, this is referred to as the flow thread coordinate space.
+//
+// It should be noted that a multicol container may be nested inside another fragmentation context
+// (another multicol container, or the pages when printing), although this class doesn't deal with
+// that (it's internal to the multicol implementation).
+//
+// [1] http://www.w3.org/TR/css3-break/#fragmentation-model
+class CORE_EXPORT FragmentationContext {
+public:
+    virtual ~FragmentationContext() { }
+
+    // The height of the fragmentainers may depend on the total height of the contents (column
+    // balancing), in which case false is returned if we haven't laid out yet. Otherwise, true is
+    // returned.
+    virtual bool isFragmentainerLogicalHeightKnown() = 0;
+
+    // Return the height of the fragmentainer at the specified offset. The fragmentainer height
+    // isn't necessarily uniform all across the fragmentation context.
+    virtual LayoutUnit fragmentainerLogicalHeightAt(LayoutUnit blockOffset) = 0;
+
+    // Return how much is left of the fragmentainer at the specified offset. Callers typically want
+    // this information to decide whether some piece of content fits in this fragmentainer, or if it
+    // has to push the content to the next fragmentainer.
+    virtual LayoutUnit remainingLogicalHeightAt(LayoutUnit blockOffset) = 0;
+
+    // Return the flow thread of the fragmentation context, if it is a multicol fragmentation
+    // context. Since multicol containers may be nested inside other fragmentation contexts,
+    // sometimes we need to know if it's a multicol container that we're dealing with.
+    virtual class LayoutMultiColumnFlowThread* associatedFlowThread() { return nullptr; }
+};
+
+} // namespace blink
+
+#endif // FragmentationContext_h
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
index c7939b6..a1e1e39 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -1548,6 +1548,7 @@
         return;
 
     for (auto* box : *descendants) {
+        ASSERT(box->isDescendantOf(this));
         while (box != this) {
             if (box->normalChildNeedsLayout())
                 break;
@@ -1676,21 +1677,24 @@
         }
     }
 
-    // If we have clipping, then we can't have any spillout.
-    bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer();
-    bool useClip = (hasControlClip() || useOverflowClip);
-    bool checkChildren = !useClip;
-    if (!checkChildren) {
-        if (hasControlClip()) {
-            checkChildren = locationInContainer.intersects(controlClipRect(adjustedLocation));
+    bool checkChildren = true;
+
+    // Self painting layers will handle overflow clip in most cases, but without one we need to
+    // check if overflip clip will affect child hit testing.
+    if (hasOverflowClip() && !hasSelfPaintingLayer()) {
+        if (style()->hasBorderRadius()) {
+            LayoutRect borderRect = borderBoxRect();
+            borderRect.moveBy(adjustedLocation);
+            checkChildren = locationInContainer.intersects(style()->getRoundedInnerBorderFor(borderRect));
         } else {
-            LayoutRect clipRect = overflowClipRect(adjustedLocation, IncludeOverlayScrollbarSize);
-            if (style()->hasBorderRadius())
-                checkChildren = locationInContainer.intersects(style()->getRoundedBorderFor(clipRect));
-            else
-                checkChildren = locationInContainer.intersects(clipRect);
+            checkChildren = locationInContainer.intersects(overflowClipRect(adjustedLocation, IncludeOverlayScrollbarSize));
         }
     }
+
+    // A control clip can also clip out child hit testing.
+    if (checkChildren && hasControlClip())
+        checkChildren = locationInContainer.intersects(controlClipRect(adjustedLocation));
+
     if (checkChildren) {
         // Hit test descendants first.
         LayoutSize scrolledOffset(localOffset);
@@ -1710,8 +1714,7 @@
     if (style()->hasBorderRadius()) {
         LayoutRect borderRect = borderBoxRect();
         borderRect.moveBy(adjustedLocation);
-        FloatRoundedRect border = style()->getRoundedBorderFor(borderRect);
-        if (!locationInContainer.intersects(border))
+        if (!locationInContainer.intersects(style()->getRoundedBorderFor(borderRect)))
             return false;
     }
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.h b/third_party/WebKit/Source/core/layout/LayoutBlock.h
index 5f047ae..fab87114 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.h
@@ -409,7 +409,7 @@
     // FIXME-BLOCKFLOW: Remove virtualizaion when all callers have moved to LayoutBlockFlow
     virtual bool hitTestFloats(HitTestResult&, const HitTestLocation&, const LayoutPoint&) { return false; }
 
-    virtual bool isPointInOverflowControl(HitTestResult&, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset) const;
+    bool isPointInOverflowControl(HitTestResult&, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset) const;
 
     void computeBlockPreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const;
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
index d819092..428415f4 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -1751,6 +1751,7 @@
     if (!containsFloats())
         return;
     removeFloatingObjects();
+    setChildNeedsLayout(MarkOnlyThis);
 
     // 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.
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
index 4a51e69..3b671d8 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -48,6 +48,7 @@
 #include "core/layout/LayoutListMarker.h"
 #include "core/layout/LayoutMultiColumnSpannerPlaceholder.h"
 #include "core/layout/LayoutPart.h"
+#include "core/layout/LayoutReplica.h"
 #include "core/layout/LayoutScrollbarPart.h"
 #include "core/layout/LayoutTableCell.h"
 #include "core/layout/LayoutView.h"
@@ -1315,7 +1316,7 @@
         childLocalRect.moveBy(-childLocation);
         if (childLocalRect.y() < 0 || childLocalRect.x() < 0) {
             // If there is unobscured area above/left of a static positioned box then the rect is probably not covered.
-            if (childBox->style()->position() == StaticPosition)
+            if (!childBox->isPositioned())
                 return false;
             continue;
         }
@@ -1456,6 +1457,16 @@
     return reason;
 }
 
+void LayoutBox::invalidatePaintOfSubtreesIfNeeded(PaintInvalidationState& childPaintInvalidationState)
+{
+    LayoutBoxModelObject::invalidatePaintOfSubtreesIfNeeded(childPaintInvalidationState);
+
+    if (PaintLayer* layer = this->layer()) {
+        if (PaintLayerReflectionInfo* reflectionInfo = layer->reflectionInfo())
+            reflectionInfo->reflection()->invalidateTreeIfNeeded(childPaintInvalidationState);
+    }
+}
+
 LayoutRect LayoutBox::overflowClipRect(const LayoutPoint& location, OverlayScrollbarSizeRelevancy relevancy) const
 {
     // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property
@@ -4845,4 +4856,11 @@
     return ShapeOutsideInfo::isEnabledFor(*this) ? ShapeOutsideInfo::info(*this) : nullptr;
 }
 
+void LayoutBox::clearPreviousPaintInvalidationRects()
+{
+    LayoutBoxModelObject::clearPreviousPaintInvalidationRects();
+    if (PaintLayerScrollableArea* scrollableArea = this->scrollableArea())
+        scrollableArea->clearPreviousPaintInvalidationRects();
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.h b/third_party/WebKit/Source/core/layout/LayoutBox.h
index 21e1e12..16efa068 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.h
@@ -846,6 +846,8 @@
     void mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr) const override;
     void mapAbsoluteToLocalPoint(MapCoordinatesFlags, TransformState&) const override;
 
+    void clearPreviousPaintInvalidationRects() override;
+
 protected:
     void willBeDestroyed() override;
 
@@ -877,6 +879,7 @@
     void incrementallyInvalidatePaint(const LayoutBoxModelObject& paintInvalidationContainer, const LayoutRect& oldBounds, const LayoutRect& newBounds, const LayoutPoint& positionFromPaintInvalidationContainer) override;
 
     PaintInvalidationReason invalidatePaintIfNeeded(PaintInvalidationState&, const LayoutBoxModelObject& paintInvalidationContainer) override;
+    void invalidatePaintOfSubtreesIfNeeded(PaintInvalidationState& childPaintInvalidationState) override;
 
     bool hasNonCompositedScrollbars() const final;
     void excludeScrollbars(LayoutRect&, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
index 06b7478..0c7af6c 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
@@ -402,7 +402,7 @@
     }
 }
 
-void LayoutBoxModelObject::invalidateDisplayItemClientOnBacking(const DisplayItemClientWrapper& displayItemClient, PaintInvalidationReason invalidationReason, const LayoutRect* paintInvalidationRect) const
+void LayoutBoxModelObject::invalidateDisplayItemClientOnBacking(const DisplayItemClient& displayItemClient, PaintInvalidationReason invalidationReason, const LayoutRect* paintInvalidationRect) const
 {
     if (layer()->groupedMapping()) {
         if (GraphicsLayer* squashingLayer = layer()->groupedMapping()->squashingLayer()) {
@@ -413,7 +413,7 @@
             squashingLayer->invalidateDisplayItemClient(displayItemClient, invalidationReason, paintInvalidationRect ? &paintInvalidationRectOnSquashingLayer : nullptr);
         }
     } else if (CompositedLayerMapping* compositedLayerMapping = layer()->compositedLayerMapping()) {
-        if (this->displayItemClient() != displayItemClient.displayItemClient() && isBox() && toLayoutBox(this)->usesCompositedScrolling()) {
+        if (this != &displayItemClient && isBox() && toLayoutBox(this)->usesCompositedScrolling()) {
             // This paint invalidation container is using composited scrolling, and we are invalidating a scrolling content,
             // so we should invalidate on the scrolling contents layer only.
             compositedLayerMapping->invalidateDisplayItemClientOnScrollingContentsLayer(displayItemClient, invalidationReason, paintInvalidationRect);
@@ -1010,6 +1010,19 @@
 
     ASSERT(this == child->parent());
     ASSERT(!beforeChild || toBoxModelObject == beforeChild->parent());
+
+    // If a child is moving from a block-flow to an inline-flow parent then any floats currently intruding into
+    // the child can no longer do so. This can happen if a block becomes floating or out-of-flow and is moved
+    // to an anonymous block. Remove all floats from their float-lists immediately as markAllDescendantsWithFloatsForLayout
+    // won't attempt to remove floats from parents that have inline-flow if we try later.
+    if (child->isLayoutBlockFlow() && toBoxModelObject->childrenInline() && !child->childrenInline() && !childrenInline()) {
+        toLayoutBlockFlow(child)->removeFloatingObjectsFromDescendants();
+        ASSERT(!toLayoutBlockFlow(child)->containsFloats());
+    }
+
+    if (fullRemoveInsert && isLayoutBlock() && child->isBox())
+        LayoutBlock::removePercentHeightDescendantIfNeeded(toLayoutBox(child));
+
     if (fullRemoveInsert && (toBoxModelObject->isLayoutBlock() || toBoxModelObject->isLayoutInline())) {
         // Takes care of adding the new child correctly if toBlock and fromBlock
         // have different kind of children (block vs inline).
@@ -1027,6 +1040,7 @@
     if (fullRemoveInsert && isLayoutBlock()) {
         LayoutBlock* block = toLayoutBlock(this);
         block->removePositionedObjects(nullptr);
+        LayoutBlock::removePercentHeightDescendantIfNeeded(block);
         if (block->isLayoutBlockFlow())
             toLayoutBlockFlow(block)->removeFloatingObjects();
     }
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
index ce858c5..8e55591 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
@@ -286,7 +286,7 @@
     // Indicate that the contents of this layoutObject need to be repainted. Only has an effect if compositing is being used,
     void setBackingNeedsPaintInvalidationInRect(const LayoutRect&, PaintInvalidationReason) const; // r is in the coordinate space of this layout object
 
-    void invalidateDisplayItemClientOnBacking(const DisplayItemClientWrapper&, PaintInvalidationReason, const LayoutRect* paintInvalidationRect) const;
+    void invalidateDisplayItemClientOnBacking(const DisplayItemClient&, PaintInvalidationReason, const LayoutRect* paintInvalidationRect) const;
 
     // http://www.w3.org/TR/css3-background/#body-background
     // <html> root element with no background steals background from its first <body> child.
diff --git a/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp b/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp
index 938e9ed..b99ee7b 100644
--- a/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp
@@ -28,7 +28,9 @@
 
 #include "core/layout/LayoutMultiColumnSet.h"
 #include "core/layout/LayoutMultiColumnSpannerPlaceholder.h"
+#include "core/layout/LayoutView.h"
 #include "core/layout/MultiColumnFragmentainerGroup.h"
+#include "core/layout/ViewFragmentationContext.h"
 
 namespace blink {
 
@@ -355,7 +357,7 @@
 
     m_needsColumnHeightsRecalculation = false;
 
-    m_blockOffsetInEnclosingFlowThread = enclosingFlowThread() ? multiColumnBlockFlow()->offsetFromLogicalTopOfFirstPage() : LayoutUnit();
+    m_blockOffsetInEnclosingFragmentationContext = enclosingFragmentationContext() ? multiColumnBlockFlow()->offsetFromLogicalTopOfFirstPage() : LayoutUnit();
 
     for (LayoutBox* columnBox = firstMultiColumnBox(); columnBox; columnBox = columnBox->nextSiblingMultiColumnBox()) {
         if (!columnBox->isLayoutMultiColumnSet()) {
@@ -434,11 +436,23 @@
 
 LayoutMultiColumnFlowThread* LayoutMultiColumnFlowThread::enclosingFlowThread() const
 {
+    if (isLayoutPagedFlowThread()) {
+        // Paged overflow containers should never be fragmented by enclosing fragmentation
+        // contexts. They are to be treated as unbreakable content.
+        return nullptr;
+    }
     if (multiColumnBlockFlow()->isInsideFlowThread())
         return toLayoutMultiColumnFlowThread(locateFlowThreadContainingBlockOf(*multiColumnBlockFlow()));
     return nullptr;
 }
 
+FragmentationContext* LayoutMultiColumnFlowThread::enclosingFragmentationContext() const
+{
+    if (LayoutMultiColumnFlowThread* enclosingFlowThread = this->enclosingFlowThread())
+        return enclosingFlowThread;
+    return view()->fragmentationContext();
+}
+
 void LayoutMultiColumnFlowThread::appendNewFragmentainerGroupIfNeeded(LayoutUnit offsetInFlowThread)
 {
     if (!isPageLogicalHeightKnown()) {
@@ -458,18 +472,34 @@
     }
 
     if (!columnSet->hasFragmentainerGroupForColumnAt(offsetInFlowThread)) {
-        LayoutMultiColumnFlowThread* enclosingFlowThread = this->enclosingFlowThread();
-        if (!enclosingFlowThread)
+        FragmentationContext* enclosingFragmentationContext = this->enclosingFragmentationContext();
+        if (!enclosingFragmentationContext)
             return; // Not nested. We'll never need more rows than the one we already have then.
-
+        ASSERT(!isLayoutPagedFlowThread());
         // We have run out of columns here, so we add another row to hold more columns. When we add
         // a new row, it implicitly means that we're inserting another column in our enclosing
         // multicol container. That in turn may mean that we've run out of columns there too.
         const MultiColumnFragmentainerGroup& newRow = columnSet->appendNewFragmentainerGroup();
-        enclosingFlowThread->appendNewFragmentainerGroupIfNeeded(newRow.blockOffsetInEnclosingFlowThread());
+        if (LayoutMultiColumnFlowThread* enclosingFlowThread = enclosingFragmentationContext->associatedFlowThread())
+            enclosingFlowThread->appendNewFragmentainerGroupIfNeeded(newRow.blockOffsetInEnclosingFragmentationContext());
     }
 }
 
+bool LayoutMultiColumnFlowThread::isFragmentainerLogicalHeightKnown()
+{
+    return isPageLogicalHeightKnown();
+}
+
+LayoutUnit LayoutMultiColumnFlowThread::fragmentainerLogicalHeightAt(LayoutUnit blockOffset)
+{
+    return pageLogicalHeightForOffset(blockOffset);
+}
+
+LayoutUnit LayoutMultiColumnFlowThread::remainingLogicalHeightAt(LayoutUnit blockOffset)
+{
+    return pageRemainingLogicalHeightForOffset(blockOffset, AssociateWithLatterPage);
+}
+
 void LayoutMultiColumnFlowThread::calculateColumnCountAndWidth(LayoutUnit& width, unsigned& count) const
 {
     LayoutBlock* columnBlock = multiColumnBlockFlow();
@@ -915,12 +945,12 @@
 
     // First figure out if there's any chance that we're nested at all. If we can be sure that
     // we're not, bail early. This code is run very often, and since locating a containing flow
-    // thread has some cost (depending on tree depth), avoid calling enclosingFlowThread() right
-    // away. This test may give some false positives (hence the "mayBe"), if we're in an
-    // out-of-flow subtree and have an outer multicol container that doesn't affect us, but that's
-    // okay. We'll discover that further down the road when trying to locate our enclosing flow
-    // thread for real.
-    bool mayBeNested = multiColumnBlockFlow()->isInsideFlowThread();
+    // thread has some cost (depending on tree depth), avoid calling
+    // enclosingFragmentationContext() right away. This test may give some false positives (hence
+    // the "mayBe"), if we're in an out-of-flow subtree and have an outer multicol container that
+    // doesn't affect us, but that's okay. We'll discover that further down the road when trying to
+    // locate our enclosing flow thread for real.
+    bool mayBeNested = multiColumnBlockFlow()->isInsideFlowThread() || view()->fragmentationContext();
     if (!mayBeNested)
         return;
     appendNewFragmentainerGroupIfNeeded(logicalTopInFlowThreadAfterPagination);
diff --git a/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.h b/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.h
index 084b16e4..bacdc4e 100644
--- a/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.h
+++ b/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.h
@@ -28,6 +28,7 @@
 #define LayoutMultiColumnFlowThread_h
 
 #include "core/CoreExport.h"
+#include "core/layout/FragmentationContext.h"
 #include "core/layout/LayoutFlowThread.h"
 
 namespace blink {
@@ -112,7 +113,7 @@
 //
 // There's also some documentation online:
 // https://sites.google.com/a/chromium.org/dev/developers/design-documents/multi-column-layout
-class CORE_EXPORT LayoutMultiColumnFlowThread : public LayoutFlowThread {
+class CORE_EXPORT LayoutMultiColumnFlowThread : public LayoutFlowThread, public FragmentationContext {
 public:
     ~LayoutMultiColumnFlowThread() override;
 
@@ -190,13 +191,20 @@
     bool removeSpannerPlaceholderIfNoLongerValid(LayoutBox* spannerObjectInFlowThread);
 
     LayoutMultiColumnFlowThread* enclosingFlowThread() const;
-    LayoutUnit blockOffsetInEnclosingFlowThread() const { ASSERT(enclosingFlowThread()); return m_blockOffsetInEnclosingFlowThread; }
+    FragmentationContext* enclosingFragmentationContext() const;
+    LayoutUnit blockOffsetInEnclosingFragmentationContext() const { ASSERT(enclosingFragmentationContext()); return m_blockOffsetInEnclosingFragmentationContext; }
 
     // If we've run out of columns in the last fragmentainer group (column row), we have to insert
     // another fragmentainer group in order to hold more columns. This means that we're moving to
     // the next outer column (in the enclosing fragmentation context).
     void appendNewFragmentainerGroupIfNeeded(LayoutUnit offsetInFlowThread);
 
+    // Implementing FragmentationContext:
+    bool isFragmentainerLogicalHeightKnown() final;
+    LayoutUnit fragmentainerLogicalHeightAt(LayoutUnit blockOffset) final;
+    LayoutUnit remainingLogicalHeightAt(LayoutUnit blockOffset) final;
+    LayoutMultiColumnFlowThread* associatedFlowThread() final { return this; }
+
     const char* name() const override { return "LayoutMultiColumnFlowThread"; }
 
 protected:
@@ -231,9 +239,9 @@
     unsigned m_columnCount; // The used value of column-count
     LayoutUnit m_columnHeightAvailable; // Total height available to columns, or 0 if auto.
 
-    // Cached block offset from this flow thread to the enclosing flow thread, if any. In the
-    // coordinate space of the enclosing flow thread.
-    LayoutUnit m_blockOffsetInEnclosingFlowThread;
+    // Cached block offset from this flow thread to the enclosing fragmentation context, if any. In
+    // the coordinate space of the enclosing fragmentation context.
+    LayoutUnit m_blockOffsetInEnclosingFragmentationContext;
 
     bool m_inBalancingPass; // Set when relayouting for column balancing.
     bool m_needsColumnHeightsRecalculation; // Set when we need to recalculate the column set heights after layout.
diff --git a/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.cpp b/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.cpp
index b316cf8f..e49a812 100644
--- a/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.cpp
@@ -101,8 +101,8 @@
 LayoutUnit LayoutMultiColumnSet::nextLogicalTopForUnbreakableContent(LayoutUnit flowThreadOffset, LayoutUnit contentLogicalHeight) const
 {
     ASSERT(pageLogicalTopForOffset(flowThreadOffset) == flowThreadOffset);
-    LayoutMultiColumnFlowThread* enclosingFlowThread = multiColumnFlowThread()->enclosingFlowThread();
-    if (!enclosingFlowThread) {
+    FragmentationContext* enclosingFragmentationContext = multiColumnFlowThread()->enclosingFragmentationContext();
+    if (!enclosingFragmentationContext) {
         // If there's no enclosing fragmentation context, there'll ever be only one row, and all
         // columns there will have the same height.
         return flowThreadOffset;
@@ -119,7 +119,7 @@
     LayoutUnit firstRowLogicalBottomInFlowThread = firstRow.logicalTopInFlowThread() + firstRow.logicalHeight() * usedColumnCount();
     if (flowThreadOffset >= firstRowLogicalBottomInFlowThread)
         return flowThreadOffset; // We're not in the first row. Give up.
-    LayoutUnit newLogicalHeight = enclosingFlowThread->pageLogicalHeightForOffset(firstRowLogicalBottomInFlowThread);
+    LayoutUnit newLogicalHeight = enclosingFragmentationContext->fragmentainerLogicalHeightAt(firstRowLogicalBottomInFlowThread);
     if (contentLogicalHeight > newLogicalHeight) {
         // The next outer column or page doesn't have enough space either. Give up and stay where
         // we are.
@@ -255,7 +255,7 @@
 
 bool LayoutMultiColumnSet::recalculateColumnHeight()
 {
-    if (m_oldLogicalTop != logicalTop() && multiColumnFlowThread()->enclosingFlowThread()) {
+    if (m_oldLogicalTop != logicalTop() && multiColumnFlowThread()->enclosingFragmentationContext()) {
         // Preceding spanners or column sets have been moved or resized. This means that the
         // fragmentainer groups that we have inserted need to be re-inserted. Restart column
         // balancing.
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
index 4670bbc..9518112 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -132,7 +132,7 @@
 
 struct SameSizeAsLayoutObject {
     virtual ~SameSizeAsLayoutObject() { } // Allocate vtable pointer.
-    void* pointers[5];
+    void* pointers[6];
 #if ENABLE(ASSERT)
     unsigned m_debugBitfields : 2;
 #endif
@@ -866,7 +866,7 @@
     // we may not have one if we're part of an uninstalled
     // subtree. We'll climb as high as we can though.
     for (LayoutObject* object = parent(); object; object = object->parent()) {
-        if (object->style()->position() != StaticPosition)
+        if (object->isPositioned())
             return object;
 
         if (object->canContainFixedPositionObjects())
@@ -1229,7 +1229,7 @@
         paintInvalidationContainer.setBackingNeedsPaintInvalidationInRect(dirtyRect, invalidationReason);
 }
 
-void LayoutObject::invalidateDisplayItemClient(const DisplayItemClientWrapper& displayItemClient) const
+void LayoutObject::invalidateDisplayItemClient(const DisplayItemClient& displayItemClient) const
 {
     // TODO(wangxianzhu): Ensure correct bounds for the client will be or has been passed to PaintController. crbug.com/547119.
     // Not using enclosingCompositedContainer() directly because this object may be in an orphaned subtree.
@@ -1517,6 +1517,11 @@
     m_previousPaintInvalidationRect.move(LayoutSize(scrollDelta));
 }
 
+void LayoutObject::clearPreviousPaintInvalidationRects()
+{
+    setPreviousPaintInvalidationRect(LayoutRect());
+}
+
 void LayoutObject::incrementallyInvalidatePaint(const LayoutBoxModelObject& paintInvalidationContainer, const LayoutRect& oldBounds, const LayoutRect& newBounds, const LayoutPoint& positionFromPaintInvalidationBacking)
 {
     ASSERT(oldBounds.location() == newBounds.location());
@@ -3240,13 +3245,6 @@
 
 inline void LayoutObject::markContainerChainForPaintInvalidation()
 {
-    // Setting layer-needs-repaint doesn't mean we'll fully repaint the layer, but
-    // means we won't skip painting of the whole layer with a CachedSubsequenceDisplayItem.
-    // This is to ensure we'll check paint offset changes of the objects on the layer.
-    // We'll still use cached display items for non-invalidated objects on the layer.
-    if (PaintLayer* enclosingLayer = this->enclosingLayer())
-        enclosingLayer->setNeedsRepaint();
-
     for (LayoutObject* container = this->containerCrossingFrameBoundaries(); container && !container->shouldCheckForPaintInvalidationRegardlessOfPaintInvalidationState(); container = container->containerCrossingFrameBoundaries())
         container->m_bitfields.setChildShouldCheckForPaintInvalidation(true);
 }
@@ -3423,7 +3421,7 @@
     // Clear previous paint invalidation rect on the original paint invalidation container to avoid
     // under-invalidation if the new paint invalidation rect on the new paint invalidation container
     // happens to be the same as the old one.
-    setPreviousPaintInvalidationRect(LayoutRect());
+    clearPreviousPaintInvalidationRects();
 }
 
 void LayoutObject::invalidatePaintIncludingNonCompositingDescendants()
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h
index 2a922ed..709f3bba 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -204,7 +204,7 @@
 // preferredLogicalWidthsDirty.
 //
 // See the individual getters below for more details about what each width is.
-class CORE_EXPORT LayoutObject : public ImageResourceClient {
+class CORE_EXPORT LayoutObject : public ImageResourceClient, public DisplayItemClient {
     friend class LayoutObjectChildList;
     WTF_MAKE_NONCOPYABLE(LayoutObject);
 public:
@@ -1237,7 +1237,9 @@
     // this object).
     LayoutRect previousPaintInvalidationRectIncludingCompositedScrolling(const LayoutBoxModelObject& paintInvalidationContainer) const;
     LayoutSize previousPaintInvalidationRectSize() const { return previousPaintInvalidationRect().size(); }
-    void setPreviousPaintInvalidationRect(const LayoutRect& rect) { m_previousPaintInvalidationRect = rect; }
+
+    // Called when the previous paint invalidation rect(s) is no longer valid.
+    virtual void clearPreviousPaintInvalidationRects();
 
     // Only adjusts if the paint invalidation container is not a composited scroller.
     void adjustPreviousPaintInvalidationForScrollIfNeeded(const DoubleSize& scrollDelta);
@@ -1299,9 +1301,7 @@
 
     virtual LayoutRect viewRect() const;
 
-    DisplayItemClient displayItemClient() const { return toDisplayItemClient(this); }
-
-    void invalidateDisplayItemClient(const DisplayItemClientWrapper&) const;
+    void invalidateDisplayItemClient(const DisplayItemClient&) const;
     void invalidateDisplayItemClientsIncludingNonCompositingDescendants(const LayoutBoxModelObject* paintInvalidationContainer, PaintInvalidationReason, const LayoutRect* paintInvalidationRect) const;
 
     // Called before anonymousChild.setStyle(). Override to set custom styles for the child.
@@ -1435,6 +1435,8 @@
     // of this layoutObject within the current layer that should be used for each result.
     virtual void computeSelfHitTestRects(Vector<LayoutRect>&, const LayoutPoint& layerOffset) const { }
 
+    void setPreviousPaintInvalidationRect(const LayoutRect& rect) { m_previousPaintInvalidationRect = rect; }
+
     virtual PaintInvalidationReason paintInvalidationReason(const LayoutBoxModelObject& paintInvalidationContainer,
         const LayoutRect& oldPaintInvalidationRect, const LayoutPoint& oldPositionFromPaintInvalidationBacking,
         const LayoutRect& newPaintInvalidationRect, const LayoutPoint& newPositionFromPaintInvalidationBacking) const;
diff --git a/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp b/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp
index fc8066f..6afcf09 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp
@@ -6,11 +6,14 @@
 #include "core/layout/LayoutObject.h"
 
 #include "core/layout/LayoutTestHelper.h"
+#include "core/layout/LayoutView.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
 
 class LayoutObjectTest : public RenderingTest {
+protected:
+    LayoutView& layoutView() const { return *document().layoutView(); }
 };
 
 TEST_F(LayoutObjectTest, LayoutDecoratedNameCalledWithPositionedObject)
@@ -23,5 +26,86 @@
     EXPECT_STREQ("LayoutBlockFlow (positioned)", obj->decoratedName().ascii().data());
 }
 
+
+// Some display checks.
+TEST_F(LayoutObjectTest, DisplayNoneCreateObject)
+{
+    setBodyInnerHTML("<div style='display:none'></div>");
+    EXPECT_EQ(nullptr, document().body()->firstChild()->layoutObject());
+}
+
+TEST_F(LayoutObjectTest, DisplayBlockCreateObject)
+{
+    setBodyInnerHTML("<foo style='display:block'></foo>");
+    LayoutObject* layoutObject = document().body()->firstChild()->layoutObject();
+    EXPECT_NE(nullptr, layoutObject);
+    EXPECT_TRUE(layoutObject->isLayoutBlockFlow());
+    EXPECT_FALSE(layoutObject->isInline());
+}
+
+TEST_F(LayoutObjectTest, DisplayInlineBlockCreateObject)
+{
+    setBodyInnerHTML("<foo style='display:inline-block'></foo>");
+    LayoutObject* layoutObject = document().body()->firstChild()->layoutObject();
+    EXPECT_NE(nullptr, layoutObject);
+    EXPECT_TRUE(layoutObject->isLayoutBlockFlow());
+    EXPECT_TRUE(layoutObject->isInline());
+}
+
+
+
+// Containing block test.
+TEST_F(LayoutObjectTest, ContainingBlockLayoutViewShouldBeNull)
+{
+    EXPECT_EQ(nullptr, layoutView().containingBlock());
+}
+
+TEST_F(LayoutObjectTest, ContainingBlockBodyShouldBeDocumentElement)
+{
+    EXPECT_EQ(document().body()->layoutObject()->containingBlock(), document().documentElement()->layoutObject());
+}
+
+TEST_F(LayoutObjectTest, ContainingBlockDocumentElementShouldBeLayoutView)
+{
+    EXPECT_EQ(document().documentElement()->layoutObject()->containingBlock(), layoutView());
+}
+
+TEST_F(LayoutObjectTest, ContainingBlockStaticLayoutObjectShouldBeParent)
+{
+    setBodyInnerHTML("<foo style='position:static'></foo>");
+    LayoutObject* bodyLayoutObject = document().body()->layoutObject();
+    LayoutObject* layoutObject = bodyLayoutObject->slowFirstChild();
+    EXPECT_EQ(layoutObject->containingBlock(), bodyLayoutObject);
+}
+
+TEST_F(LayoutObjectTest, ContainingBlockAbsoluteLayoutObjectShouldBeLayoutView)
+{
+    setBodyInnerHTML("<foo style='position:absolute'></foo>");
+    LayoutObject* layoutObject = document().body()->layoutObject()->slowFirstChild();
+    EXPECT_EQ(layoutObject->containingBlock(), layoutView());
+}
+
+TEST_F(LayoutObjectTest, ContainingBlockAbsoluteLayoutObjectShouldBeNonStaticallyPositionedBlockAncestor)
+{
+    setBodyInnerHTML("<div style='position:relative'><bar style='position:absolute'></bar></div>");
+    LayoutObject* containingBlocklayoutObject = document().body()->layoutObject()->slowFirstChild();
+    LayoutObject* layoutObject = containingBlocklayoutObject->slowFirstChild();
+    EXPECT_EQ(layoutObject->containingBlock(), containingBlocklayoutObject);
+}
+
+TEST_F(LayoutObjectTest, ContainingBlockAbsoluteLayoutObjectShouldNotBeNonStaticlyPositionedInlineAncestor)
+{
+    setBodyInnerHTML("<span style='position:relative'><bar style='position:absolute'></bar></span>");
+    LayoutObject* bodyLayoutObject = document().body()->layoutObject();
+    LayoutObject* layoutObject = bodyLayoutObject->slowFirstChild()->slowFirstChild();
+
+    // Sanity check: Make sure we don't generate anonymous objects.
+    EXPECT_EQ(nullptr, bodyLayoutObject->slowFirstChild()->nextSibling());
+    EXPECT_EQ(nullptr, layoutObject->slowFirstChild());
+    EXPECT_EQ(nullptr, layoutObject->nextSibling());
+
+    EXPECT_EQ(layoutObject->containingBlock(), bodyLayoutObject);
+}
+
 }
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp b/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp
index 2fc349c..a475fb5 100644
--- a/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp
@@ -367,9 +367,10 @@
 {
     ASSERT(preferredLogicalWidthsDirty());
 
-    // We cannot resolve any percent logical width here as the available logical
-    // width may not be set on our containing block.
-    if (style()->logicalWidth().hasPercent())
+    // We cannot resolve some logical width here (i.e. percent, fill-available or fit-content)
+    // as the available logical width may not be set on our containing block.
+    const Length& logicalWidth = style()->logicalWidth();
+    if (logicalWidth.hasPercent() || logicalWidth.isFillAvailable() || logicalWidth.isFitContent())
         computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
     else
         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeReplacedLogicalWidth(ComputePreferred);
diff --git a/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp b/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp
index f3016e76..1e819cb8 100644
--- a/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp
@@ -242,7 +242,7 @@
 
     if (needLayoutObject && partStyle->display() != BLOCK) {
         // See if we are a button that should not be visible according to OS settings.
-        ScrollbarButtonsPlacement buttonsPlacement = theme()->buttonsPlacement();
+        ScrollbarButtonsPlacement buttonsPlacement = theme().buttonsPlacement();
         switch (partType) {
         case BackButtonStartPart:
             needLayoutObject = (buttonsPlacement == ScrollbarButtonsPlacementSingle || buttonsPlacement == ScrollbarButtonsPlacementDoubleStart
diff --git a/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp b/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp
index 87294efd..f500d3d 100644
--- a/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp
@@ -120,7 +120,7 @@
 {
     if (!length.isIntrinsicOrAuto() || (sizeType == MinSize && length.isAuto()))
         return minimumValueForLength(length, containingLength);
-    return ScrollbarTheme::theme()->scrollbarThickness();
+    return ScrollbarTheme::theme().scrollbarThickness();
 }
 
 void LayoutScrollbarPart::computeScrollbarWidth()
diff --git a/third_party/WebKit/Source/core/layout/LayoutScrollbarTheme.cpp b/third_party/WebKit/Source/core/layout/LayoutScrollbarTheme.cpp
index d3e2d73..94aada6 100644
--- a/third_party/WebKit/Source/core/layout/LayoutScrollbarTheme.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutScrollbarTheme.cpp
@@ -41,13 +41,13 @@
     return &theme;
 }
 
-void LayoutScrollbarTheme::buttonSizesAlongTrackAxis(const ScrollbarThemeClient* scrollbar, int& beforeSize, int& afterSize)
+void LayoutScrollbarTheme::buttonSizesAlongTrackAxis(const ScrollbarThemeClient& scrollbar, int& beforeSize, int& afterSize)
 {
     IntRect firstButton = backButtonRect(scrollbar, BackButtonStartPart);
     IntRect secondButton = forwardButtonRect(scrollbar, ForwardButtonStartPart);
     IntRect thirdButton = backButtonRect(scrollbar, BackButtonEndPart);
     IntRect fourthButton = forwardButtonRect(scrollbar, ForwardButtonEndPart);
-    if (scrollbar->orientation() == HorizontalScrollbar) {
+    if (scrollbar.orientation() == HorizontalScrollbar) {
         beforeSize = firstButton.width() + secondButton.width();
         afterSize = thirdButton.width() + fourthButton.width();
     } else {
@@ -56,52 +56,52 @@
     }
 }
 
-bool LayoutScrollbarTheme::hasButtons(const ScrollbarThemeClient* scrollbar)
+bool LayoutScrollbarTheme::hasButtons(const ScrollbarThemeClient& scrollbar)
 {
     int startSize;
     int endSize;
     buttonSizesAlongTrackAxis(scrollbar, startSize, endSize);
-    return (startSize + endSize) <= (scrollbar->orientation() == HorizontalScrollbar ? scrollbar->width() : scrollbar->height());
+    return (startSize + endSize) <= (scrollbar.orientation() == HorizontalScrollbar ? scrollbar.width() : scrollbar.height());
 }
 
-bool LayoutScrollbarTheme::hasThumb(const ScrollbarThemeClient* scrollbar)
+bool LayoutScrollbarTheme::hasThumb(const ScrollbarThemeClient& scrollbar)
 {
     return trackLength(scrollbar) - thumbLength(scrollbar) >= 0;
 }
 
-int LayoutScrollbarTheme::minimumThumbLength(const ScrollbarThemeClient* scrollbar)
+int LayoutScrollbarTheme::minimumThumbLength(const ScrollbarThemeClient& scrollbar)
 {
-    return toLayoutScrollbar(scrollbar)->minimumThumbLength();
+    return toLayoutScrollbar(scrollbar).minimumThumbLength();
 }
 
-IntRect LayoutScrollbarTheme::backButtonRect(const ScrollbarThemeClient* scrollbar, ScrollbarPart partType, bool)
+IntRect LayoutScrollbarTheme::backButtonRect(const ScrollbarThemeClient& scrollbar, ScrollbarPart partType, bool)
 {
-    return toLayoutScrollbar(scrollbar)->buttonRect(partType);
+    return toLayoutScrollbar(scrollbar).buttonRect(partType);
 }
 
-IntRect LayoutScrollbarTheme::forwardButtonRect(const ScrollbarThemeClient* scrollbar, ScrollbarPart partType, bool)
+IntRect LayoutScrollbarTheme::forwardButtonRect(const ScrollbarThemeClient& scrollbar, ScrollbarPart partType, bool)
 {
-    return toLayoutScrollbar(scrollbar)->buttonRect(partType);
+    return toLayoutScrollbar(scrollbar).buttonRect(partType);
 }
 
-IntRect LayoutScrollbarTheme::trackRect(const ScrollbarThemeClient* scrollbar, bool)
+IntRect LayoutScrollbarTheme::trackRect(const ScrollbarThemeClient& scrollbar, bool)
 {
     if (!hasButtons(scrollbar))
-        return scrollbar->frameRect();
+        return scrollbar.frameRect();
 
     int startLength;
     int endLength;
     buttonSizesAlongTrackAxis(scrollbar, startLength, endLength);
 
-    return toLayoutScrollbar(scrollbar)->trackRect(startLength, endLength);
+    return toLayoutScrollbar(scrollbar).trackRect(startLength, endLength);
 }
 
-IntRect LayoutScrollbarTheme::constrainTrackRectToTrackPieces(const ScrollbarThemeClient* scrollbar, const IntRect& rect)
+IntRect LayoutScrollbarTheme::constrainTrackRectToTrackPieces(const ScrollbarThemeClient& scrollbar, const IntRect& rect)
 {
-    IntRect backRect = toLayoutScrollbar(scrollbar)->trackPieceRectWithMargins(BackTrackPart, rect);
-    IntRect forwardRect = toLayoutScrollbar(scrollbar)->trackPieceRectWithMargins(ForwardTrackPart, rect);
+    IntRect backRect = toLayoutScrollbar(scrollbar).trackPieceRectWithMargins(BackTrackPart, rect);
+    IntRect forwardRect = toLayoutScrollbar(scrollbar).trackPieceRectWithMargins(ForwardTrackPart, rect);
     IntRect result = rect;
-    if (scrollbar->orientation() == HorizontalScrollbar) {
+    if (scrollbar.orientation() == HorizontalScrollbar) {
         result.setX(backRect.x());
         result.setWidth(forwardRect.maxX() - backRect.x());
     } else {
@@ -111,44 +111,44 @@
     return result;
 }
 
-void LayoutScrollbarTheme::paintScrollCorner(GraphicsContext* context, const DisplayItemClientWrapper& displayItemClient, const IntRect& cornerRect)
+void LayoutScrollbarTheme::paintScrollCorner(GraphicsContext& context, const DisplayItemClient& displayItemClient, const IntRect& cornerRect)
 {
-    if (DrawingRecorder::useCachedDrawingIfPossible(*context, displayItemClient, DisplayItem::ScrollbarCorner))
+    if (DrawingRecorder::useCachedDrawingIfPossible(context, displayItemClient, DisplayItem::ScrollbarCorner))
         return;
 
-    DrawingRecorder recorder(*context, displayItemClient, DisplayItem::ScrollbarCorner, cornerRect);
+    DrawingRecorder recorder(context, displayItemClient, DisplayItem::ScrollbarCorner, cornerRect);
     // FIXME: Implement.
-    context->fillRect(cornerRect, Color::white);
+    context.fillRect(cornerRect, Color::white);
 }
 
-void LayoutScrollbarTheme::paintScrollbarBackground(GraphicsContext* context, const ScrollbarThemeClient* scrollbar)
+void LayoutScrollbarTheme::paintScrollbarBackground(GraphicsContext& context, const ScrollbarThemeClient& scrollbar)
 {
-    ScrollbarPainter(*toLayoutScrollbar(scrollbar)).paintPart(context, ScrollbarBGPart, scrollbar->frameRect());
+    ScrollbarPainter(toLayoutScrollbar(scrollbar)).paintPart(context, ScrollbarBGPart, scrollbar.frameRect());
 }
 
-void LayoutScrollbarTheme::paintTrackBackground(GraphicsContext* context, const ScrollbarThemeClient* scrollbar, const IntRect& rect)
+void LayoutScrollbarTheme::paintTrackBackground(GraphicsContext& context, const ScrollbarThemeClient& scrollbar, const IntRect& rect)
 {
-    ScrollbarPainter(*toLayoutScrollbar(scrollbar)).paintPart(context, TrackBGPart, rect);
+    ScrollbarPainter(toLayoutScrollbar(scrollbar)).paintPart(context, TrackBGPart, rect);
 }
 
-void LayoutScrollbarTheme::paintTrackPiece(GraphicsContext* context, const ScrollbarThemeClient* scrollbar, const IntRect& rect, ScrollbarPart part)
+void LayoutScrollbarTheme::paintTrackPiece(GraphicsContext& context, const ScrollbarThemeClient& scrollbar, const IntRect& rect, ScrollbarPart part)
 {
-    ScrollbarPainter(*toLayoutScrollbar(scrollbar)).paintPart(context, part, rect);
+    ScrollbarPainter(toLayoutScrollbar(scrollbar)).paintPart(context, part, rect);
 }
 
-void LayoutScrollbarTheme::paintButton(GraphicsContext* context, const ScrollbarThemeClient* scrollbar, const IntRect& rect, ScrollbarPart part)
+void LayoutScrollbarTheme::paintButton(GraphicsContext& context, const ScrollbarThemeClient& scrollbar, const IntRect& rect, ScrollbarPart part)
 {
-    ScrollbarPainter(*toLayoutScrollbar(scrollbar)).paintPart(context, part, rect);
+    ScrollbarPainter(toLayoutScrollbar(scrollbar)).paintPart(context, part, rect);
 }
 
-void LayoutScrollbarTheme::paintThumb(GraphicsContext* context, const ScrollbarThemeClient* scrollbar, const IntRect& rect)
+void LayoutScrollbarTheme::paintThumb(GraphicsContext& context, const ScrollbarThemeClient& scrollbar, const IntRect& rect)
 {
-    ScrollbarPainter(*toLayoutScrollbar(scrollbar)).paintPart(context, ThumbPart, rect);
+    ScrollbarPainter(toLayoutScrollbar(scrollbar)).paintPart(context, ThumbPart, rect);
 }
 
-void LayoutScrollbarTheme::paintTickmarks(GraphicsContext* context, const ScrollbarThemeClient* scrollbar, const IntRect& rect)
+void LayoutScrollbarTheme::paintTickmarks(GraphicsContext& context, const ScrollbarThemeClient& scrollbar, const IntRect& rect)
 {
-    ScrollbarTheme::theme()->paintTickmarks(context, scrollbar, rect);
+    ScrollbarTheme::theme().paintTickmarks(context, scrollbar, rect);
 }
 
 }
diff --git a/third_party/WebKit/Source/core/layout/LayoutScrollbarTheme.h b/third_party/WebKit/Source/core/layout/LayoutScrollbarTheme.h
index d91faeb..c70b2911 100644
--- a/third_party/WebKit/Source/core/layout/LayoutScrollbarTheme.h
+++ b/third_party/WebKit/Source/core/layout/LayoutScrollbarTheme.h
@@ -36,43 +36,43 @@
 public:
     ~LayoutScrollbarTheme() override { }
 
-    int scrollbarThickness(ScrollbarControlSize controlSize) override { return ScrollbarTheme::theme()->scrollbarThickness(controlSize); }
+    int scrollbarThickness(ScrollbarControlSize controlSize) override { return ScrollbarTheme::theme().scrollbarThickness(controlSize); }
 
-    ScrollbarButtonsPlacement buttonsPlacement() const override { return ScrollbarTheme::theme()->buttonsPlacement(); }
+    ScrollbarButtonsPlacement buttonsPlacement() const override { return ScrollbarTheme::theme().buttonsPlacement(); }
 
-    void paintScrollCorner(GraphicsContext*, const DisplayItemClientWrapper&, const IntRect& cornerRect) override;
+    void paintScrollCorner(GraphicsContext&, const DisplayItemClient&, const IntRect& cornerRect) override;
 
-    bool shouldCenterOnThumb(const ScrollbarThemeClient* scrollbar, const PlatformMouseEvent& event) override { return ScrollbarTheme::theme()->shouldCenterOnThumb(scrollbar, event); }
-    bool shouldSnapBackToDragOrigin(const ScrollbarThemeClient* scrollbar, const PlatformMouseEvent& event) override { return ScrollbarTheme::theme()->shouldSnapBackToDragOrigin(scrollbar, event); }
+    bool shouldCenterOnThumb(const ScrollbarThemeClient& scrollbar, const PlatformMouseEvent& event) override { return ScrollbarTheme::theme().shouldCenterOnThumb(scrollbar, event); }
+    bool shouldSnapBackToDragOrigin(const ScrollbarThemeClient& scrollbar, const PlatformMouseEvent& event) override { return ScrollbarTheme::theme().shouldSnapBackToDragOrigin(scrollbar, event); }
 
-    double initialAutoscrollTimerDelay() override { return ScrollbarTheme::theme()->initialAutoscrollTimerDelay(); }
-    double autoscrollTimerDelay() override { return ScrollbarTheme::theme()->autoscrollTimerDelay(); }
+    double initialAutoscrollTimerDelay() override { return ScrollbarTheme::theme().initialAutoscrollTimerDelay(); }
+    double autoscrollTimerDelay() override { return ScrollbarTheme::theme().autoscrollTimerDelay(); }
 
-    void registerScrollbar(ScrollbarThemeClient* scrollbar) override { return ScrollbarTheme::theme()->registerScrollbar(scrollbar); }
-    void unregisterScrollbar(ScrollbarThemeClient* scrollbar) override { return ScrollbarTheme::theme()->unregisterScrollbar(scrollbar); }
+    void registerScrollbar(ScrollbarThemeClient& scrollbar) override { return ScrollbarTheme::theme().registerScrollbar(scrollbar); }
+    void unregisterScrollbar(ScrollbarThemeClient& scrollbar) override { return ScrollbarTheme::theme().unregisterScrollbar(scrollbar); }
 
-    int minimumThumbLength(const ScrollbarThemeClient*) override;
+    int minimumThumbLength(const ScrollbarThemeClient&) override;
 
-    void buttonSizesAlongTrackAxis(const ScrollbarThemeClient*, int& beforeSize, int& afterSize);
+    void buttonSizesAlongTrackAxis(const ScrollbarThemeClient&, int& beforeSize, int& afterSize);
 
     static LayoutScrollbarTheme* layoutScrollbarTheme();
 
 protected:
-    bool hasButtons(const ScrollbarThemeClient*) override;
-    bool hasThumb(const ScrollbarThemeClient*) override;
+    bool hasButtons(const ScrollbarThemeClient&) override;
+    bool hasThumb(const ScrollbarThemeClient&) override;
 
-    IntRect backButtonRect(const ScrollbarThemeClient*, ScrollbarPart, bool painting = false) override;
-    IntRect forwardButtonRect(const ScrollbarThemeClient*, ScrollbarPart, bool painting = false) override;
-    IntRect trackRect(const ScrollbarThemeClient*, bool painting = false) override;
+    IntRect backButtonRect(const ScrollbarThemeClient&, ScrollbarPart, bool painting = false) override;
+    IntRect forwardButtonRect(const ScrollbarThemeClient&, ScrollbarPart, bool painting = false) override;
+    IntRect trackRect(const ScrollbarThemeClient&, bool painting = false) override;
 
-    void paintScrollbarBackground(GraphicsContext*, const ScrollbarThemeClient*) override;
-    void paintTrackBackground(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&) override;
-    void paintTrackPiece(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&, ScrollbarPart) override;
-    void paintButton(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&, ScrollbarPart) override;
-    void paintThumb(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&) override;
-    void paintTickmarks(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&) override;
+    void paintScrollbarBackground(GraphicsContext&, const ScrollbarThemeClient&) override;
+    void paintTrackBackground(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&) override;
+    void paintTrackPiece(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&, ScrollbarPart) override;
+    void paintButton(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&, ScrollbarPart) override;
+    void paintThumb(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&) override;
+    void paintTickmarks(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&) override;
 
-    IntRect constrainTrackRectToTrackPieces(const ScrollbarThemeClient*, const IntRect&) override;
+    IntRect constrainTrackRectToTrackPieces(const ScrollbarThemeClient&, const IntRect&) override;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutTestHelper.cpp b/third_party/WebKit/Source/core/layout/LayoutTestHelper.cpp
index 97db2f3d..518e7dfc 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTestHelper.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTestHelper.cpp
@@ -6,6 +6,7 @@
 #include "core/layout/LayoutTestHelper.h"
 
 #include "core/frame/FrameHost.h"
+#include "core/html/HTMLIFrameElement.h"
 #include "platform/graphics/test/FakeGraphicsLayerFactory.h"
 
 namespace blink {
@@ -42,10 +43,33 @@
 
 void RenderingTest::TearDown()
 {
+    if (m_subframe) {
+        m_subframe->detach(FrameDetachType::Remove);
+        static_cast<SingleChildFrameLoaderClient*>(document().frame()->client())->setChild(nullptr);
+        document().frame()->host()->decrementSubframeCount();
+    }
+
     // We need to destroy most of the Blink structure here because derived tests may restore
     // RuntimeEnabledFeatures setting during teardown, which happens before our destructor
     // getting invoked, breaking the assumption that REF can't change during Blink lifetime.
     m_pageHolder = nullptr;
 }
 
+Document& RenderingTest::setupChildIframe(const AtomicString& iframeElementId, const String& htmlContentOfIframe)
+{
+
+    HTMLIFrameElement& iframe = *toHTMLIFrameElement(document().getElementById(iframeElementId));
+    m_frameLoaderClient = FrameLoaderClientWithParent::create(document().frame());
+    m_subframe = LocalFrame::create(m_frameLoaderClient.get(), document().frame()->host(), &iframe);
+    m_subframe->setView(FrameView::create(m_subframe.get(), IntSize(500, 500)));
+    m_subframe->init();
+    static_cast<SingleChildFrameLoaderClient*>(document().frame()->client())->setChild(m_subframe.get());
+    document().frame()->host()->incrementSubframeCount();
+    Document& frameDocument = *iframe.contentDocument();
+
+    frameDocument.setBaseURLOverride(KURL(ParsedURLString, "http://test.com"));
+    frameDocument.body()->setInnerHTML(htmlContentOfIframe, ASSERT_NO_EXCEPTION);
+    return frameDocument;
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutTestHelper.h b/third_party/WebKit/Source/core/layout/LayoutTestHelper.h
index caaeddb2..81eb4dce 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTestHelper.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTestHelper.h
@@ -38,6 +38,9 @@
         document().view()->updateAllLifecyclePhases();
     }
 
+    // Returns the Document for the iframe.
+    Document& setupChildIframe(const AtomicString& iframeElementId, const String& htmlContentOfIframe);
+
     // Both enables compositing and runs the document lifecycle.
     void enableCompositing()
     {
@@ -46,6 +49,8 @@
     }
 
 private:
+    RefPtrWillBePersistent<LocalFrame> m_subframe;
+    OwnPtrWillBePersistent<FrameLoaderClient> m_frameLoaderClient;
     OwnPtr<DummyPageHolder> m_pageHolder;
 };
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutText.cpp b/third_party/WebKit/Source/core/layout/LayoutText.cpp
index 929cf22..da345a8 100644
--- a/third_party/WebKit/Source/core/layout/LayoutText.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutText.cpp
@@ -1870,7 +1870,7 @@
 
 PassRefPtr<AbstractInlineTextBox> LayoutText::firstAbstractInlineTextBox()
 {
-    return AbstractInlineTextBox::getOrCreate(this, m_firstTextBox);
+    return AbstractInlineTextBox::getOrCreate(LineLayoutText(this), m_firstTextBox);
 }
 
 void LayoutText::invalidateDisplayItemClients(const LayoutBoxModelObject& paintInvalidationContainer, PaintInvalidationReason invalidationReason, const LayoutRect* paintInvalidationRect) const
diff --git a/third_party/WebKit/Source/core/layout/LayoutTextControl.cpp b/third_party/WebKit/Source/core/layout/LayoutTextControl.cpp
index c3e6049dc..911ff68c8e 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTextControl.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTextControl.cpp
@@ -111,7 +111,7 @@
 int LayoutTextControl::scrollbarThickness() const
 {
     // FIXME: We should get the size of the scrollbar from the LayoutTheme instead.
-    return ScrollbarTheme::theme()->scrollbarThickness();
+    return ScrollbarTheme::theme().scrollbarThickness();
 }
 
 void LayoutTextControl::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
diff --git a/third_party/WebKit/Source/core/layout/LayoutThemeDefault.cpp b/third_party/WebKit/Source/core/layout/LayoutThemeDefault.cpp
index 449cc7e0..66d47ff 100644
--- a/third_party/WebKit/Source/core/layout/LayoutThemeDefault.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutThemeDefault.cpp
@@ -390,7 +390,7 @@
 
 int LayoutThemeDefault::menuListArrowPadding() const
 {
-    return ScrollbarTheme::theme()->scrollbarThickness();
+    return ScrollbarTheme::theme().scrollbarThickness();
 }
 
 int LayoutThemeDefault::menuListInternalPadding(const ComputedStyle& style, int paddingType) const
diff --git a/third_party/WebKit/Source/core/layout/LayoutView.cpp b/third_party/WebKit/Source/core/layout/LayoutView.cpp
index 7fbda64d..0dbbb38 100644
--- a/third_party/WebKit/Source/core/layout/LayoutView.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutView.cpp
@@ -38,6 +38,7 @@
 #include "core/layout/LayoutPart.h"
 #include "core/layout/LayoutQuote.h"
 #include "core/layout/LayoutScrollbarPart.h"
+#include "core/layout/ViewFragmentationContext.h"
 #include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/page/Page.h"
 #include "core/paint/PaintLayer.h"
@@ -238,8 +239,15 @@
     if (!document().paginated())
         setPageLogicalHeight(0);
 
-    if (shouldUsePrintingLayout())
+    if (shouldUsePrintingLayout()) {
         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = logicalWidth();
+        // TODO(mstensho): Get rid of m_pageLogicalHeight zero check. Currently, pageProperty() in
+        // PrintContext starts printing with zero height, so we have to cope for now.
+        if (!m_fragmentationContext && m_pageLogicalHeight)
+            m_fragmentationContext = adoptPtr(new ViewFragmentationContext(*this));
+    } else if (m_fragmentationContext) {
+        m_fragmentationContext.clear();
+    }
 
     SubtreeLayoutScope layoutScope(*this);
 
@@ -306,7 +314,7 @@
     // In normal compositing mode, LayoutView doesn't actually apply clipping
     // on its descendants. Instead their visual overflow is propagated to
     // compositor()->m_rootContentLayer for accelerated scrolling.
-    return LayoutRect(unscaledDocumentRect());
+    return LayoutRect(documentRect());
 }
 
 void LayoutView::mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const
@@ -389,9 +397,8 @@
     if (mode & TraverseDocumentBoundaries) {
         if (LayoutPart* parentDocLayoutObject = frame()->ownerLayoutObject()) {
             parentDocLayoutObject->mapAbsoluteToLocalPoint(mode, transformState);
-
-            transformState.move(-parentDocLayoutObject->contentBoxOffset());
-            transformState.move(frame()->view()->scrollOffset());
+            transformState.move(parentDocLayoutObject->contentBoxOffset());
+            transformState.move(-frame()->view()->scrollOffset());
         }
     }
 }
@@ -847,7 +854,7 @@
     return rect;
 }
 
-IntRect LayoutView::unscaledDocumentRect() const
+IntRect LayoutView::documentRect() const
 {
     LayoutRect overflowRect(layoutOverflowRect());
     flipForWritingMode(overflowRect);
@@ -861,15 +868,7 @@
 
 LayoutRect LayoutView::backgroundRect(LayoutBox* backgroundLayoutObject) const
 {
-    return LayoutRect(unscaledDocumentRect());
-}
-
-IntRect LayoutView::documentRect() const
-{
-    FloatRect overflowRect(unscaledDocumentRect());
-    if (hasTransformRelatedProperty())
-        overflowRect = layer()->currentTransform().mapRect(overflowRect);
-    return IntRect(overflowRect);
+    return LayoutRect(documentRect());
 }
 
 IntSize LayoutView::layoutSize(IncludeScrollbarsInRect scrollbarInclusion) const
diff --git a/third_party/WebKit/Source/core/layout/LayoutView.h b/third_party/WebKit/Source/core/layout/LayoutView.h
index e13a18c..a7ede78 100644
--- a/third_party/WebKit/Source/core/layout/LayoutView.h
+++ b/third_party/WebKit/Source/core/layout/LayoutView.h
@@ -40,6 +40,7 @@
 class PaintLayerCompositor;
 class LayoutQuote;
 class LayoutMedia;
+class ViewFragmentationContext;
 
 // LayoutView is the root of the layout tree and the Document's LayoutObject.
 //
@@ -142,6 +143,8 @@
 
     void updateHitTestResult(HitTestResult&, const LayoutPoint&) override;
 
+    ViewFragmentationContext* fragmentationContext() const { return m_fragmentationContext.get(); }
+
     LayoutUnit pageLogicalHeight() const { return m_pageLogicalHeight; }
     void setPageLogicalHeight(LayoutUnit height)
     {
@@ -158,9 +161,6 @@
     PaintLayerCompositor* compositor();
     bool usesCompositing() const;
 
-    // TODO(trchen): All pinch-zoom implementation should now use compositor raster scale based zooming,
-    // instead of LayoutView transform. Check whether we can now unify unscaledDocumentRect and documentRect.
-    IntRect unscaledDocumentRect() const;
     LayoutRect backgroundRect(LayoutBox* backgroundLayoutObject) const;
 
     IntRect documentRect() const;
@@ -262,6 +262,7 @@
     // See the class comment for more details.
     LayoutState* m_layoutState;
 
+    OwnPtr<ViewFragmentationContext> m_fragmentationContext;
     OwnPtr<PaintLayerCompositor> m_compositor;
     RefPtr<IntervalArena> m_intervalArena;
 
diff --git a/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.cpp b/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.cpp
index 4cd074c7..82583f3 100644
--- a/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.cpp
+++ b/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.cpp
@@ -7,6 +7,7 @@
 #include "core/layout/MultiColumnFragmentainerGroup.h"
 
 #include "core/layout/ColumnBalancer.h"
+#include "core/layout/FragmentationContext.h"
 #include "core/layout/LayoutMultiColumnSet.h"
 
 namespace blink {
@@ -34,9 +35,9 @@
     return offset;
 }
 
-LayoutUnit MultiColumnFragmentainerGroup::blockOffsetInEnclosingFlowThread() const
+LayoutUnit MultiColumnFragmentainerGroup::blockOffsetInEnclosingFragmentationContext() const
 {
-    return logicalTop() + m_columnSet.logicalTop() + m_columnSet.multiColumnFlowThread()->blockOffsetInEnclosingFlowThread();
+    return logicalTop() + m_columnSet.logicalTop() + m_columnSet.multiColumnFlowThread()->blockOffsetInEnclosingFragmentationContext();
 }
 
 void MultiColumnFragmentainerGroup::resetColumnHeight()
@@ -45,8 +46,8 @@
 
     LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread();
     if (m_columnSet.heightIsAuto()) {
-        LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosingFlowThread();
-        if (enclosingFlowThread && enclosingFlowThread->isPageLogicalHeightKnown()) {
+        FragmentationContext* enclosingFragmentationContext = flowThread->enclosingFragmentationContext();
+        if (enclosingFragmentationContext && enclosingFragmentationContext->isFragmentainerLogicalHeightKnown()) {
             // Even if height is auto, we set an initial height, in order to tell how much content
             // this MultiColumnFragmentainerGroup can hold, and when we need to append a new one.
             m_columnHeight = m_maxColumnHeight;
@@ -114,11 +115,11 @@
         // Translation that would map points in the coordinate space of the outermost flow thread to
         // visual points in the first column in the first fragmentainer group (row) in our multicol
         // container.
-        LayoutSize enclosingTranslationOrigin = enclosingFlowThread->flowThreadTranslationAtOffset(flowThread->blockOffsetInEnclosingFlowThread());
+        LayoutSize enclosingTranslationOrigin = enclosingFlowThread->flowThreadTranslationAtOffset(flowThread->blockOffsetInEnclosingFragmentationContext());
 
         // Translation that would map points in the coordinate space of the outermost flow thread to
         // visual points in the first column in this fragmentainer group.
-        enclosingTranslation = enclosingFlowThread->flowThreadTranslationAtOffset(blockOffsetInEnclosingFlowThread());
+        enclosingTranslation = enclosingFlowThread->flowThreadTranslationAtOffset(blockOffsetInEnclosingFragmentationContext());
 
         // What we ultimately return from this method is a translation that maps points in the
         // coordinate space of our flow thread to a visual point in a certain column in this
@@ -323,11 +324,11 @@
             maxColumnHeight = logicalMaxHeight;
     }
     LayoutUnit maxHeight = heightAdjustedForRowOffset(maxColumnHeight);
-    if (LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosingFlowThread()) {
-        if (enclosingFlowThread->isPageLogicalHeightKnown()) {
+    if (FragmentationContext* enclosingFragmentationContext = flowThread->enclosingFragmentationContext()) {
+        if (enclosingFragmentationContext->isFragmentainerLogicalHeightKnown()) {
             // We're nested inside another fragmentation context whose fragmentainer heights are
             // known. This constrains the max height.
-            LayoutUnit remainingOuterLogicalHeight = enclosingFlowThread->pageRemainingLogicalHeightForOffset(blockOffsetInEnclosingFlowThread(), LayoutBlock::AssociateWithLatterPage);
+            LayoutUnit remainingOuterLogicalHeight = enclosingFragmentationContext->remainingLogicalHeightAt(blockOffsetInEnclosingFragmentationContext());
             ASSERT(remainingOuterLogicalHeight > 0);
             if (maxHeight > remainingOuterLogicalHeight)
                 maxHeight = remainingOuterLogicalHeight;
diff --git a/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.h b/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.h
index c68d35c8..e1ca9abfb 100644
--- a/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.h
+++ b/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.h
@@ -44,9 +44,9 @@
 
     LayoutSize offsetFromColumnSet() const;
 
-    // Return the block offset from the enclosing flow thread, if nested. In the coordinate space
-    // of the enclosing flow thread.
-    LayoutUnit blockOffsetInEnclosingFlowThread() const;
+    // Return the block offset from the enclosing fragmentation context, if nested. In the
+    // coordinate space of the enclosing fragmentation context.
+    LayoutUnit blockOffsetInEnclosingFragmentationContext() const;
 
     // The top of our flow thread portion
     LayoutUnit logicalTopInFlowThread() const { return m_logicalTopInFlowThread; }
diff --git a/third_party/WebKit/Source/core/layout/TracedLayoutObject.cpp b/third_party/WebKit/Source/core/layout/TracedLayoutObject.cpp
index ee60df3d..34dc0cf2 100644
--- a/third_party/WebKit/Source/core/layout/TracedLayoutObject.cpp
+++ b/third_party/WebKit/Source/core/layout/TracedLayoutObject.cpp
@@ -27,7 +27,7 @@
 }
 
 TracedLayoutObject::TracedLayoutObject(const LayoutObject& object, bool traceGeometry)
-    : m_address((unsigned long) &object)
+    : m_address(reinterpret_cast<uintptr_t>(&object))
     , m_isAnonymous(object.isAnonymous())
     , m_isPositioned(object.isOutOfFlowPositioned())
     , m_isRelPositioned(object.isRelPositioned())
diff --git a/third_party/WebKit/Source/core/layout/TracedLayoutObject.h b/third_party/WebKit/Source/core/layout/TracedLayoutObject.h
index 079dc72..0861f9c 100644
--- a/third_party/WebKit/Source/core/layout/TracedLayoutObject.h
+++ b/third_party/WebKit/Source/core/layout/TracedLayoutObject.h
@@ -27,7 +27,7 @@
 
     PassRefPtr<JSONObject> toJSON() const;
 
-    unsigned long m_address;
+    uintptr_t m_address;
     bool m_isAnonymous;
     bool m_isPositioned;
     bool m_isRelPositioned;
diff --git a/third_party/WebKit/Source/core/layout/ViewFragmentationContext.cpp b/third_party/WebKit/Source/core/layout/ViewFragmentationContext.cpp
new file mode 100644
index 0000000..6f6d2df
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/ViewFragmentationContext.cpp
@@ -0,0 +1,31 @@
+// 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/layout/ViewFragmentationContext.h"
+
+#include "core/layout/LayoutView.h"
+
+namespace blink {
+
+bool ViewFragmentationContext::isFragmentainerLogicalHeightKnown()
+{
+    ASSERT(m_view.pageLogicalHeight());
+    return true;
+}
+
+LayoutUnit ViewFragmentationContext::fragmentainerLogicalHeightAt(LayoutUnit)
+{
+    ASSERT(m_view.pageLogicalHeight());
+    return m_view.pageLogicalHeight();
+}
+
+LayoutUnit ViewFragmentationContext::remainingLogicalHeightAt(LayoutUnit blockOffset)
+{
+    LayoutUnit pageLogicalHeight = m_view.pageLogicalHeight();
+    return pageLogicalHeight - intMod(blockOffset, pageLogicalHeight);
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ViewFragmentationContext.h b/third_party/WebKit/Source/core/layout/ViewFragmentationContext.h
new file mode 100644
index 0000000..75cfb4f
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/ViewFragmentationContext.h
@@ -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.
+
+#ifndef ViewFragmentationContext_h
+#define ViewFragmentationContext_h
+
+#include "core/layout/FragmentationContext.h"
+
+namespace blink {
+
+class LayoutView;
+
+class ViewFragmentationContext final : public FragmentationContext {
+public:
+    ViewFragmentationContext(LayoutView& view) : m_view(view) { }
+    bool isFragmentainerLogicalHeightKnown() final;
+    LayoutUnit fragmentainerLogicalHeightAt(LayoutUnit blockOffset) final;
+    LayoutUnit remainingLogicalHeightAt(LayoutUnit blockOffset) final;
+
+private:
+    LayoutView& m_view;
+};
+
+} // namespace blink
+
+#endif // ViewFragmentationContext_h
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutInline.h b/third_party/WebKit/Source/core/layout/api/LineLayoutInline.h
index a0f28d4..7da9c12b 100644
--- a/third_party/WebKit/Source/core/layout/api/LineLayoutInline.h
+++ b/third_party/WebKit/Source/core/layout/api/LineLayoutInline.h
@@ -87,6 +87,11 @@
         return toInline()->firstLineBoxIncludingCulling();
     }
 
+    LineBoxList* lineBoxes()
+    {
+        return toInline()->lineBoxes();
+    }
+
 protected:
     LayoutInline* toInline()
     {
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutItem.h b/third_party/WebKit/Source/core/layout/api/LineLayoutItem.h
index 5898a3e..73d8d8283 100644
--- a/third_party/WebKit/Source/core/layout/api/LineLayoutItem.h
+++ b/third_party/WebKit/Source/core/layout/api/LineLayoutItem.h
@@ -214,6 +214,11 @@
         return m_layoutObject->isInlineBlockOrInlineTable();
     }
 
+    bool isInlineElementContinuation() const
+    {
+        return m_layoutObject->isInlineElementContinuation();
+    }
+
     bool isLayoutBlock() const
     {
         return m_layoutObject->isLayoutBlock();
@@ -334,6 +339,11 @@
         return LineLayoutItem(m_layoutObject->previousInPreOrder(stayWithin));
     }
 
+    FloatQuad localToAbsoluteQuad(const FloatQuad& quad, MapCoordinatesFlags mode = 0, bool* wasFixed = nullptr) const
+    {
+        return m_layoutObject->localToAbsoluteQuad(quad, mode, wasFixed);
+    }
+
 #ifndef NDEBUG
 
     const char* name() const
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
index 99082f7..0aa79d80 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
@@ -1511,12 +1511,13 @@
         }, ApplyToChildContainingLayers);
     }
 
-    // Regardless, mark the scrolling contents layer and scrolling block
+    // Regardless, mark the graphics layer, scrolling layer and scrolling block
     // selection layer (if they exist) as not flattening. Having them flatten
     // causes unclipped render surfaces which cause bugs.
     // http://crbug.com/521768
     if (hasScrollingLayer()) {
-        m_scrollingContentsLayer->setShouldFlattenTransform(false);
+        m_graphicsLayer->setShouldFlattenTransform(false);
+        m_scrollingLayer->setShouldFlattenTransform(false);
         if (m_scrollingBlockSelectionLayer)
             m_scrollingBlockSelectionLayer->setShouldFlattenTransform(false);
     }
@@ -2132,19 +2133,19 @@
         layer->invalidateDisplayItemClient(displayItemClient, invalidationReason, visualRect ? &visualRectOnLayer : nullptr);
     }
 
-    const DisplayItemClientWrapper& displayItemClient;
+    const DisplayItemClient& displayItemClient;
     PaintInvalidationReason invalidationReason;
     const LayoutRect* visualRect;
     LayoutSize subpixelAccumulation;
 };
 
-void CompositedLayerMapping::invalidateDisplayItemClient(const DisplayItemClientWrapper& displayItemClient, PaintInvalidationReason paintInvalidationReason, const LayoutRect* visualRect)
+void CompositedLayerMapping::invalidateDisplayItemClient(const DisplayItemClient& displayItemClient, PaintInvalidationReason paintInvalidationReason, const LayoutRect* visualRect)
 {
     InvalidateDisplayItemClientFunctor functor = { displayItemClient, paintInvalidationReason, visualRect, m_owningLayer.subpixelAccumulation() };
     ApplyToGraphicsLayers(this, functor, ApplyToContentLayers);
 }
 
-void CompositedLayerMapping::invalidateDisplayItemClientOnScrollingContentsLayer(const DisplayItemClientWrapper& displayItemClient, PaintInvalidationReason paintInvalidationReason, const LayoutRect* visualRect)
+void CompositedLayerMapping::invalidateDisplayItemClientOnScrollingContentsLayer(const DisplayItemClient& displayItemClient, PaintInvalidationReason paintInvalidationReason, const LayoutRect* visualRect)
 {
     InvalidateDisplayItemClientFunctor functor = { displayItemClient, paintInvalidationReason, visualRect, m_owningLayer.subpixelAccumulation() };
     ApplyToGraphicsLayers(this, functor, ApplyToScrollingContentsLayer);
@@ -2187,7 +2188,7 @@
     return parentClipRect;
 }
 
-void CompositedLayerMapping::doPaintTask(const GraphicsLayerPaintInfo& paintInfo, const PaintLayerFlags& paintLayerFlags, GraphicsContext* context,
+void CompositedLayerMapping::doPaintTask(const GraphicsLayerPaintInfo& paintInfo, const GraphicsLayer& graphicsLayer, const PaintLayerFlags& paintLayerFlags, GraphicsContext* context,
     const IntRect& clip /* In the coords of rootLayer */) const
 {
     FontCachePurgePreventer fontCachePurgePreventer;
@@ -2195,7 +2196,7 @@
     IntSize offset = paintInfo.offsetFromLayoutObject;
     AffineTransform translation;
     translation.translate(-offset.width(), -offset.height());
-    TransformRecorder transformRecorder(*context, *this, translation);
+    TransformRecorder transformRecorder(*context, graphicsLayer, translation);
 
     // The dirtyRect is in the coords of the painting root.
     IntRect dirtyRect(clip);
@@ -2232,10 +2233,10 @@
         // FIXME: Is it correct to clip to dirtyRect in slimming paint mode?
         // FIXME: Combine similar code here and LayerClipRecorder.
         dirtyRect.intersect(paintInfo.localClipRectForSquashedLayer);
-        context->paintController().createAndAppend<ClipDisplayItem>(*this, DisplayItem::ClipLayerOverflowControls, dirtyRect);
+        context->paintController().createAndAppend<ClipDisplayItem>(graphicsLayer, DisplayItem::ClipLayerOverflowControls, dirtyRect);
 
         PaintLayerPainter(*paintInfo.paintLayer).paintLayer(context, paintingInfo, paintLayerFlags);
-        context->paintController().endItem<EndClipDisplayItem>(*this, DisplayItem::clipTypeToEndClipType(DisplayItem::ClipLayerOverflowControls));
+        context->paintController().endItem<EndClipDisplayItem>(graphicsLayer, DisplayItem::clipTypeToEndClipType(DisplayItem::ClipLayerOverflowControls));
     }
 }
 
@@ -2248,7 +2249,7 @@
     TransformRecorder transformRecorder(context, *scrollbar, AffineTransform::translation(-scrollbarRect.x(), -scrollbarRect.y()));
     IntRect transformedClip = clip;
     transformedClip.moveBy(scrollbarRect.location());
-    scrollbar->paint(&context, CullRect(transformedClip));
+    scrollbar->paint(context, CullRect(transformedClip));
 }
 
 // The following should be kept in sync with the code computing potential_new_recorded_viewport in
@@ -2402,10 +2403,10 @@
         paintInfo.offsetFromLayoutObject = graphicsLayer->offsetFromLayoutObject();
 
         // We have to use the same root as for hit testing, because both methods can compute and cache clipRects.
-        doPaintTask(paintInfo, paintLayerFlags, &context, interestRect);
+        doPaintTask(paintInfo, *graphicsLayer, paintLayerFlags, &context, interestRect);
     } else if (graphicsLayer == m_squashingLayer.get()) {
         for (size_t i = 0; i < m_squashedLayers.size(); ++i)
-            doPaintTask(m_squashedLayers[i], paintLayerFlags, &context, interestRect);
+            doPaintTask(m_squashedLayers[i], *graphicsLayer, paintLayerFlags, &context, interestRect);
     } else if (graphicsLayer == layerForHorizontalScrollbar()) {
         paintScrollbar(m_owningLayer.scrollableArea()->horizontalScrollbar(), context, interestRect);
     } else if (graphicsLayer == layerForVerticalScrollbar()) {
@@ -2413,8 +2414,8 @@
     } else if (graphicsLayer == layerForScrollCorner()) {
         IntPoint scrollCornerAndResizerLocation = m_owningLayer.scrollableArea()->scrollCornerAndResizerRect().location();
         CullRect cullRect(enclosingIntRect(interestRect));
-        ScrollableAreaPainter(*m_owningLayer.scrollableArea()).paintScrollCorner(&context, -scrollCornerAndResizerLocation, cullRect);
-        ScrollableAreaPainter(*m_owningLayer.scrollableArea()).paintResizer(&context, -scrollCornerAndResizerLocation, cullRect);
+        ScrollableAreaPainter(*m_owningLayer.scrollableArea()).paintScrollCorner(context, -scrollCornerAndResizerLocation, cullRect);
+        ScrollableAreaPainter(*m_owningLayer.scrollableArea()).paintResizer(context, -scrollCornerAndResizerLocation, cullRect);
     }
     InspectorInstrumentation::didPaint(m_owningLayer.layoutObject(), graphicsLayer, &context, LayoutRect(interestRect));
 #if ENABLE(ASSERT)
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.h b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.h
index 30f7229d..671a53333 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.h
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.h
@@ -127,8 +127,8 @@
     // If |visualRect| is not nullptr, it contains all pixels that might be painted by the display item client,
     // in coordinate space of the layer's layout object.
     // |visualRect| can be nullptr if we know it's unchanged and PaintController has cached the previous value.
-    void invalidateDisplayItemClient(const DisplayItemClientWrapper&, PaintInvalidationReason, const LayoutRect* visualRect);
-    void invalidateDisplayItemClientOnScrollingContentsLayer(const DisplayItemClientWrapper&, PaintInvalidationReason, const LayoutRect* visualRect);
+    void invalidateDisplayItemClient(const DisplayItemClient&, PaintInvalidationReason, const LayoutRect* visualRect);
+    void invalidateDisplayItemClientOnScrollingContentsLayer(const DisplayItemClient&, PaintInvalidationReason, const LayoutRect* visualRect);
 
     // Notification from the layoutObject that its content changed.
     void contentChanged(ContentChangeType);
@@ -213,9 +213,6 @@
 
     void updateScrollingBlockSelection();
 
-    DisplayItemClient displayItemClient() const { return toDisplayItemClient(this); }
-    String debugName() const { return "CompositedLayerMapping for " + owningLayer().debugName(); }
-
 private:
     IntRect recomputeInterestRect(const GraphicsLayer*) const;
     static bool interestRectChangedEnoughToRepaint(const IntRect& previousInterestRect, const IntRect& newInterestRect, const IntSize& layerSize);
@@ -302,7 +299,7 @@
 
     static bool hasVisibleNonCompositingDescendant(PaintLayer* parent);
 
-    void doPaintTask(const GraphicsLayerPaintInfo&, const PaintLayerFlags&, GraphicsContext*, const IntRect& clip) const;
+    void doPaintTask(const GraphicsLayerPaintInfo&, const GraphicsLayer&, const PaintLayerFlags&, GraphicsContext*, const IntRect& clip) const;
 
     // Computes the background clip rect for the given squashed layer, up to any containing layer that is squashed into the
     // same squashing layer and contains this squashed layer's clipping ancestor.
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp
index 283be2ff2..4fd748b 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp
@@ -6,11 +6,9 @@
 #include "core/layout/compositing/CompositedLayerMapping.h"
 
 #include "core/frame/FrameView.h"
-#include "core/html/HTMLIFrameElement.h"
 #include "core/layout/LayoutBoxModelObject.h"
 #include "core/layout/LayoutTestHelper.h"
 #include "core/layout/LayoutView.h"
-#include "core/loader/EmptyClients.h"
 #include "core/paint/PaintLayer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -34,6 +32,11 @@
         return compositedLayerMapping->computeInterestRect(graphicsLayer, previousInterestRect);
     }
 
+    bool shouldFlattenTransform(const GraphicsLayer& layer) const
+    {
+        return layer.shouldFlattenTransform();
+    }
+
     bool interestRectChangedEnoughToRepaint(const IntRect& previousInterestRect, const IntRect& newInterestRect, const IntSize& layerSize)
     {
         return CompositedLayerMapping::interestRectChangedEnoughToRepaint(previousInterestRect, newInterestRect, layerSize);
@@ -58,6 +61,8 @@
     {
         GraphicsLayer::setDrawDebugRedFillForTesting(true);
         RuntimeEnabledFeatures::setSlimmingPaintSynchronizedPaintingEnabled(m_originalSlimmingPaintSynchronizedPaintingEnabled);
+
+        RenderingTest::TearDown();
     }
 
     bool m_originalSlimmingPaintSynchronizedPaintingEnabled;
@@ -65,10 +70,11 @@
 
 #define EXPECT_RECT_EQ(expected, actual) \
     do { \
-        EXPECT_EQ(expected.x(), actual.x()); \
-        EXPECT_EQ(expected.y(), actual.y()); \
-        EXPECT_EQ(expected.width(), actual.width()); \
-        EXPECT_EQ(expected.height(), actual.height()); \
+        const IntRect& actualRect = actual; \
+        EXPECT_EQ(expected.x(), actualRect.x()); \
+        EXPECT_EQ(expected.y(), actualRect.y()); \
+        EXPECT_EQ(expected.width(), actualRect.width()); \
+        EXPECT_EQ(expected.height(), actualRect.height()); \
     } while (false)
 
 TEST_F(CompositedLayerMappingTest, SimpleInterestRect)
@@ -264,6 +270,25 @@
     EXPECT_FALSE(graphicsLayer->contentsClippingMaskLayer());
 }
 
+TEST_F(CompositedLayerMappingTest, ScrollContentsFlattenForScroller)
+{
+    setBodyInnerHTML(
+        "<style>div::-webkit-scrollbar{ width: 5px; }</style>"
+        "<div id='scroller' style='width: 100px; height: 100px; overflow: scroll; will-change: transform'>"
+        "<div style='width: 1000px; height: 1000px;'>Foo</div>Foo</div>");
+
+    document().view()->updateAllLifecyclePhases();
+    Element* element = document().getElementById("scroller");
+    PaintLayer* paintLayer = toLayoutBoxModelObject(element->layoutObject())->layer();
+    CompositedLayerMapping* compositedLayerMapping = paintLayer->compositedLayerMapping();
+
+    ASSERT_TRUE(compositedLayerMapping);
+
+    EXPECT_FALSE(shouldFlattenTransform(*compositedLayerMapping->mainGraphicsLayer()));
+    EXPECT_FALSE(shouldFlattenTransform(*compositedLayerMapping->scrollingLayer()));
+    EXPECT_TRUE(shouldFlattenTransform(*compositedLayerMapping->scrollingContentsLayer()));
+}
+
 TEST_F(CompositedLayerMappingTest, InterestRectChangedEnoughToRepaintEmpty)
 {
     IntSize layerSize(1000, 1000);
@@ -488,7 +513,7 @@
     EXPECT_RECT_EQ(IntRect(5600, 0, 4400, 1000), groupedMapping->computeInterestRect(groupedMapping->squashingLayer(), IntRect()));
 }
 
-TEST_F(CompositedLayerMappingTest, InterestRectOfScrolledIframe)
+TEST_F(CompositedLayerMappingTest, InterestRectOfIframeInScrolledDiv)
 {
     document().setBaseURLOverride(KURL(ParsedURLString, "http://test.com"));
     setBodyInnerHTML(
@@ -497,18 +522,7 @@
         "<iframe id=frame src='http://test.com' width='500' height='500' frameBorder='0'>"
         "</iframe>");
 
-    HTMLIFrameElement& iframe = *toHTMLIFrameElement(document().getElementById("frame"));
-    OwnPtrWillBeRawPtr<FrameLoaderClient> frameLoaderClient = FrameLoaderClientWithParent::create(document().frame());
-    RefPtrWillBePersistent<LocalFrame> subframe = LocalFrame::create(frameLoaderClient.get(), document().frame()->host(), &iframe);
-    subframe->setView(FrameView::create(subframe.get(), IntSize(500, 500)));
-    subframe->init();
-    static_cast<SingleChildFrameLoaderClient*>(document().frame()->client())->setChild(subframe.get());
-    document().frame()->host()->incrementSubframeCount();
-    Document& frameDocument = *iframe.contentDocument();
-
-    frameDocument.setBaseURLOverride(KURL(ParsedURLString, "http://test.com"));
-    frameDocument.body()->setInnerHTML("<style>body { margin: 0; } #target { width: 200px; height: 200px; will-change: transform}</style><div id=target></div>",
-        ASSERT_NO_EXCEPTION);
+    Document& frameDocument = setupChildIframe("frame", "<style>body { margin: 0; } #target { width: 200px; height: 200px; will-change: transform}</style><div id=target></div>");
 
     // Scroll 8000 pixels down to move the iframe into view.
     document().view()->setScrollPosition(DoublePoint(0.0, 8000.0), ProgrammaticScroll);
@@ -518,10 +532,51 @@
     ASSERT_TRUE(target);
 
     EXPECT_RECT_EQ(IntRect(0, 0, 200, 200), recomputeInterestRect(target->layoutObject()->enclosingLayer()->graphicsLayerBacking()));
+}
 
-    subframe->detach(FrameDetachType::Remove);
-    static_cast<SingleChildFrameLoaderClient*>(document().frame()->client())->setChild(nullptr);
-    document().frame()->host()->decrementSubframeCount();
+TEST_F(CompositedLayerMappingTest, InterestRectOfScrolledIframe)
+{
+    document().setBaseURLOverride(KURL(ParsedURLString, "http://test.com"));
+    document().frame()->settings()->setPreferCompositingToLCDTextEnabled(true);
+    setBodyInnerHTML(
+        "<style>body { margin: 0; }</style>"
+        "<iframe id=frame src='http://test.com' width='500' height='500' frameBorder='0'>"
+        "</iframe>");
+
+    Document& frameDocument = setupChildIframe("frame", "<style>body { margin: 0; } #target { width: 200px; height: 8000px;}</style><div id=target></div>");
+
+    document().view()->updateAllLifecyclePhases();
+
+    // Scroll 7500 pixels down to bring the scrollable area to the bottom.
+    frameDocument.view()->setScrollPosition(DoublePoint(0.0, 7500.0), ProgrammaticScroll);
+    document().view()->updateAllLifecyclePhases();
+
+    ASSERT_TRUE(frameDocument.view()->layoutView()->hasLayer());
+    // The width is 485 pixels due to the size of the scrollbar.
+    EXPECT_RECT_EQ(IntRect(0, 3500, 485, 4500), recomputeInterestRect(frameDocument.view()->layoutView()->enclosingLayer()->graphicsLayerBacking()));
+}
+
+TEST_F(CompositedLayerMappingTest, InterestRectOfIframeWithContentBoxOffset)
+{
+    document().setBaseURLOverride(KURL(ParsedURLString, "http://test.com"));
+    document().frame()->settings()->setPreferCompositingToLCDTextEnabled(true);
+    // Set a 10px border in order to have a contentBoxOffset for the iframe element.
+    setBodyInnerHTML(
+        "<style>body { margin: 0; } #frame { border: 10px solid black; }</style>"
+        "<iframe id=frame src='http://test.com' width='500' height='500' frameBorder='0'>"
+        "</iframe>");
+
+    Document& frameDocument = setupChildIframe("frame", "<style>body { margin: 0; } #target { width: 200px; height: 8000px;}</style> <div id=target></div>");
+
+    document().view()->updateAllLifecyclePhases();
+
+    // Scroll 3000 pixels down to bring the scrollable area to somewhere in the middle.
+    frameDocument.view()->setScrollPosition(DoublePoint(0.0, 3000.0), ProgrammaticScroll);
+    document().view()->updateAllLifecyclePhases();
+
+    ASSERT_TRUE(frameDocument.view()->layoutView()->hasLayer());
+    // The width is 485 pixels due to the size of the scrollbar.
+    EXPECT_RECT_EQ(IntRect(0, 0, 485, 7500), recomputeInterestRect(frameDocument.view()->layoutView()->enclosingLayer()->graphicsLayerBacking()));
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp b/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp
index b3bb5511..969d1ef6 100644
--- a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp
@@ -333,11 +333,11 @@
 
 static void forceRecomputePaintInvalidationRectsIncludingNonCompositingDescendants(LayoutObject* layoutObject)
 {
-    // We clear the previous paint invalidation rect as it's wrong (paint invaliation container
+    // We clear the previous paint invalidation rect as it's wrong (paint invalidation container
     // changed, ...). Forcing a full invalidation will make us recompute it. Also we are not
     // changing the previous position from our paint invalidation container, which is fine as
     // we want a full paint invalidation anyway.
-    layoutObject->setPreviousPaintInvalidationRect(LayoutRect());
+    layoutObject->clearPreviousPaintInvalidationRects();
     layoutObject->setShouldDoFullPaintInvalidation();
 
     for (LayoutObject* child = layoutObject->slowFirstChild(); child; child = child->nextSibling()) {
@@ -804,7 +804,7 @@
     translation.translate(-paintOffset.x(), -paintOffset.y());
     TransformRecorder transformRecorder(context, *scrollbar, translation);
 
-    scrollbar->paint(&context, CullRect(transformedClip));
+    scrollbar->paint(context, CullRect(transformedClip));
 }
 
 IntRect PaintLayerCompositor::computeInterestRect(const GraphicsLayer* graphicsLayer, const IntRect&) const
@@ -819,7 +819,7 @@
     else if (graphicsLayer == layerForVerticalScrollbar())
         paintScrollbar(m_layoutView.frameView()->verticalScrollbar(), context, interestRect);
     else if (graphicsLayer == layerForScrollCorner())
-        FramePainter(*m_layoutView.frameView()).paintScrollCorner(&context, interestRect);
+        FramePainter(*m_layoutView.frameView()).paintScrollCorner(context, interestRect);
 }
 
 bool PaintLayerCompositor::supportsFixedRootBackgroundCompositing() const
@@ -1044,8 +1044,7 @@
         m_layerForHorizontalScrollbar = nullptr;
         if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
             scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_layoutView.frameView(), HorizontalScrollbar);
-        if (Scrollbar* horizontalScrollbar = m_layoutView.frameView()->horizontalScrollbar())
-            m_layoutView.frameView()->setScrollbarNeedsPaintInvalidation(horizontalScrollbar);
+        m_layoutView.frameView()->setScrollbarNeedsPaintInvalidation(HorizontalScrollbar);
     }
 
     if (m_layerForVerticalScrollbar) {
@@ -1053,8 +1052,7 @@
         m_layerForVerticalScrollbar = nullptr;
         if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
             scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_layoutView.frameView(), VerticalScrollbar);
-        if (Scrollbar* verticalScrollbar = m_layoutView.frameView()->verticalScrollbar())
-            m_layoutView.frameView()->setScrollbarNeedsPaintInvalidation(verticalScrollbar);
+        m_layoutView.frameView()->setScrollbarNeedsPaintInvalidation(VerticalScrollbar);
     }
 
     if (m_layerForScrollCorner) {
@@ -1076,6 +1074,11 @@
     if (!m_rootContentLayer)
         return;
 
+    // In Slimming Paint v2, PaintArtifactCompositor is responsible for the root
+    // layer.
+    if (RuntimeEnabledFeatures::slimmingPaintV2Enabled())
+        return;
+
     switch (attachment) {
     case RootLayerUnattached:
         ASSERT_NOT_REACHED();
diff --git a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.h b/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.h
index 333db37..7520b695 100644
--- a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.h
+++ b/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.h
@@ -63,6 +63,9 @@
 // GraphicsLayers based on the Layer painting order.
 //
 // There is one PaintLayerCompositor per LayoutView.
+//
+// In Slimming Paint v2, PaintLayerCompositor will be eventually replaced by
+// PaintArtifactCompositor.
 
 class CORE_EXPORT PaintLayerCompositor final : public GraphicsLayerClient {
     USING_FAST_MALLOC(PaintLayerCompositor);
diff --git a/third_party/WebKit/Source/core/layout/line/AbstractInlineTextBox.cpp b/third_party/WebKit/Source/core/layout/line/AbstractInlineTextBox.cpp
index 4491ff83..5f1e357 100644
--- a/third_party/WebKit/Source/core/layout/line/AbstractInlineTextBox.cpp
+++ b/third_party/WebKit/Source/core/layout/line/AbstractInlineTextBox.cpp
@@ -39,7 +39,7 @@
 
 AbstractInlineTextBox::InlineToAbstractInlineTextBoxHashMap* AbstractInlineTextBox::gAbstractInlineTextBoxMap = nullptr;
 
-PassRefPtr<AbstractInlineTextBox> AbstractInlineTextBox::getOrCreate(LayoutText* layoutText, InlineTextBox* inlineTextBox)
+PassRefPtr<AbstractInlineTextBox> AbstractInlineTextBox::getOrCreate(LineLayoutText lineLayoutText, InlineTextBox* inlineTextBox)
 {
     if (!inlineTextBox)
         return nullptr;
@@ -51,7 +51,7 @@
     if (it != gAbstractInlineTextBoxMap->end())
         return it->value;
 
-    RefPtr<AbstractInlineTextBox> obj = adoptRef(new AbstractInlineTextBox(layoutText, inlineTextBox));
+    RefPtr<AbstractInlineTextBox> obj = adoptRef(new AbstractInlineTextBox(lineLayoutText, inlineTextBox));
     gAbstractInlineTextBoxMap->set(inlineTextBox, obj);
     return obj;
 }
@@ -70,19 +70,19 @@
 
 AbstractInlineTextBox::~AbstractInlineTextBox()
 {
-    ASSERT(!m_layoutText);
+    ASSERT(!m_lineLayoutItem);
     ASSERT(!m_inlineTextBox);
 }
 
 void AbstractInlineTextBox::detach()
 {
-    if (Node* node = m_layoutText->node()) {
+    if (Node* node = m_lineLayoutItem.node()) {
         if (AXObjectCache* cache = node->document().existingAXObjectCache())
             cache->remove(this);
     }
 
-    m_layoutText = 0;
-    m_inlineTextBox = 0;
+    m_lineLayoutItem = LineLayoutText(nullptr);
+    m_inlineTextBox = nullptr;
 }
 
 PassRefPtr<AbstractInlineTextBox> AbstractInlineTextBox::nextInlineTextBox() const
@@ -91,16 +91,16 @@
     if (!m_inlineTextBox)
         return nullptr;
 
-    return getOrCreate(m_layoutText, m_inlineTextBox->nextTextBox());
+    return getOrCreate(m_lineLayoutItem, m_inlineTextBox->nextTextBox());
 }
 
 LayoutRect AbstractInlineTextBox::bounds() const
 {
-    if (!m_inlineTextBox || !m_layoutText)
+    if (!m_inlineTextBox || !m_lineLayoutItem)
         return LayoutRect();
 
     FloatRect boundaries(m_inlineTextBox->calculateBoundaries());
-    return LayoutRect(m_layoutText->localToAbsoluteQuad(boundaries).enclosingBoundingBox());
+    return LayoutRect(m_lineLayoutItem.localToAbsoluteQuad(boundaries).enclosingBoundingBox());
 }
 
 unsigned AbstractInlineTextBox::len() const
@@ -113,10 +113,10 @@
 
 AbstractInlineTextBox::Direction AbstractInlineTextBox::direction() const
 {
-    if (!m_inlineTextBox || !m_layoutText)
+    if (!m_inlineTextBox || !m_lineLayoutItem)
         return LeftToRight;
 
-    if (m_layoutText->style()->isHorizontalWritingMode())
+    if (m_lineLayoutItem.style()->isHorizontalWritingMode())
         return (m_inlineTextBox->direction() == RTL ? RightToLeft : LeftToRight);
     return (m_inlineTextBox->direction() == RTL ? BottomToTop : TopToBottom);
 }
@@ -153,18 +153,18 @@
 
 String AbstractInlineTextBox::text() const
 {
-    if (!m_inlineTextBox || !m_layoutText)
+    if (!m_inlineTextBox || !m_lineLayoutItem)
         return String();
 
     unsigned start = m_inlineTextBox->start();
     unsigned len = m_inlineTextBox->len();
-    if (Node* node = m_layoutText->node()) {
+    if (Node* node = m_lineLayoutItem.node()) {
         if (node->isTextNode())
             return plainText(EphemeralRange(Position(node, start), Position(node, start + len)), TextIteratorIgnoresStyleVisibility);
         return plainText(EphemeralRange(Position(node, PositionAnchorType::BeforeAnchor), Position(node, PositionAnchorType::AfterAnchor)), TextIteratorIgnoresStyleVisibility);
     }
 
-    String result = m_layoutText->text().substring(start, len).simplifyWhiteSpace(WTF::DoNotStripWhiteSpace);
+    String result = m_lineLayoutItem.text().substring(start, len).simplifyWhiteSpace(WTF::DoNotStripWhiteSpace);
     if (m_inlineTextBox->nextTextBox() && m_inlineTextBox->nextTextBox()->start() > m_inlineTextBox->end() && result.length() && !result.right(1).containsOnlyWhitespace())
         return result + " ";
     return result;
@@ -190,7 +190,7 @@
 
     InlineBox* next = m_inlineTextBox->nextOnLine();
     if (next && next->isInlineTextBox())
-        return getOrCreate(&toInlineTextBox(next)->layoutObject(), toInlineTextBox(next));
+        return getOrCreate(toInlineTextBox(next)->lineLayoutItem(), toInlineTextBox(next));
 
     return nullptr;
 }
@@ -203,7 +203,7 @@
 
     InlineBox* previous = m_inlineTextBox->prevOnLine();
     if (previous && previous->isInlineTextBox())
-        return getOrCreate(&toInlineTextBox(previous)->layoutObject(), toInlineTextBox(previous));
+        return getOrCreate(toInlineTextBox(previous)->lineLayoutItem(), toInlineTextBox(previous));
 
     return nullptr;
 }
diff --git a/third_party/WebKit/Source/core/layout/line/AbstractInlineTextBox.h b/third_party/WebKit/Source/core/layout/line/AbstractInlineTextBox.h
index 2fca2f9..7dc5396 100644
--- a/third_party/WebKit/Source/core/layout/line/AbstractInlineTextBox.h
+++ b/third_party/WebKit/Source/core/layout/line/AbstractInlineTextBox.h
@@ -33,7 +33,7 @@
 
 #include "core/CoreExport.h"
 #include "core/dom/Range.h"
-#include "core/layout/LayoutText.h"
+#include "core/layout/api/LineLayoutText.h"
 #include "core/layout/line/InlineTextBox.h"
 #include "wtf/HashMap.h"
 #include "wtf/RefPtr.h"
@@ -46,13 +46,13 @@
 // get information about InlineTextBoxes without tight coupling.
 class CORE_EXPORT AbstractInlineTextBox : public RefCounted<AbstractInlineTextBox> {
 private:
-    AbstractInlineTextBox(LayoutText* layoutText, InlineTextBox* inlineTextBox)
-        : m_layoutText(layoutText)
+    AbstractInlineTextBox(LineLayoutText lineLayoutItem, InlineTextBox* inlineTextBox)
+        : m_lineLayoutItem(lineLayoutItem)
         , m_inlineTextBox(inlineTextBox)
     {
     }
 
-    static PassRefPtr<AbstractInlineTextBox> getOrCreate(LayoutText*, InlineTextBox*);
+    static PassRefPtr<AbstractInlineTextBox> getOrCreate(LineLayoutText, InlineTextBox*);
     static void willDestroy(InlineTextBox*);
 
     friend class LayoutText;
@@ -75,7 +75,7 @@
 
     ~AbstractInlineTextBox();
 
-    LayoutText* layoutText() const { return m_layoutText; }
+    LineLayoutText lineLayoutItem() const { return m_lineLayoutItem; }
 
     PassRefPtr<AbstractInlineTextBox> nextInlineTextBox() const;
     LayoutRect bounds() const;
@@ -93,7 +93,7 @@
     void detach();
 
     // Weak ptrs; these are nulled when InlineTextBox::destroy() calls AbstractInlineTextBox::willDestroy.
-    LayoutText* m_layoutText;
+    LineLayoutText m_lineLayoutItem;
     InlineTextBox* m_inlineTextBox;
 
     typedef HashMap<InlineTextBox*, RefPtr<AbstractInlineTextBox>> InlineToAbstractInlineTextBoxHashMap;
diff --git a/third_party/WebKit/Source/core/layout/line/InlineBox.h b/third_party/WebKit/Source/core/layout/line/InlineBox.h
index 83c04b2..04cba3c 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineBox.h
+++ b/third_party/WebKit/Source/core/layout/line/InlineBox.h
@@ -39,7 +39,7 @@
 
 // InlineBox represents a rectangle that occurs on a line.  It corresponds to
 // some LayoutObject (i.e., it represents a portion of that LayoutObject).
-class InlineBox {
+class InlineBox : public DisplayItemClient {
     WTF_MAKE_NONCOPYABLE(InlineBox);
 public:
     InlineBox(LayoutObject& obj)
@@ -103,7 +103,7 @@
 #endif
 
     virtual const char* boxName() const;
-    virtual String debugName() const;
+    String debugName() const override;
 
     bool isText() const { return m_bitfields.isText(); }
     void setIsText(bool isText) { m_bitfields.setIsText(isText); }
@@ -299,7 +299,6 @@
     bool dirOverride() const { return m_bitfields.dirOverride(); }
     void setDirOverride(bool dirOverride) { m_bitfields.setDirOverride(dirOverride); }
 
-    DisplayItemClient displayItemClient() const { return toDisplayItemClient(this); }
     // Invalidate display item clients in the whole sub inline box tree.
     void invalidateDisplayItemClientsRecursively();
 
diff --git a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
index 5a94a49f..5c1127da 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
+++ b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
@@ -32,6 +32,8 @@
 #include "core/layout/LayoutRubyText.h"
 #include "core/layout/LayoutView.h"
 #include "core/layout/api/LineLayoutBox.h"
+#include "core/layout/api/LineLayoutInline.h"
+#include "core/layout/api/LineLayoutListMarker.h"
 #include "core/layout/api/LineLayoutRubyRun.h"
 #include "core/layout/line/GlyphOverflow.h"
 #include "core/layout/line/InlineTextBox.h"
@@ -105,7 +107,7 @@
     child->setFirstLineStyleBit(isFirstLineStyle());
     child->setIsHorizontal(isHorizontal());
     if (child->isText()) {
-        if (child->layoutObject().parent() == layoutObject())
+        if (child->lineLayoutItem().parent().isEqual(&layoutObject()))
             m_hasTextChildren = true;
         setHasTextDescendantsOnAncestors(this);
     } else if (child->isInlineFlowBox()) {
@@ -113,14 +115,14 @@
             setHasTextDescendantsOnAncestors(this);
     }
 
-    if (descendantsHaveSameLineHeightAndBaseline() && !child->layoutObject().isOutOfFlowPositioned()) {
-        const ComputedStyle& parentStyle = layoutObject().styleRef(isFirstLineStyle());
-        const ComputedStyle& childStyle = child->layoutObject().styleRef(isFirstLineStyle());
+    if (descendantsHaveSameLineHeightAndBaseline() && !child->lineLayoutItem().isOutOfFlowPositioned()) {
+        const ComputedStyle& parentStyle = lineLayoutItem().styleRef(isFirstLineStyle());
+        const ComputedStyle& childStyle = child->lineLayoutItem().styleRef(isFirstLineStyle());
         bool shouldClearDescendantsHaveSameLineHeightAndBaseline = false;
-        if (child->layoutObject().isReplaced()) {
+        if (child->lineLayoutItem().isReplaced()) {
             shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
         } else if (child->isText()) {
-            if (child->layoutObject().isBR() || child->layoutObject().parent() != layoutObject()) {
+            if (child->lineLayoutItem().isBR() || (!child->lineLayoutItem().parent().isEqual(&layoutObject()))) {
                 if (!parentStyle.font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle.font().fontMetrics())
                     || parentStyle.lineHeight() != childStyle.lineHeight()
                     || (parentStyle.verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle.verticalAlign() != BASELINE)
@@ -129,7 +131,7 @@
             if (childStyle.hasTextCombine() || childStyle.textEmphasisMark() != TextEmphasisMarkNone)
                 shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
         } else {
-            if (child->layoutObject().isBR()) {
+            if (child->lineLayoutItem().isBR()) {
                 // FIXME: This is dumb. We only turn off because current layout test results expect the <br> to be 0-height on the baseline.
                 // Other than making a zillion tests have to regenerate results, there's no reason to ditch the optimization here.
                 shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
@@ -150,19 +152,19 @@
             clearDescendantsHaveSameLineHeightAndBaseline();
     }
 
-    if (!child->layoutObject().isOutOfFlowPositioned()) {
+    if (!child->lineLayoutItem().isOutOfFlowPositioned()) {
         if (child->isText()) {
-            const ComputedStyle& childStyle = child->layoutObject().styleRef(isFirstLineStyle());
+            const ComputedStyle& childStyle = child->lineLayoutItem().styleRef(isFirstLineStyle());
             if (childStyle.letterSpacing() < 0 || childStyle.textShadow() || childStyle.textEmphasisMark() != TextEmphasisMarkNone || childStyle.textStrokeWidth())
                 child->clearKnownToHaveNoOverflow();
-        } else if (child->layoutObject().isReplaced()) {
+        } else if (child->lineLayoutItem().isReplaced()) {
             LineLayoutBox box = LineLayoutBox(child->lineLayoutItem());
             if (box.hasOverflowModel() || box.hasSelfPaintingLayer())
                 child->clearKnownToHaveNoOverflow();
-        } else if (!child->layoutObject().isBR() && (child->layoutObject().style(isFirstLineStyle())->boxShadow() || child->boxModelObject().hasSelfPaintingLayer()
-            || (child->layoutObject().isListMarker() && !toLayoutListMarker(child->layoutObject()).isInside())
-            || child->layoutObject().style(isFirstLineStyle())->hasBorderImageOutsets()
-            || child->layoutObject().style(isFirstLineStyle())->hasOutline())) {
+        } else if (!child->lineLayoutItem().isBR() && (child->lineLayoutItem().style(isFirstLineStyle())->boxShadow() || child->boxModelObject().hasSelfPaintingLayer()
+            || (child->lineLayoutItem().isListMarker() && !LineLayoutListMarker(child->lineLayoutItem()).isInside())
+            || child->lineLayoutItem().style(isFirstLineStyle())->hasBorderImageOutsets()
+            || child->lineLayoutItem().style(isFirstLineStyle())->hasOutline())) {
             child->clearKnownToHaveNoOverflow();
         }
 
@@ -253,7 +255,7 @@
 {
     InlineBox::move(delta);
     for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
-        if (child->layoutObject().isOutOfFlowPositioned())
+        if (child->lineLayoutItem().isOutOfFlowPositioned())
             continue;
         child->move(delta);
     }
@@ -263,7 +265,7 @@
 
 LineBoxList* InlineFlowBox::lineBoxes() const
 {
-    return toLayoutInline(layoutObject()).lineBoxes();
+    return LineLayoutInline(lineLayoutItem()).lineBoxes();
 }
 
 static inline bool isLastChildForLayoutObject(LayoutObject* ancestor, LayoutObject* child)
@@ -309,13 +311,13 @@
 
     // The root inline box never has borders/margins/padding.
     if (parent()) {
-        bool ltr = layoutObject().style()->isLeftToRightDirection();
+        bool ltr = lineLayoutItem().style()->isLeftToRightDirection();
 
         // Check to see if all initial lines are unconstructed.  If so, then
         // we know the inline began on this line (unless we are a continuation).
         LineBoxList* lineBoxList = lineBoxes();
-        if (!lineBoxList->firstLineBox()->isConstructed() && !layoutObject().isInlineElementContinuation()) {
-            if (layoutObject().style()->boxDecorationBreak() == DCLONE)
+        if (!lineBoxList->firstLineBox()->isConstructed() && !lineLayoutItem().isInlineElementContinuation()) {
+            if (lineLayoutItem().style()->boxDecorationBreak() == DCLONE)
                 includeLeftEdge = includeRightEdge = true;
             else if (ltr && lineBoxList->firstLineBox() == this)
                 includeLeftEdge = true;
@@ -332,7 +334,7 @@
             // (2) The logicallyLastRun is not a descendant of this layout object.
             // (3) The logicallyLastRun is a descendant of this layout object, but it is the last child of this layout object and it does not wrap to the next line.
             // (4) The decoration break is set to clone therefore there will be borders on every sides.
-            if (layoutObject().style()->boxDecorationBreak() == DCLONE) {
+            if (lineLayoutItem().style()->boxDecorationBreak() == DCLONE) {
                 includeLeftEdge = includeRightEdge = true;
             } else if (ltr) {
                 if (!nextLineBox()
@@ -380,7 +382,7 @@
     LayoutUnit& logicalLeft, LayoutUnit& minLogicalLeft, LayoutUnit& maxLogicalRight, bool& needsWordSpacing)
 {
     for (InlineBox* curr = firstChild; curr && curr != lastChild; curr = curr->nextOnLine()) {
-        if (curr->layoutObject().isText()) {
+        if (curr->lineLayoutItem().isText()) {
             InlineTextBox* text = toInlineTextBox(curr);
             LineLayoutText rt = text->lineLayoutItem();
             LayoutUnit space;
@@ -402,8 +404,8 @@
             if (knownToHaveNoOverflow())
                 maxLogicalRight = std::max(logicalLeft, maxLogicalRight);
         } else {
-            if (curr->layoutObject().isOutOfFlowPositioned()) {
-                if (curr->layoutObject().parent()->style()->isLeftToRightDirection()) {
+            if (curr->lineLayoutItem().isOutOfFlowPositioned()) {
+                if (curr->lineLayoutItem().parent().style()->isLeftToRightDirection()) {
                     curr->setLogicalLeft(logicalLeft);
                 } else {
                     // Our offset that we cache needs to be from the edge of the right border box and
@@ -413,7 +415,7 @@
                 }
                 continue; // The positioned object has no effect on the width.
             }
-            if (curr->layoutObject().isLayoutInline()) {
+            if (curr->lineLayoutItem().isLayoutInline()) {
                 InlineFlowBox* flow = toInlineFlowBox(curr);
                 logicalLeft += flow->marginLogicalLeft();
                 if (knownToHaveNoOverflow())
@@ -422,7 +424,7 @@
                 if (knownToHaveNoOverflow())
                     maxLogicalRight = std::max(logicalLeft, maxLogicalRight);
                 logicalLeft += flow->marginLogicalRight();
-            } else if (!curr->layoutObject().isListMarker() || toLayoutListMarker(curr->layoutObject()).isInside()) {
+            } else if (!curr->lineLayoutItem().isListMarker() || LineLayoutListMarker(curr->lineLayoutItem()).isInside()) {
                 // The box can have a different writing-mode than the overall line, so this is a bit complicated.
                 // Just get all the physical margin and overflow values by hand based off |isHorizontal|.
                 LineLayoutBoxModel box = curr->boxModelObject();
@@ -455,7 +457,7 @@
 {
     // Use "central" (Ideographic) baseline if writing-mode is vertical-* and text-orientation is not sideways-*.
     // http://dev.w3.org/csswg/css-writing-modes-3/#text-baselines
-    if (!isHorizontal() && layoutObject().style(isFirstLineStyle())->fontDescription().isVerticalAnyUpright())
+    if (!isHorizontal() && lineLayoutItem().style(isFirstLineStyle())->fontDescription().isVerticalAnyUpright())
         return IdeographicBaseline;
     return AlphabeticBaseline;
 }
@@ -465,7 +467,7 @@
     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
         // The computed lineheight needs to be extended for the
         // positioned elements
-        if (curr->layoutObject().isOutOfFlowPositioned())
+        if (curr->lineLayoutItem().isOutOfFlowPositioned())
             continue; // Positioned placeholders don't affect calculations.
         if (curr->verticalAlign() == TOP || curr->verticalAlign() == BOTTOM) {
             int lineHeight = curr->lineHeight();
@@ -527,7 +529,7 @@
         return;
 
     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
-        if (curr->layoutObject().isOutOfFlowPositioned())
+        if (curr->lineLayoutItem().isOutOfFlowPositioned())
             continue; // Positioned placeholders don't affect calculations.
 
         InlineFlowBox* inlineFlowBox = curr->isInlineFlowBox() ? toInlineFlowBox(curr) : nullptr;
@@ -580,7 +582,7 @@
 {
     bool isRootBox = isRootInlineBox();
     if (isRootBox) {
-        const FontMetrics& fontMetrics = layoutObject().style(isFirstLineStyle())->fontMetrics();
+        const FontMetrics& fontMetrics = lineLayoutItem().style(isFirstLineStyle())->fontMetrics();
         // RootInlineBoxes are always placed at pixel boundaries in their logical y direction. Not doing
         // so results in incorrect layout of text decorations, most notably underlines.
         setLogicalTop(roundToInt(top + maxAscent - fontMetrics.ascent(baselineType)));
@@ -594,7 +596,7 @@
     }
 
     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
-        if (curr->layoutObject().isOutOfFlowPositioned())
+        if (curr->lineLayoutItem().isOutOfFlowPositioned())
             continue; // Positioned placeholders don't affect calculations.
 
         if (descendantsHaveSameLineHeightAndBaseline()) {
@@ -622,7 +624,7 @@
         LayoutUnit boxHeightIncludingMargins = boxHeight;
         LayoutUnit borderPaddingHeight = 0;
         if (curr->isText() || curr->isInlineFlowBox()) {
-            const FontMetrics& fontMetrics = curr->layoutObject().style(isFirstLineStyle())->fontMetrics();
+            const FontMetrics& fontMetrics = curr->lineLayoutItem().style(isFirstLineStyle())->fontMetrics();
             newLogicalTop += curr->baselinePosition(baselineType) - fontMetrics.ascent(baselineType);
             if (curr->isInlineFlowBox()) {
                 LineLayoutBoxModel boxObject = LineLayoutBoxModel(curr->lineLayoutItem());
@@ -630,7 +632,7 @@
                 borderPaddingHeight = boxObject.borderAndPaddingLogicalHeight();
             }
             newLogicalTopIncludingMargins = newLogicalTop;
-        } else if (!curr->layoutObject().isBR()) {
+        } else if (!curr->lineLayoutItem().isBR()) {
             LineLayoutBox box = LineLayoutBox(curr->lineLayoutItem());
             newLogicalTopIncludingMargins = newLogicalTop;
             // TODO(kojii): isHorizontal() does not match to m_layoutObject.isHorizontalWritingMode(). crbug.com/552954
@@ -644,11 +646,11 @@
         curr->setLogicalTop(newLogicalTop);
 
         if (childAffectsTopBottomPos) {
-            if (curr->layoutObject().isRubyRun()) {
+            if (curr->lineLayoutItem().isRubyRun()) {
                 // Treat the leading on the first and last lines of ruby runs as not being part of the overall lineTop/lineBottom.
                 // Really this is a workaround hack for the fact that ruby should have been done as line layout and not done using
                 // inline-block.
-                if (layoutObject().style()->isFlippedLinesWritingMode() == (curr->layoutObject().style()->rubyPosition() == RubyPositionAfter))
+                if (lineLayoutItem().style()->isFlippedLinesWritingMode() == (curr->lineLayoutItem().style()->rubyPosition() == RubyPositionAfter))
                     hasAnnotationsBefore = true;
                 else
                     hasAnnotationsAfter = true;
@@ -657,15 +659,15 @@
                 if (LayoutRubyBase* rubyBase = rubyRun.rubyBase()) {
                     LayoutUnit bottomRubyBaseLeading = (curr->logicalHeight() - rubyBase->logicalBottom()) + rubyBase->logicalHeight() - (rubyBase->lastRootBox() ? rubyBase->lastRootBox()->lineBottom() : LayoutUnit());
                     LayoutUnit topRubyBaseLeading = rubyBase->logicalTop() + (rubyBase->firstRootBox() ? rubyBase->firstRootBox()->lineTop() : LayoutUnit());
-                    newLogicalTop += !layoutObject().style()->isFlippedLinesWritingMode() ? topRubyBaseLeading : bottomRubyBaseLeading;
+                    newLogicalTop += !lineLayoutItem().style()->isFlippedLinesWritingMode() ? topRubyBaseLeading : bottomRubyBaseLeading;
                     boxHeight -= (topRubyBaseLeading + bottomRubyBaseLeading);
                 }
             }
             if (curr->isInlineTextBox()) {
                 TextEmphasisPosition emphasisMarkPosition;
-                if (toInlineTextBox(curr)->getEmphasisMarkPosition(curr->layoutObject().styleRef(isFirstLineStyle()), emphasisMarkPosition)) {
+                if (toInlineTextBox(curr)->getEmphasisMarkPosition(curr->lineLayoutItem().styleRef(isFirstLineStyle()), emphasisMarkPosition)) {
                     bool emphasisMarkIsOver = emphasisMarkPosition == TextEmphasisPositionOver;
-                    if (emphasisMarkIsOver != curr->layoutObject().style(isFirstLineStyle())->isFlippedLinesWritingMode())
+                    if (emphasisMarkIsOver != curr->lineLayoutItem().style(isFirstLineStyle())->isFlippedLinesWritingMode())
                         hasAnnotationsBefore = true;
                     else
                         hasAnnotationsAfter = true;
@@ -706,7 +708,7 @@
             lineBottomIncludingMargins = std::max(lineBottom, lineBottomIncludingMargins);
         }
 
-        if (layoutObject().style()->isFlippedLinesWritingMode())
+        if (lineLayoutItem().style()->isFlippedLinesWritingMode())
             flipLinesInBlockDirection(lineTopIncludingMargins, lineBottomIncludingMargins);
     }
 }
@@ -714,7 +716,7 @@
 void InlineFlowBox::computeMaxLogicalTop(LayoutUnit& maxLogicalTop) const
 {
     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
-        if (curr->layoutObject().isOutOfFlowPositioned())
+        if (curr->lineLayoutItem().isOutOfFlowPositioned())
             continue; // Positioned placeholders don't affect calculations.
 
         if (descendantsHaveSameLineHeightAndBaseline())
@@ -734,7 +736,7 @@
     setLogicalTop(lineBottom - (logicalTop() - lineTop) - logicalHeight());
 
     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
-        if (curr->layoutObject().isOutOfFlowPositioned())
+        if (curr->lineLayoutItem().isOutOfFlowPositioned())
             continue; // Positioned placeholders aren't affected here.
 
         if (curr->isInlineFlowBox())
@@ -746,11 +748,11 @@
 
 inline void InlineFlowBox::addBoxShadowVisualOverflow(LayoutRect& logicalVisualOverflow)
 {
-    const ComputedStyle& style = layoutObject().styleRef(isFirstLineStyle());
+    const ComputedStyle& style = lineLayoutItem().styleRef(isFirstLineStyle());
 
     // box-shadow on the block element applies to the block and not to the lines,
     // unless it is modified by :first-line pseudo element.
-    if (!parent() && (!isFirstLineStyle() || &style == layoutObject().style()))
+    if (!parent() && (!isFirstLineStyle() || &style == lineLayoutItem().style()))
         return;
 
     WritingMode writingMode = style.writingMode();
@@ -770,11 +772,11 @@
 
 inline void InlineFlowBox::addBorderOutsetVisualOverflow(LayoutRect& logicalVisualOverflow)
 {
-    const ComputedStyle& style = layoutObject().styleRef(isFirstLineStyle());
+    const ComputedStyle& style = lineLayoutItem().styleRef(isFirstLineStyle());
 
     // border-image-outset on the block element applies to the block and not to the lines,
     // unless it is modified by :first-line pseudo element.
-    if (!parent() && (!isFirstLineStyle() || &style == layoutObject().style()))
+    if (!parent() && (!isFirstLineStyle() || &style == lineLayoutItem().style()))
         return;
 
     if (!style.hasBorderImageOutsets())
@@ -800,7 +802,7 @@
     if (!parent())
         return;
 
-    const ComputedStyle& style = layoutObject().styleRef(isFirstLineStyle());
+    const ComputedStyle& style = lineLayoutItem().styleRef(isFirstLineStyle());
     if (!style.hasOutline())
         return;
 
@@ -876,7 +878,7 @@
     // transforms or relative positioning (since those objects always have self-painting layers), but it does need to be adjusted
     // for writing-mode differences.
     if (!box.hasSelfPaintingLayer()) {
-        LayoutRect childLogicalVisualOverflow = box.logicalVisualOverflowRectForPropagation(layoutObject().styleRef());
+        LayoutRect childLogicalVisualOverflow = box.logicalVisualOverflowRectForPropagation(lineLayoutItem().styleRef());
         childLogicalVisualOverflow.move(inlineBox->logicalLeft(), inlineBox->logicalTop());
         logicalVisualOverflow.unite(childLogicalVisualOverflow);
     }
@@ -884,7 +886,7 @@
     // Layout overflow internal to the child box only propagates if the child box doesn't have overflow clip set.
     // Otherwise the child border box propagates as layout overflow.  This rectangle must include transforms and relative positioning
     // and be adjusted for writing-mode differences.
-    LayoutRect childLogicalLayoutOverflow = box.logicalLayoutOverflowRectForPropagation(layoutObject().styleRef());
+    LayoutRect childLogicalLayoutOverflow = box.logicalLayoutOverflowRectForPropagation(lineLayoutItem().styleRef());
     childLogicalLayoutOverflow.move(inlineBox->logicalLeft(), inlineBox->logicalTop());
     logicalLayoutOverflow.unite(childLogicalLayoutOverflow);
 }
@@ -911,10 +913,10 @@
     addOutlineVisualOverflow(logicalVisualOverflow);
 
     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
-        if (curr->layoutObject().isOutOfFlowPositioned())
+        if (curr->lineLayoutItem().isOutOfFlowPositioned())
             continue; // Positioned placeholders don't affect calculations.
 
-        if (curr->layoutObject().isText()) {
+        if (curr->lineLayoutItem().isText()) {
             InlineTextBox* text = toInlineTextBox(curr);
             LineLayoutText rt = text->lineLayoutItem();
             if (rt.isBR())
@@ -922,7 +924,7 @@
             LayoutRect textBoxOverflow(text->logicalFrameRect());
             addTextBoxVisualOverflow(text, textBoxDataMap, textBoxOverflow);
             logicalVisualOverflow.unite(textBoxOverflow);
-        } else if (curr->layoutObject().isLayoutInline()) {
+        } else if (curr->lineLayoutItem().isLayoutInline()) {
             InlineFlowBox* flow = toInlineFlowBox(curr);
             flow->computeOverflow(lineTop, lineBottom, textBoxDataMap);
             if (!flow->boxModelObject().hasSelfPaintingLayer())
@@ -1002,7 +1004,7 @@
 
         // If the current inline box's layout object and the previous inline box's layout object are same,
         // we should yield the hit-test to the previous inline box.
-        if (prev && curr->layoutObject() == prev->layoutObject())
+        if (prev && curr->lineLayoutItem().isEqual(&prev->layoutObject()))
             continue;
 
         // If a parent of the current inline box is a culled inline,
@@ -1027,10 +1029,10 @@
         }
     }
 
-    if (layoutObject().style()->hasBorderRadius()) {
+    if (lineLayoutItem().style()->hasBorderRadius()) {
         LayoutRect borderRect = logicalFrameRect();
         borderRect.moveBy(accumulatedOffset);
-        FloatRoundedRect border = layoutObject().style()->getRoundedBorderFor(borderRect, includeLogicalLeftEdge(), includeLogicalRightEdge());
+        FloatRoundedRect border = lineLayoutItem().style()->getRoundedBorderFor(borderRect, includeLogicalLeftEdge(), includeLogicalRightEdge());
         if (!locationInContainer.intersects(border))
             return false;
     }
@@ -1045,7 +1047,7 @@
     rect = LayoutRect(pixelSnappedIntRect(rect));
     if (visibleToHitTestRequest(result.hitTestRequest()) && locationInContainer.intersects(rect)) {
         layoutObject().updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset))); // Don't add in m_topLeft here, we want coords in the containing block's space.
-        if (!result.addNodeToListBasedTestResult(layoutObject().node(), locationInContainer, rect))
+        if (!result.addNodeToListBasedTestResult(lineLayoutItem().node(), locationInContainer, rect))
             return true;
     }
 
@@ -1063,7 +1065,7 @@
     // would be clipped out, so it has to be drawn separately).
     StyleImage* image = lastBackgroundLayer.image();
     bool hasFillImage = image && image->canRender();
-    return (!hasFillImage && !layoutObject().style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent();
+    return (!hasFillImage && !lineLayoutItem().style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent();
 }
 
 InlineBox* InlineFlowBox::firstLeafChild() const
@@ -1135,13 +1137,13 @@
 {
     LayoutUnit result = 0;
     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
-        if (curr->layoutObject().isOutOfFlowPositioned())
+        if (curr->lineLayoutItem().isOutOfFlowPositioned())
             continue; // Positioned placeholders don't affect calculations.
 
         if (curr->isInlineFlowBox())
             result = std::max(result, toInlineFlowBox(curr)->computeOverAnnotationAdjustment(allowedPosition));
 
-        if (curr->layoutObject().isReplaced() && curr->layoutObject().isRubyRun() && curr->layoutObject().style()->rubyPosition() == RubyPositionBefore) {
+        if (curr->lineLayoutItem().isReplaced() && curr->lineLayoutItem().isRubyRun() && curr->lineLayoutItem().style()->rubyPosition() == RubyPositionBefore) {
             LineLayoutRubyRun rubyRun = LineLayoutRubyRun(curr->lineLayoutItem());
             LayoutRubyText* rubyText = rubyRun.rubyText();
             if (!rubyText)
@@ -1163,7 +1165,7 @@
         }
 
         if (curr->isInlineTextBox()) {
-            const ComputedStyle& style = curr->layoutObject().styleRef(isFirstLineStyle());
+            const ComputedStyle& style = curr->lineLayoutItem().styleRef(isFirstLineStyle());
             TextEmphasisPosition emphasisMarkPosition;
             if (style.textEmphasisMark() != TextEmphasisMarkNone && toInlineTextBox(curr)->getEmphasisMarkPosition(style, emphasisMarkPosition) && emphasisMarkPosition == TextEmphasisPositionOver) {
                 if (!style.isFlippedLinesWritingMode()) {
@@ -1183,13 +1185,13 @@
 {
     LayoutUnit result = 0;
     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
-        if (curr->layoutObject().isOutOfFlowPositioned())
+        if (curr->lineLayoutItem().isOutOfFlowPositioned())
             continue; // Positioned placeholders don't affect calculations.
 
         if (curr->isInlineFlowBox())
             result = std::max(result, toInlineFlowBox(curr)->computeUnderAnnotationAdjustment(allowedPosition));
 
-        if (curr->layoutObject().isReplaced() && curr->layoutObject().isRubyRun() && curr->layoutObject().style()->rubyPosition() == RubyPositionAfter) {
+        if (curr->lineLayoutItem().isReplaced() && curr->lineLayoutItem().isRubyRun() && curr->lineLayoutItem().style()->rubyPosition() == RubyPositionAfter) {
             LineLayoutRubyRun rubyRun = LineLayoutRubyRun(curr->lineLayoutItem());
             LayoutRubyText* rubyText = rubyRun.rubyText();
             if (!rubyText)
@@ -1211,7 +1213,7 @@
         }
 
         if (curr->isInlineTextBox()) {
-            const ComputedStyle& style = curr->layoutObject().styleRef(isFirstLineStyle());
+            const ComputedStyle& style = curr->lineLayoutItem().styleRef(isFirstLineStyle());
             if (style.textEmphasisMark() != TextEmphasisMarkNone && style.textEmphasisPosition() == TextEmphasisPositionUnder) {
                 if (!style.isFlippedLinesWritingMode()) {
                     LayoutUnit bottomOfEmphasisMark = curr->logicalBottom() + style.font().emphasisMarkHeight(style.textEmphasisMarkString());
@@ -1242,7 +1244,7 @@
         leafBoxesInLogicalOrder.append(leaf);
     }
 
-    if (layoutObject().style()->rtlOrdering() == VisualOrder)
+    if (lineLayoutItem().style()->rtlOrdering() == VisualOrder)
         return;
 
     // Reverse of reordering of the line (L2 according to Bidi spec):
diff --git a/third_party/WebKit/Source/core/layout/line/InlineTextBox.h b/third_party/WebKit/Source/core/layout/line/InlineTextBox.h
index 0ddc244..0127f041 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineTextBox.h
+++ b/third_party/WebKit/Source/core/layout/line/InlineTextBox.h
@@ -51,7 +51,6 @@
         setIsText(true);
     }
 
-    LayoutText& layoutObject() const { return toLayoutText(InlineBox::layoutObject()); }
     LineLayoutText lineLayoutItem() const { return LineLayoutText(InlineBox::lineLayoutItem()); }
 
     void destroy() final;
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.h b/third_party/WebKit/Source/core/loader/EmptyClients.h
index 9f4f7bd..a0ae2774 100644
--- a/third_party/WebKit/Source/core/loader/EmptyClients.h
+++ b/third_party/WebKit/Source/core/loader/EmptyClients.h
@@ -234,6 +234,8 @@
     void didRunInsecureContent(SecurityOrigin*, const KURL&) override {}
     void didDetectXSS(const KURL&, bool) override {}
     void didDispatchPingLoader(const KURL&) override {}
+    void didDisplayContentWithCertificateErrors(const KURL&, const CString&, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) override {}
+    void didRunContentWithCertificateErrors(const KURL&, const CString&, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) override {}
     void selectorMatchChanged(const Vector<String>&, const Vector<String>&) override {}
     PassRefPtrWillBeRawPtr<LocalFrame> createFrame(const FrameLoadRequest&, const AtomicString&, HTMLFrameOwnerElement*) override;
     PassRefPtrWillBeRawPtr<Widget> createPlugin(HTMLPlugInElement*, const KURL&, const Vector<String>&, const Vector<String>&, const String&, bool, DetachedPluginPolicy) override;
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
index 6be16e9e..41bed10 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -34,6 +34,7 @@
 #include "bindings/core/v8/ScriptController.h"
 #include "core/dom/Document.h"
 #include "core/fetch/ClientHintsPreferences.h"
+#include "core/fetch/ResourceLoader.h"
 #include "core/fetch/UniqueIdentifier.h"
 #include "core/frame/FrameConsole.h"
 #include "core/frame/FrameHost.h"
@@ -239,6 +240,9 @@
         m_documentLoader->clientHintsPreferences().updateFromAcceptClientHintsHeader(response.httpHeaderField("accept-ch"), fetcher);
     }
 
+    if (response.hasMajorCertificateErrors() && resourceLoader)
+        MixedContentChecker::handleCertificateError(frame(), resourceLoader->originalRequest(), response);
+
     frame()->loader().progress().incrementProgress(identifier, response);
     frame()->loader().client()->dispatchDidReceiveResponse(m_documentLoader, identifier, response);
     TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceReceiveResponse", TRACE_EVENT_SCOPE_THREAD, "data", InspectorReceiveResponseEvent::data(identifier, frame(), response));
diff --git a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
index b492489..42e507db 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
+++ b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
@@ -129,6 +129,13 @@
     virtual void didDetectXSS(const KURL&, bool didBlockEntirePage) = 0;
     virtual void didDispatchPingLoader(const KURL&) = 0;
 
+    // The given main resource displayed content with certificate errors
+    // with the given URL and security info.
+    virtual void didDisplayContentWithCertificateErrors(const KURL&, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) = 0;
+    // The given main resource ran content with certificate errors with
+    // the given URL and security info.
+    virtual void didRunContentWithCertificateErrors(const KURL&, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) = 0;
+
     // Will be called when |PerformanceTiming| events are updated
     virtual void didChangePerformanceTiming() { }
 
diff --git a/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp b/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp
index fdcc09b..f525cda 100644
--- a/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp
+++ b/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp
@@ -458,6 +458,27 @@
     return effectiveFrame;
 }
 
+void MixedContentChecker::handleCertificateError(LocalFrame* frame, const ResourceRequest& request, const ResourceResponse& response)
+{
+    WebURLRequest::FrameType frameType = request.frameType();
+    LocalFrame* effectiveFrame = effectiveFrameForFrameType(frame, frameType);
+    if (frameType == WebURLRequest::FrameTypeTopLevel || !effectiveFrame)
+        return;
+
+    FrameLoaderClient* client = effectiveFrame->loader().client();
+    WebURLRequest::RequestContext requestContext = request.requestContext();
+    ContextType contextType = MixedContentChecker::contextTypeFromContext(requestContext, frame);
+    if (contextType == ContextTypeBlockable) {
+        client->didRunContentWithCertificateErrors(response.url(), response.getSecurityInfo(), effectiveFrame->document()->url(), effectiveFrame->loader().documentLoader()->response().getSecurityInfo());
+    } else {
+        // contextTypeFromContext() never returns NotMixedContent (it
+        // computes the type of mixed content, given that the content is
+        // mixed).
+        ASSERT(contextType != ContextTypeNotMixedContent);
+        client->didDisplayContentWithCertificateErrors(response.url(), response.getSecurityInfo(), effectiveFrame->document()->url(), effectiveFrame->loader().documentLoader()->response().getSecurityInfo());
+    }
+}
+
 MixedContentChecker::ContextType MixedContentChecker::contextTypeForInspector(LocalFrame* frame, const ResourceRequest& request)
 {
     LocalFrame* effectiveFrame = effectiveFrameForFrameType(frame, request.frameType());
diff --git a/third_party/WebKit/Source/core/loader/MixedContentChecker.h b/third_party/WebKit/Source/core/loader/MixedContentChecker.h
index d88780bd..e2e50c4 100644
--- a/third_party/WebKit/Source/core/loader/MixedContentChecker.h
+++ b/third_party/WebKit/Source/core/loader/MixedContentChecker.h
@@ -31,6 +31,7 @@
 #ifndef MixedContentChecker_h
 #define MixedContentChecker_h
 
+#include "base/gtest_prod_util.h"
 #include "core/CoreExport.h"
 #include "platform/heap/Handle.h"
 #include "platform/network/ResourceRequest.h"
@@ -42,6 +43,7 @@
 class FrameLoaderClient;
 class LocalFrame;
 class KURL;
+class ResourceResponse;
 class SecurityOrigin;
 
 class CORE_EXPORT MixedContentChecker final {
@@ -75,7 +77,10 @@
     // for a mixed content check for the given frame type.
     static LocalFrame* effectiveFrameForFrameType(LocalFrame*, WebURLRequest::FrameType);
 
+    static void handleCertificateError(LocalFrame*, const ResourceRequest&, const ResourceResponse&);
+
 private:
+    FRIEND_TEST_ALL_PREFIXES(MixedContentCheckerTest, HandleCertificateError);
     enum MixedContentType {
         Display,
         Execution,
diff --git a/third_party/WebKit/Source/core/loader/MixedContentCheckerTest.cpp b/third_party/WebKit/Source/core/loader/MixedContentCheckerTest.cpp
index 4291c0a..8b4cb217 100644
--- a/third_party/WebKit/Source/core/loader/MixedContentCheckerTest.cpp
+++ b/third_party/WebKit/Source/core/loader/MixedContentCheckerTest.cpp
@@ -5,9 +5,12 @@
 #include "config.h"
 #include "core/loader/MixedContentChecker.h"
 
+#include "core/loader/EmptyClients.h"
 #include "core/testing/DummyPageHolder.h"
+#include "platform/network/ResourceResponse.h"
 #include "platform/weborigin/KURL.h"
 #include "platform/weborigin/SecurityOrigin.h"
+#include "testing/gmock/include/gmock/gmock-generated-function-mockers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "wtf/RefPtr.h"
 #include <base/macros.h>
@@ -67,4 +70,48 @@
     EXPECT_EQ(MixedContentChecker::ContextTypeOptionallyBlockable, MixedContentChecker::contextTypeForInspector(&dummyPageHolder->frame(), blockableMixedContent));
 }
 
+namespace {
+
+    class MockFrameLoaderClient : public EmptyFrameLoaderClient {
+    public:
+        MockFrameLoaderClient()
+            : EmptyFrameLoaderClient()
+        {
+        }
+        MOCK_METHOD4(didDisplayContentWithCertificateErrors, void(const KURL&, const CString&, const WebURL&, const CString&));
+        MOCK_METHOD4(didRunContentWithCertificateErrors, void(const KURL&, const CString&, const WebURL&, const CString&));
+    };
+
+} // namespace
+
+TEST(MixedContentCheckerTest, HandleCertificateError)
+{
+    MockFrameLoaderClient* client = new MockFrameLoaderClient;
+    OwnPtr<DummyPageHolder> dummyPageHolder = DummyPageHolder::create(IntSize(1, 1), nullptr, adoptPtrWillBeNoop(client));
+
+    KURL mainResourceUrl(KURL(), "https://example.test");
+    KURL displayedUrl(KURL(), "https://example-displayed.test");
+    KURL ranUrl(KURL(), "https://example-ran.test");
+
+    dummyPageHolder->frame().document()->setURL(mainResourceUrl);
+    ResourceRequest request1(ranUrl);
+    request1.setRequestContext(WebURLRequest::RequestContextScript);
+    request1.setFrameType(WebURLRequest::FrameTypeNone);
+    ResourceResponse response1;
+    response1.setURL(ranUrl);
+    response1.setSecurityInfo("security info1");
+    EXPECT_CALL(*client, didRunContentWithCertificateErrors(ranUrl, response1.getSecurityInfo(), WebURL(mainResourceUrl), CString()));
+    MixedContentChecker::handleCertificateError(&dummyPageHolder->frame(), request1, response1);
+
+    ResourceRequest request2(displayedUrl);
+    request2.setRequestContext(WebURLRequest::RequestContextImage);
+    request2.setFrameType(WebURLRequest::FrameTypeNone);
+    ResourceResponse response2;
+    ASSERT_EQ(MixedContentChecker::ContextTypeOptionallyBlockable, MixedContentChecker::contextTypeFromContext(request2.requestContext(), &dummyPageHolder->frame()));
+    response2.setURL(displayedUrl);
+    response2.setSecurityInfo("security info2");
+    EXPECT_CALL(*client, didDisplayContentWithCertificateErrors(displayedUrl, response2.getSecurityInfo(), WebURL(mainResourceUrl), CString()));
+    MixedContentChecker::handleCertificateError(&dummyPageHolder->frame(), request2, response2);
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/page/ChromeClient.h b/third_party/WebKit/Source/core/page/ChromeClient.h
index 771528b7..e3ed1387 100644
--- a/third_party/WebKit/Source/core/page/ChromeClient.h
+++ b/third_party/WebKit/Source/core/page/ChromeClient.h
@@ -62,6 +62,7 @@
 class LocalFrame;
 class Node;
 class Page;
+class PaintArtifact;
 class PopupOpeningObserver;
 class WebCompositorAnimationTimeline;
 class WebFrameScheduler;
@@ -187,6 +188,10 @@
     // one. Otherwise it sets it for the WebViewImpl.
     virtual void attachRootGraphicsLayer(GraphicsLayer*, LocalFrame* localRoot) = 0;
 
+    // In Slimming Paint v2, called when the paint artifact is updated, to allow
+    // the underlying web widget to composite it.
+    virtual void didPaint(const PaintArtifact&) { }
+
     virtual void attachCompositorAnimationTimeline(WebCompositorAnimationTimeline*, LocalFrame* localRoot) { }
     virtual void detachCompositorAnimationTimeline(WebCompositorAnimationTimeline*, LocalFrame* localRoot) { }
 
diff --git a/third_party/WebKit/Source/core/page/PrintContext.cpp b/third_party/WebKit/Source/core/page/PrintContext.cpp
index 4808b8a69..c02388f 100644
--- a/third_party/WebKit/Source/core/page/PrintContext.cpp
+++ b/third_party/WebKit/Source/core/page/PrintContext.cpp
@@ -24,7 +24,7 @@
 #include "core/frame/FrameView.h"
 #include "core/frame/LocalFrame.h"
 #include "core/layout/LayoutView.h"
-#include "third_party/skia/include/core/SkAnnotation.h"
+#include "platform/graphics/GraphicsContext.h"
 
 namespace blink {
 
@@ -230,7 +230,7 @@
     }
 }
 
-void PrintContext::outputLinkedDestinations(SkCanvas* canvas, const IntRect& pageRect)
+void PrintContext::outputLinkedDestinations(GraphicsContext& context, const IntRect& pageRect)
 {
     if (!m_linkedDestinationsValid) {
         // Collect anchors in the top-level frame only because our PrintContext
@@ -247,13 +247,11 @@
         // TODO(bokan): boundingBox looks to be in content coordinates but
         // convertToRootFrame doesn't apply scroll offsets when converting up to
         // the root frame.
-        boundingBox = layoutObject->frameView()->convertToRootFrame(boundingBox);
-        if (!pageRect.intersects(boundingBox))
+        IntPoint point = layoutObject->frameView()->convertToRootFrame(boundingBox.location());
+        if (!pageRect.contains(point))
             continue;
-        IntPoint point = boundingBox.minXMinYCorner();
         point.clampNegativeToZero();
-        SkAutoDataUnref nameData(SkData::NewWithCString(entry.key.utf8().data()));
-        SkAnnotateNamedDestination(canvas, SkPoint::Make(point.x(), point.y()), nameData);
+        context.setURLDestinationLocation(entry.key, point);
     }
 }
 
diff --git a/third_party/WebKit/Source/core/page/PrintContext.h b/third_party/WebKit/Source/core/page/PrintContext.h
index e1365ba..402595b 100644
--- a/third_party/WebKit/Source/core/page/PrintContext.h
+++ b/third_party/WebKit/Source/core/page/PrintContext.h
@@ -28,14 +28,13 @@
 #include "wtf/Vector.h"
 #include "wtf/text/WTFString.h"
 
-class SkCanvas;
-
 namespace blink {
 
 class Element;
 class LocalFrame;
 class FloatRect;
 class FloatSize;
+class GraphicsContext;
 class IntRect;
 class Node;
 
@@ -79,7 +78,7 @@
     DECLARE_VIRTUAL_TRACE();
 
 protected:
-    void outputLinkedDestinations(SkCanvas*, const IntRect& pageRect);
+    void outputLinkedDestinations(GraphicsContext&, const IntRect& pageRect);
 
     RawPtrWillBeMember<LocalFrame> m_frame;
     Vector<IntRect> m_pageRects;
diff --git a/third_party/WebKit/Source/core/page/PrintContextTest.cpp b/third_party/WebKit/Source/core/page/PrintContextTest.cpp
index 4a20be6..8e58228 100644
--- a/third_party/WebKit/Source/core/page/PrintContextTest.cpp
+++ b/third_party/WebKit/Source/core/page/PrintContextTest.cpp
@@ -9,14 +9,13 @@
 
 #include "core/frame/FrameView.h"
 #include "core/html/HTMLElement.h"
-#include "core/html/HTMLIFrameElement.h"
 #include "core/layout/LayoutTestHelper.h"
 #include "core/layout/LayoutView.h"
-#include "core/loader/EmptyClients.h"
 #include "core/paint/PaintLayer.h"
 #include "core/paint/PaintLayerPainter.h"
 #include "core/testing/DummyPageHolder.h"
 #include "platform/graphics/GraphicsContext.h"
+#include "platform/graphics/paint/DrawingRecorder.h"
 #include "platform/graphics/paint/SkPictureBuilder.h"
 #include "platform/scroll/ScrollbarTheme.h"
 #include "platform/testing/SkiaForCoreTesting.h"
@@ -32,9 +31,9 @@
 public:
     MockPrintContext(LocalFrame* frame) : PrintContext(frame) { }
 
-    void outputLinkedDestinations(SkCanvas* canvas, const IntRect& pageRect)
+    void outputLinkedDestinations(GraphicsContext& context, const IntRect& pageRect)
     {
-        PrintContext::outputLinkedDestinations(canvas, pageRect);
+        PrintContext::outputLinkedDestinations(context, pageRect);
     }
 };
 
@@ -99,9 +98,12 @@
         SkPictureBuilder pictureBuilder(pageRect);
         GraphicsContext& context = pictureBuilder.context();
         context.setPrinting(true);
-        document().view()->paintContents(&context, GlobalPaintPrinting, pageRect);
+        document().view()->paintContents(context, GlobalPaintPrinting, pageRect);
+        {
+            DrawingRecorder recorder(context, *document().layoutView(), DisplayItem::PrintedContentDestinationLocations, pageRect);
+            printContext().outputLinkedDestinations(context, pageRect);
+        }
         pictureBuilder.endRecording()->playback(&canvas);
-        printContext().outputLinkedDestinations(&canvas, pageRect);
         printContext().end();
     }
 
@@ -120,10 +122,10 @@
         return ts.release();
     }
 
-    static String htmlForAnchor(int x, int y, const char* name)
+    static String htmlForAnchor(int x, int y, const char* name, const char* textContent)
     {
         TextStream ts;
-        ts << "<a name='" << name << "' style='position: absolute; left: " << x << "px; top: " << y << "px'>" << name << "</a>";
+        ts << "<a name='" << name << "' style='position: absolute; left: " << x << "px; top: " << y << "px'>" << textContent << "</a>";
         return ts.release();
     }
 
@@ -223,8 +225,24 @@
     document().setBaseURLOverride(KURL(ParsedURLString, "http://a.com/"));
     setBodyInnerHTML(absoluteBlockHtmlForLink(50, 60, 70, 80, "#fragment") // Generates a Link_Named_Dest_Key annotation
         + absoluteBlockHtmlForLink(150, 160, 170, 180, "#not-found") // Generates no annotation
-        + htmlForAnchor(250, 260, "fragment") // Generates a Define_Named_Dest_Key annotation
-        + htmlForAnchor(350, 360, "fragment-not-used")); // Generates no annotation
+        + htmlForAnchor(250, 260, "fragment", "fragment") // Generates a Define_Named_Dest_Key annotation
+        + htmlForAnchor(350, 360, "fragment-not-used", "fragment-not-used")); // Generates no annotation
+    printSinglePage(canvas);
+
+    const Vector<MockCanvas::Operation>& operations = canvas.recordedOperations();
+    ASSERT_EQ(2u, operations.size());
+    EXPECT_EQ(MockCanvas::DrawRect, operations[0].type);
+    EXPECT_SKRECT_EQ(50, 60, 70, 80, operations[0].rect);
+    EXPECT_EQ(MockCanvas::DrawPoint, operations[1].type);
+    EXPECT_SKRECT_EQ(250, 260, 0, 0, operations[1].rect);
+}
+
+TEST_F(PrintContextTest, EmptyLinkedTarget)
+{
+    MockCanvas canvas;
+    document().setBaseURLOverride(KURL(ParsedURLString, "http://a.com/"));
+    setBodyInnerHTML(absoluteBlockHtmlForLink(50, 60, 70, 80, "#fragment")
+        + htmlForAnchor(250, 260, "fragment", ""));
     printSinglePage(canvas);
 
     const Vector<MockCanvas::Operation>& operations = canvas.recordedOperations();
@@ -255,20 +273,9 @@
         "<iframe id='frame' src='http://b.com/' width='500' height='500'"
         " style='border-width: 5px; margin: 5px; position: absolute; top: 90px; left: 90px'></iframe>");
 
-    HTMLIFrameElement& iframe = *toHTMLIFrameElement(document().getElementById("frame"));
-    OwnPtrWillBeRawPtr<FrameLoaderClient> frameLoaderClient = FrameLoaderClientWithParent::create(document().frame());
-    RefPtrWillBePersistent<LocalFrame> subframe = LocalFrame::create(frameLoaderClient.get(), document().frame()->host(), &iframe);
-    subframe->setView(FrameView::create(subframe.get(), IntSize(500, 500)));
-    subframe->init();
-    static_cast<SingleChildFrameLoaderClient*>(document().frame()->client())->setChild(subframe.get());
-    document().frame()->host()->incrementSubframeCount();
-
-    Document& frameDocument = *iframe.contentDocument();
-    frameDocument.setBaseURLOverride(KURL(ParsedURLString, "http://b.com/"));
-    frameDocument.body()->setInnerHTML(absoluteBlockHtmlForLink(50, 60, 70, 80, "#fragment")
+    setupChildIframe("frame", absoluteBlockHtmlForLink(50, 60, 70, 80, "#fragment")
         + absoluteBlockHtmlForLink(150, 160, 170, 180, "http://www.google.com")
-        + absoluteBlockHtmlForLink(250, 260, 270, 280, "http://www.google.com#fragment"),
-        ASSERT_NO_EXCEPTION);
+        + absoluteBlockHtmlForLink(250, 260, 270, 280, "http://www.google.com#fragment"));
 
     printSinglePage(canvas);
 
@@ -278,10 +285,6 @@
     EXPECT_SKRECT_EQ(250, 260, 170, 180, operations[0].rect);
     EXPECT_EQ(MockCanvas::DrawRect, operations[1].type);
     EXPECT_SKRECT_EQ(350, 360, 270, 280, operations[1].rect);
-
-    subframe->detach(FrameDetachType::Remove);
-    static_cast<SingleChildFrameLoaderClient*>(document().frame()->client())->setChild(nullptr);
-    document().frame()->host()->decrementSubframeCount();
 }
 
 TEST_F(PrintContextFrameTest, WithScrolledSubframe)
@@ -292,24 +295,13 @@
         "<iframe id='frame' src='http://b.com/' width='500' height='500'"
         " style='border-width: 5px; margin: 5px; position: absolute; top: 90px; left: 90px'></iframe>");
 
-    HTMLIFrameElement& iframe = *toHTMLIFrameElement(document().getElementById("frame"));
-    OwnPtrWillBeRawPtr<FrameLoaderClient> frameLoaderClient = FrameLoaderClientWithParent::create(document().frame());
-    RefPtrWillBePersistent<LocalFrame> subframe = LocalFrame::create(frameLoaderClient.get(), document().frame()->host(), &iframe);
-    subframe->setView(FrameView::create(subframe.get(), IntSize(500, 500)));
-    subframe->init();
-    static_cast<SingleChildFrameLoaderClient*>(document().frame()->client())->setChild(subframe.get());
-    document().frame()->host()->incrementSubframeCount();
-
-    Document& frameDocument = *iframe.contentDocument();
-    frameDocument.setBaseURLOverride(KURL(ParsedURLString, "http://b.com/"));
-    frameDocument.body()->setInnerHTML(
-        absoluteBlockHtmlForLink(10, 10, 20, 20, "http://invisible.com")
+    Document& frameDocument = setupChildIframe("frame", absoluteBlockHtmlForLink(10, 10, 20, 20, "http://invisible.com")
         + absoluteBlockHtmlForLink(50, 60, 70, 80, "http://partly.visible.com")
         + absoluteBlockHtmlForLink(150, 160, 170, 180, "http://www.google.com")
         + absoluteBlockHtmlForLink(250, 260, 270, 280, "http://www.google.com#fragment")
-        + absoluteBlockHtmlForLink(850, 860, 70, 80, "http://another.invisible.com"),
-        ASSERT_NO_EXCEPTION);
-    iframe.contentWindow()->scrollTo(100, 100);
+        + absoluteBlockHtmlForLink(850, 860, 70, 80, "http://another.invisible.com"));
+
+    frameDocument.domWindow()->scrollTo(100, 100);
 
     printSinglePage(canvas);
 
@@ -321,10 +313,6 @@
     EXPECT_SKRECT_EQ(150, 160, 170, 180, operations[1].rect);
     EXPECT_EQ(MockCanvas::DrawRect, operations[2].type);
     EXPECT_SKRECT_EQ(250, 260, 270, 280, operations[2].rect);
-
-    subframe->detach(FrameDetachType::Remove);
-    static_cast<SingleChildFrameLoaderClient*>(document().frame()->client())->setChild(nullptr);
-    document().frame()->host()->decrementSubframeCount();
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
index e7e5e58..9d5161de 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
@@ -276,13 +276,13 @@
         GraphicsLayer::unregisterContentsLayer(scrollbarLayer->layer());
 }
 
-static PassOwnPtr<WebScrollbarLayer> createScrollbarLayer(Scrollbar* scrollbar, float deviceScaleFactor)
+static PassOwnPtr<WebScrollbarLayer> createScrollbarLayer(Scrollbar& scrollbar, float deviceScaleFactor)
 {
-    ScrollbarTheme* theme = scrollbar->theme();
+    ScrollbarTheme& theme = scrollbar.theme();
     WebScrollbarThemePainter painter(theme, scrollbar, deviceScaleFactor);
     OwnPtr<WebScrollbarThemeGeometry> geometry(WebScrollbarThemeGeometryNative::create(theme));
 
-    OwnPtr<WebScrollbarLayer> scrollbarLayer = adoptPtr(Platform::current()->compositorSupport()->createScrollbarLayer(WebScrollbarImpl::create(scrollbar), painter, geometry.leakPtr()));
+    OwnPtr<WebScrollbarLayer> scrollbarLayer = adoptPtr(Platform::current()->compositorSupport()->createScrollbarLayer(WebScrollbarImpl::create(&scrollbar), painter, geometry.leakPtr()));
     GraphicsLayer::registerContentsLayer(scrollbarLayer->layer());
     return scrollbarLayer.release();
 }
@@ -352,8 +352,8 @@
     }
 
     if (scrollbarGraphicsLayer) {
-        Scrollbar* scrollbar = orientation == HorizontalScrollbar ? scrollableArea->horizontalScrollbar() : scrollableArea->verticalScrollbar();
-        if (scrollbar->isCustomScrollbar()) {
+        Scrollbar& scrollbar = orientation == HorizontalScrollbar ? *scrollableArea->horizontalScrollbar() : *scrollableArea->verticalScrollbar();
+        if (scrollbar.isCustomScrollbar()) {
             detachScrollbarLayer(scrollbarGraphicsLayer);
             return;
         }
@@ -365,7 +365,7 @@
             OwnPtr<WebScrollbarLayer> webScrollbarLayer;
             if (settings->useSolidColorScrollbars()) {
                 ASSERT(RuntimeEnabledFeatures::overlayScrollbarsEnabled());
-                webScrollbarLayer = createSolidColorScrollbarLayer(orientation, scrollbar->theme()->thumbThickness(scrollbar), scrollbar->theme()->trackPosition(scrollbar), scrollableArea->shouldPlaceVerticalScrollbarOnLeft());
+                webScrollbarLayer = createSolidColorScrollbarLayer(orientation, scrollbar.theme().thumbThickness(scrollbar), scrollbar.theme().trackPosition(scrollbar), scrollableArea->shouldPlaceVerticalScrollbarOnLeft());
             } else {
                 webScrollbarLayer = createScrollbarLayer(scrollbar, m_page->deviceScaleFactor());
             }
@@ -377,7 +377,7 @@
 
         // Root layer non-overlay scrollbars should be marked opaque to disable
         // blending.
-        bool isOpaqueScrollbar = !scrollbar->isOverlayScrollbar();
+        bool isOpaqueScrollbar = !scrollbar.isOverlayScrollbar();
         scrollbarGraphicsLayer->setContentsOpaque(isMainFrame && isOpaqueScrollbar);
     } else
         removeWebScrollbarLayer(scrollableArea, orientation);
@@ -982,7 +982,7 @@
     if (!frameView)
         return;
 
-    frameView->scrollAnimator()->handleWheelEventPhase(phase);
+    frameView->scrollAnimator().handleWheelEventPhase(phase);
 }
 #endif
 
diff --git a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
index ef37cf3..0bd22707 100644
--- a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
+++ b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
@@ -161,14 +161,15 @@
     m_destRect.intersect(clipRect);
 }
 
-// When we match the destination rect in a dimension, we snap the same way. Otherwise
-// we floor to avoid growing our tile size. Often these tiles are from a sprite map,
-// and bleeding adjactent sprites is visually worse than clipping the intenteded one.
+// When we match the sub-pixel fraction of the destination rect in a dimension, we
+// snap the same way. Otherwise we floor to avoid growing our tile size. Often these
+// tiles are from a sprite map, and bleeding adjactent sprites is visually worse
+// than clipping the intenteded one.
 static LayoutSize applySubPixelHeuristicToImageSize(const LayoutSize& size, const LayoutRect& destination)
 {
     LayoutSize snappedSize = LayoutSize(
-        size.width() == destination.width() ? destination.pixelSnappedWidth() : size.width().floor(),
-        size.height() == destination.height() ? destination.pixelSnappedHeight() : size.height().floor());
+        size.width().fraction() == destination.width().fraction() ? snapSizeToPixel(size.width(), destination.x()) : size.width().floor(),
+        size.height().fraction() == destination.height().fraction() ? snapSizeToPixel(size.height(), destination.y()) : size.height().floor());
     return snappedSize;
 }
 
@@ -265,7 +266,10 @@
         positioningAreaSize = destRect().size();
     }
 
-    LayoutSize fillTileSize = calculateFillTileSize(positioningBox, fillLayer, positioningAreaSize);
+    LayoutSize fillTileSize(calculateFillTileSize(positioningBox, fillLayer, positioningAreaSize));
+    // It's necessary to apply the heuristic here prior to any further calculations to avoid
+    // incorrectly using sub-pixel values that won't be present in the painted tile.
+    fillTileSize = applySubPixelHeuristicToImageSize(fillTileSize, m_destRect);
     setTileSize(fillTileSize);
     setImageContainerSize(fillTileSize);
 
diff --git a/third_party/WebKit/Source/core/paint/BlockPainter.cpp b/third_party/WebKit/Source/core/paint/BlockPainter.cpp
index bd5b0fc..e51b709 100644
--- a/third_party/WebKit/Source/core/paint/BlockPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/BlockPainter.cpp
@@ -80,7 +80,7 @@
             clipRect.moveBy(paintOffset);
             clipRecorder.emplace(*paintInfo.context, m_layoutBlock, DisplayItem::ClipScrollbarsToBoxBounds, clipRect);
         }
-        ScrollableAreaPainter(*m_layoutBlock.layer()->scrollableArea()).paintOverflowControls(paintInfo.context, roundedIntPoint(paintOffset), paintInfo.cullRect(), false /* paintingOverlayControls */);
+        ScrollableAreaPainter(*m_layoutBlock.layer()->scrollableArea()).paintOverflowControls(*paintInfo.context, roundedIntPoint(paintOffset), paintInfo.cullRect(), false /* paintingOverlayControls */);
     }
 }
 
diff --git a/third_party/WebKit/Source/core/paint/CompositingRecorder.cpp b/third_party/WebKit/Source/core/paint/CompositingRecorder.cpp
index 3776330..b13e876 100644
--- a/third_party/WebKit/Source/core/paint/CompositingRecorder.cpp
+++ b/third_party/WebKit/Source/core/paint/CompositingRecorder.cpp
@@ -13,7 +13,7 @@
 
 namespace blink {
 
-CompositingRecorder::CompositingRecorder(GraphicsContext& graphicsContext, const DisplayItemClientWrapper& client, const SkXfermode::Mode xferMode, const float opacity, const FloatRect* bounds, ColorFilter colorFilter)
+CompositingRecorder::CompositingRecorder(GraphicsContext& graphicsContext, const DisplayItemClient& client, const SkXfermode::Mode xferMode, const float opacity, const FloatRect* bounds, ColorFilter colorFilter)
     : m_client(client)
     , m_graphicsContext(graphicsContext)
 {
@@ -25,12 +25,12 @@
     endCompositing(m_graphicsContext, m_client);
 }
 
-void CompositingRecorder::beginCompositing(GraphicsContext& graphicsContext, const DisplayItemClientWrapper& client, const SkXfermode::Mode xferMode, const float opacity, const FloatRect* bounds, ColorFilter colorFilter)
+void CompositingRecorder::beginCompositing(GraphicsContext& graphicsContext, const DisplayItemClient& client, const SkXfermode::Mode xferMode, const float opacity, const FloatRect* bounds, ColorFilter colorFilter)
 {
     graphicsContext.paintController().createAndAppend<BeginCompositingDisplayItem>(client, xferMode, opacity, bounds, colorFilter);
 }
 
-void CompositingRecorder::endCompositing(GraphicsContext& graphicsContext, const DisplayItemClientWrapper& client)
+void CompositingRecorder::endCompositing(GraphicsContext& graphicsContext, const DisplayItemClient& client)
 {
     graphicsContext.paintController().endItem<EndCompositingDisplayItem>(client);
 }
diff --git a/third_party/WebKit/Source/core/paint/CompositingRecorder.h b/third_party/WebKit/Source/core/paint/CompositingRecorder.h
index 8bc6a27..f6b9c97 100644
--- a/third_party/WebKit/Source/core/paint/CompositingRecorder.h
+++ b/third_party/WebKit/Source/core/paint/CompositingRecorder.h
@@ -19,17 +19,17 @@
 class CompositingRecorder {
     USING_FAST_MALLOC(CompositingRecorder);
 public:
-    CompositingRecorder(GraphicsContext&, const DisplayItemClientWrapper&, const SkXfermode::Mode, const float opacity, const FloatRect* bounds = 0, ColorFilter = ColorFilterNone);
+    CompositingRecorder(GraphicsContext&, const DisplayItemClient&, const SkXfermode::Mode, const float opacity, const FloatRect* bounds = 0, ColorFilter = ColorFilterNone);
 
     ~CompositingRecorder();
 
     // FIXME: These helpers only exist to ease the transition to slimming paint
     //        and should be removed once slimming paint is enabled by default.
-    static void beginCompositing(GraphicsContext&, const DisplayItemClientWrapper&, const SkXfermode::Mode, const float opacity, const FloatRect* bounds = 0, ColorFilter = ColorFilterNone);
-    static void endCompositing(GraphicsContext&, const DisplayItemClientWrapper&);
+    static void beginCompositing(GraphicsContext&, const DisplayItemClient&, const SkXfermode::Mode, const float opacity, const FloatRect* bounds = 0, ColorFilter = ColorFilterNone);
+    static void endCompositing(GraphicsContext&, const DisplayItemClient&);
 
 private:
-    DisplayItemClientWrapper m_client;
+    const DisplayItemClient& m_client;
     GraphicsContext& m_graphicsContext;
 };
 
diff --git a/third_party/WebKit/Source/core/paint/FloatClipRecorder.cpp b/third_party/WebKit/Source/core/paint/FloatClipRecorder.cpp
index d4cd0ecc..735f15e 100644
--- a/third_party/WebKit/Source/core/paint/FloatClipRecorder.cpp
+++ b/third_party/WebKit/Source/core/paint/FloatClipRecorder.cpp
@@ -11,7 +11,7 @@
 
 namespace blink {
 
-FloatClipRecorder::FloatClipRecorder(GraphicsContext& context, const DisplayItemClientWrapper& client, PaintPhase paintPhase, const FloatRect& clipRect)
+FloatClipRecorder::FloatClipRecorder(GraphicsContext& context, const DisplayItemClient& client, PaintPhase paintPhase, const FloatRect& clipRect)
     : m_context(context)
     , m_client(client)
     , m_clipType(DisplayItem::paintPhaseToFloatClipType(paintPhase))
diff --git a/third_party/WebKit/Source/core/paint/FloatClipRecorder.h b/third_party/WebKit/Source/core/paint/FloatClipRecorder.h
index 2254aba8..b6122a8 100644
--- a/third_party/WebKit/Source/core/paint/FloatClipRecorder.h
+++ b/third_party/WebKit/Source/core/paint/FloatClipRecorder.h
@@ -17,13 +17,13 @@
     USING_FAST_MALLOC(FloatClipRecorder);
     WTF_MAKE_NONCOPYABLE(FloatClipRecorder);
 public:
-    FloatClipRecorder(GraphicsContext&, const DisplayItemClientWrapper&, PaintPhase, const FloatRect&);
+    FloatClipRecorder(GraphicsContext&, const DisplayItemClient&, PaintPhase, const FloatRect&);
 
     ~FloatClipRecorder();
 
 private:
     GraphicsContext& m_context;
-    DisplayItemClientWrapper m_client;
+    const DisplayItemClient& m_client;
     DisplayItem::Type m_clipType;
 };
 
diff --git a/third_party/WebKit/Source/core/paint/FramePainter.cpp b/third_party/WebKit/Source/core/paint/FramePainter.cpp
index 0f22277..9ae45d2 100644
--- a/third_party/WebKit/Source/core/paint/FramePainter.cpp
+++ b/third_party/WebKit/Source/core/paint/FramePainter.cpp
@@ -27,7 +27,7 @@
 
 bool FramePainter::s_inPaintContents = false;
 
-void FramePainter::paint(GraphicsContext* context, const GlobalPaintFlags globalPaintFlags, const CullRect& rect)
+void FramePainter::paint(GraphicsContext& context, const GlobalPaintFlags globalPaintFlags, const CullRect& rect)
 {
     frameView().notifyPageThatContentAreaWillPaint();
 
@@ -36,10 +36,10 @@
     documentDirtyRect.intersect(visibleAreaWithoutScrollbars);
 
     if (!documentDirtyRect.isEmpty()) {
-        TransformRecorder transformRecorder(*context, *frameView().layoutView(),
+        TransformRecorder transformRecorder(context, *frameView().layoutView(),
             AffineTransform::translation(frameView().x() - frameView().scrollX(), frameView().y() - frameView().scrollY()));
 
-        ClipRecorder recorder(*context, *frameView().layoutView(), DisplayItem::ClipFrameToVisibleContentRect, LayoutRect(frameView().visibleContentRect()));
+        ClipRecorder recorder(context, *frameView().layoutView(), DisplayItem::ClipFrameToVisibleContentRect, LayoutRect(frameView().visibleContentRect()));
 
         documentDirtyRect.moveBy(-frameView().location() + frameView().scrollPosition());
         paintContents(context, globalPaintFlags, documentDirtyRect);
@@ -52,16 +52,16 @@
         scrollViewDirtyRect.intersect(visibleAreaWithScrollbars);
         scrollViewDirtyRect.moveBy(-frameView().location());
 
-        TransformRecorder transformRecorder(*context, *frameView().layoutView(),
+        TransformRecorder transformRecorder(context, *frameView().layoutView(),
             AffineTransform::translation(frameView().x(), frameView().y()));
 
-        ClipRecorder recorder(*context, *frameView().layoutView(), DisplayItem::ClipFrameScrollbars, LayoutRect(IntPoint(), visibleAreaWithScrollbars.size()));
+        ClipRecorder recorder(context, *frameView().layoutView(), DisplayItem::ClipFrameScrollbars, LayoutRect(IntPoint(), visibleAreaWithScrollbars.size()));
 
         paintScrollbars(context, scrollViewDirtyRect);
     }
 }
 
-void FramePainter::paintContents(GraphicsContext* context, const GlobalPaintFlags globalPaintFlags, const IntRect& rect)
+void FramePainter::paintContents(GraphicsContext& context, const GlobalPaintFlags globalPaintFlags, const IntRect& rect)
 {
     Document* document = frameView().frame().document();
 
@@ -80,9 +80,9 @@
     else
         fillWithRed = true;
 
-    if (fillWithRed && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*context, *frameView().layoutView(), DisplayItem::DebugRedFill, LayoutPoint())) {
+    if (fillWithRed && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, *frameView().layoutView(), DisplayItem::DebugRedFill, LayoutPoint())) {
         IntRect contentRect(IntPoint(), frameView().contentsSize());
-        LayoutObjectDrawingRecorder drawingRecorder(*context, *frameView().layoutView(), DisplayItem::DebugRedFill, contentRect, LayoutPoint());
+        LayoutObjectDrawingRecorder drawingRecorder(context, *frameView().layoutView(), DisplayItem::DebugRedFill, contentRect, LayoutPoint());
     }
 #endif
 
@@ -123,12 +123,12 @@
     PaintLayerPainter layerPainter(*rootLayer);
 
     float deviceScaleFactor = blink::deviceScaleFactor(rootLayer->layoutObject()->frame());
-    context->setDeviceScaleFactor(deviceScaleFactor);
+    context.setDeviceScaleFactor(deviceScaleFactor);
 
-    layerPainter.paint(context, LayoutRect(rect), localPaintFlags, layoutObject);
+    layerPainter.paint(&context, LayoutRect(rect), localPaintFlags, layoutObject);
 
     if (rootLayer->containsDirtyOverlayScrollbars())
-        layerPainter.paintOverlayScrollbars(context, LayoutRect(rect), localPaintFlags, layoutObject);
+        layerPainter.paintOverlayScrollbars(&context, LayoutRect(rect), localPaintFlags, layoutObject);
 
     frameView().setIsPainting(false);
 
@@ -143,15 +143,15 @@
         s_inPaintContents = false;
     }
 
-    InspectorInstrumentation::didPaint(layoutView, 0, context, LayoutRect(rect));
+    InspectorInstrumentation::didPaint(layoutView, 0, &context, LayoutRect(rect));
 }
 
-void FramePainter::paintScrollbars(GraphicsContext* context, const IntRect& rect)
+void FramePainter::paintScrollbars(GraphicsContext& context, const IntRect& rect)
 {
     if (frameView().horizontalScrollbar() && !frameView().layerForHorizontalScrollbar())
-        paintScrollbar(context, frameView().horizontalScrollbar(), rect);
+        paintScrollbar(context, *frameView().horizontalScrollbar(), rect);
     if (frameView().verticalScrollbar() && !frameView().layerForVerticalScrollbar())
-        paintScrollbar(context, frameView().verticalScrollbar(), rect);
+        paintScrollbar(context, *frameView().verticalScrollbar(), rect);
 
     if (frameView().layerForScrollCorner())
         return;
@@ -159,32 +159,32 @@
     paintScrollCorner(context, frameView().scrollCornerRect());
 }
 
-void FramePainter::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
+void FramePainter::paintScrollCorner(GraphicsContext& context, const IntRect& cornerRect)
 {
     if (frameView().scrollCorner()) {
         bool needsBackground = frameView().frame().isMainFrame();
-        if (needsBackground && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*context, *frameView().layoutView(), DisplayItem::ScrollbarCorner, LayoutPoint())) {
-            LayoutObjectDrawingRecorder drawingRecorder(*context, *frameView().layoutView(), DisplayItem::ScrollbarCorner, FloatRect(cornerRect), LayoutPoint());
-            context->fillRect(cornerRect, frameView().baseBackgroundColor());
+        if (needsBackground && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, *frameView().layoutView(), DisplayItem::ScrollbarCorner, LayoutPoint())) {
+            LayoutObjectDrawingRecorder drawingRecorder(context, *frameView().layoutView(), DisplayItem::ScrollbarCorner, FloatRect(cornerRect), LayoutPoint());
+            context.fillRect(cornerRect, frameView().baseBackgroundColor());
 
         }
         ScrollbarPainter::paintIntoRect(*frameView().scrollCorner(), context, cornerRect.location(), LayoutRect(cornerRect));
         return;
     }
 
-    ScrollbarTheme::theme()->paintScrollCorner(context, *frameView().layoutView(), cornerRect);
+    ScrollbarTheme::theme().paintScrollCorner(context, *frameView().layoutView(), cornerRect);
 }
 
-void FramePainter::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const IntRect& rect)
+void FramePainter::paintScrollbar(GraphicsContext& context, Scrollbar& bar, const IntRect& rect)
 {
-    bool needsBackground = bar->isCustomScrollbar() && frameView().frame().isMainFrame();
+    bool needsBackground = bar.isCustomScrollbar() && frameView().frame().isMainFrame();
     if (needsBackground) {
-        IntRect toFill = bar->frameRect();
+        IntRect toFill = bar.frameRect();
         toFill.intersect(rect);
-        context->fillRect(toFill, frameView().baseBackgroundColor());
+        context.fillRect(toFill, frameView().baseBackgroundColor());
     }
 
-    bar->paint(context, CullRect(rect));
+    bar.paint(context, CullRect(rect));
 }
 
 const FrameView& FramePainter::frameView()
diff --git a/third_party/WebKit/Source/core/paint/FramePainter.h b/third_party/WebKit/Source/core/paint/FramePainter.h
index 6dac65a..d1500757 100644
--- a/third_party/WebKit/Source/core/paint/FramePainter.h
+++ b/third_party/WebKit/Source/core/paint/FramePainter.h
@@ -22,13 +22,13 @@
 public:
     explicit FramePainter(const FrameView& frameView) : m_frameView(&frameView) { }
 
-    void paint(GraphicsContext*, const GlobalPaintFlags, const CullRect&);
-    void paintScrollbars(GraphicsContext*, const IntRect&);
-    void paintContents(GraphicsContext*, const GlobalPaintFlags, const IntRect&);
-    void paintScrollCorner(GraphicsContext*, const IntRect& cornerRect);
+    void paint(GraphicsContext&, const GlobalPaintFlags, const CullRect&);
+    void paintScrollbars(GraphicsContext&, const IntRect&);
+    void paintContents(GraphicsContext&, const GlobalPaintFlags, const IntRect&);
+    void paintScrollCorner(GraphicsContext&, const IntRect& cornerRect);
 
 private:
-    void paintScrollbar(GraphicsContext*, Scrollbar*, const IntRect&);
+    void paintScrollbar(GraphicsContext&, Scrollbar&, const IntRect&);
 
     const FrameView& frameView();
 
diff --git a/third_party/WebKit/Source/core/paint/LayoutObjectDrawingRecorder.h b/third_party/WebKit/Source/core/paint/LayoutObjectDrawingRecorder.h
index cadb9b8..c9e0e9d 100644
--- a/third_party/WebKit/Source/core/paint/LayoutObjectDrawingRecorder.h
+++ b/third_party/WebKit/Source/core/paint/LayoutObjectDrawingRecorder.h
@@ -70,7 +70,7 @@
         if (layoutObject.paintOffsetChanged(paintOffset))
             paintController.invalidatePaintOffset(layoutObject);
         else
-            ASSERT(!paintController.paintOffsetWasInvalidated(layoutObject.displayItemClient()) || !paintController.clientCacheIsValid(layoutObject.displayItemClient()));
+            ASSERT(!paintController.paintOffsetWasInvalidated(layoutObject) || !paintController.clientCacheIsValid(layoutObject));
 
         layoutObject.mutableForPainting().setPreviousPaintOffset(paintOffset);
     }
diff --git a/third_party/WebKit/Source/core/paint/ObjectPaintProperties.h b/third_party/WebKit/Source/core/paint/ObjectPaintProperties.h
index 0148768e..6048057 100644
--- a/third_party/WebKit/Source/core/paint/ObjectPaintProperties.h
+++ b/third_party/WebKit/Source/core/paint/ObjectPaintProperties.h
@@ -5,6 +5,7 @@
 #ifndef ObjectPaintProperties_h
 #define ObjectPaintProperties_h
 
+#include "platform/graphics/paint/ClipPaintPropertyNode.h"
 #include "platform/graphics/paint/EffectPaintPropertyNode.h"
 #include "platform/graphics/paint/TransformPaintPropertyNode.h"
 #include "wtf/PassOwnPtr.h"
@@ -30,10 +31,11 @@
         PassRefPtr<TransformPaintPropertyNode> paintOffsetTranslation,
         PassRefPtr<TransformPaintPropertyNode> transform,
         PassRefPtr<EffectPaintPropertyNode> effect,
+        PassRefPtr<ClipPaintPropertyNode> overflowClip,
         PassRefPtr<TransformPaintPropertyNode> perspective,
         PassRefPtr<TransformPaintPropertyNode> scrollTranslation)
     {
-        return adoptPtr(new ObjectPaintProperties(paintOffsetTranslation, transform, effect, perspective, scrollTranslation));
+        return adoptPtr(new ObjectPaintProperties(paintOffsetTranslation, transform, effect, overflowClip, perspective, scrollTranslation));
     }
 
     // The hierarchy of transform subtree created by a LayoutObject.
@@ -53,22 +55,27 @@
 
     EffectPaintPropertyNode* effect() const { return m_effect.get(); }
 
+    ClipPaintPropertyNode* overflowClip() const { return m_overflowClip.get(); }
+
 private:
     ObjectPaintProperties(
         PassRefPtr<TransformPaintPropertyNode> paintOffsetTranslation,
         PassRefPtr<TransformPaintPropertyNode> transform,
         PassRefPtr<EffectPaintPropertyNode> effect,
+        PassRefPtr<ClipPaintPropertyNode> overflowClip,
         PassRefPtr<TransformPaintPropertyNode> perspective,
         PassRefPtr<TransformPaintPropertyNode> scrollTranslation)
         : m_paintOffsetTranslation(paintOffsetTranslation)
         , m_transform(transform)
         , m_effect(effect)
+        , m_overflowClip(overflowClip)
         , m_perspective(perspective)
         , m_scrollTranslation(scrollTranslation) { }
 
     RefPtr<TransformPaintPropertyNode> m_paintOffsetTranslation;
     RefPtr<TransformPaintPropertyNode> m_transform;
     RefPtr<EffectPaintPropertyNode> m_effect;
+    RefPtr<ClipPaintPropertyNode> m_overflowClip;
     RefPtr<TransformPaintPropertyNode> m_perspective;
     RefPtr<TransformPaintPropertyNode> m_scrollTranslation;
 };
diff --git a/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.h b/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.h
index 117de103..b9d61393 100644
--- a/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.h
+++ b/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.h
@@ -109,7 +109,7 @@
 
 class TestDisplayItem final : public DisplayItem {
 public:
-    TestDisplayItem(const DisplayItemClientWrapper& client, Type type) : DisplayItem(client, type, sizeof(*this)) { }
+    TestDisplayItem(const DisplayItemClient& client, Type type) : DisplayItem(client, type, sizeof(*this)) { }
 
     void replay(GraphicsContext&) const final { ASSERT_NOT_REACHED(); }
     void appendToWebDisplayItemList(const IntRect&, WebDisplayItemList*) const final { ASSERT_NOT_REACHED(); }
diff --git a/third_party/WebKit/Source/core/paint/PaintInvalidationCapableScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintInvalidationCapableScrollableArea.cpp
index 8b1831a..96661d27 100644
--- a/third_party/WebKit/Source/core/paint/PaintInvalidationCapableScrollableArea.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintInvalidationCapableScrollableArea.cpp
@@ -12,49 +12,87 @@
 #include "core/layout/LayoutScrollbarPart.h"
 #include "core/layout/PaintInvalidationState.h"
 #include "core/paint/PaintLayer.h"
+#include "platform/graphics/GraphicsLayer.h"
 
 namespace blink {
 
-void PaintInvalidationCapableScrollableArea::willRemoveScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
+void PaintInvalidationCapableScrollableArea::willRemoveScrollbar(Scrollbar& scrollbar, ScrollbarOrientation orientation)
 {
-    if (!scrollbar->isCustomScrollbar()
+    if (!scrollbar.isCustomScrollbar()
         && !(orientation == HorizontalScrollbar ? layerForHorizontalScrollbar() : layerForVerticalScrollbar()))
-        boxForScrollControlPaintInvalidation().invalidateDisplayItemClient(*scrollbar);
+        boxForScrollControlPaintInvalidation().invalidateDisplayItemClient(scrollbar);
 
     ScrollableArea::willRemoveScrollbar(scrollbar, orientation);
 }
 
-// Returns true if the scroll control is invalidated.
-static bool invalidatePaintOfScrollControlIfNeeded(const IntRect& scrollControlRect, LayoutRect& previousPaintInvalidationRect, bool needsPaintInvalidation, LayoutBox& box, const PaintInvalidationState& paintInvalidationState, const LayoutBoxModelObject& paintInvalidationContainer)
+static LayoutRect scrollControlPaintInvalidationRect(const IntRect& scrollControlRect, const LayoutBox& box, const PaintInvalidationState& paintInvalidationState, const LayoutBoxModelObject& paintInvalidationContainer)
 {
     LayoutRect paintInvalidationRect(scrollControlRect);
     if (!paintInvalidationRect.isEmpty())
         PaintLayer::mapRectToPaintInvalidationBacking(&box, &paintInvalidationContainer, paintInvalidationRect, &paintInvalidationState);
+    return paintInvalidationRect;
+}
 
-    if (paintInvalidationRect != previousPaintInvalidationRect) {
+// Returns true if the scroll control is invalidated.
+static bool invalidatePaintOfScrollControlIfNeeded(const LayoutRect& newPaintInvalidationRect, const LayoutRect& previousPaintInvalidationRect, bool needsPaintInvalidation, LayoutBox& box, const LayoutBoxModelObject& paintInvalidationContainer)
+{
+    bool shouldInvalidateNewRect = needsPaintInvalidation;
+    if (newPaintInvalidationRect != previousPaintInvalidationRect) {
         box.invalidatePaintUsingContainer(paintInvalidationContainer, previousPaintInvalidationRect, PaintInvalidationScroll);
-        previousPaintInvalidationRect = paintInvalidationRect;
-        needsPaintInvalidation = true;
+        shouldInvalidateNewRect = true;
     }
-
-    if (needsPaintInvalidation) {
-        box.invalidatePaintUsingContainer(paintInvalidationContainer, paintInvalidationRect, PaintInvalidationScroll);
+    if (shouldInvalidateNewRect) {
+        box.invalidatePaintUsingContainer(paintInvalidationContainer, newPaintInvalidationRect, PaintInvalidationScroll);
+        box.enclosingLayer()->setNeedsRepaint();
         return true;
     }
-
     return false;
 }
 
-static void invalidatePaintOfScrollbarIfNeeded(Scrollbar* scrollbar, GraphicsLayer* scrollbarGraphicsLayer, LayoutRect& previousPaintInvalidationRect, bool needsPaintInvalidation, LayoutBox& box, const PaintInvalidationState& paintInvalidationState, const LayoutBoxModelObject& paintInvalidationContainer)
+static void invalidatePaintOfScrollbarIfNeeded(Scrollbar* scrollbar, GraphicsLayer* graphicsLayer, bool& previouslyWasOverlay, LayoutRect& previousPaintInvalidationRect, bool needsPaintInvalidationArg, LayoutBox& box, const PaintInvalidationState& paintInvalidationState, const LayoutBoxModelObject& paintInvalidationContainer)
 {
-    IntRect scrollbarRect = scrollbar && !scrollbarGraphicsLayer ? scrollbar->frameRect() : IntRect();
-    if (!invalidatePaintOfScrollControlIfNeeded(scrollbarRect, previousPaintInvalidationRect, needsPaintInvalidation, box, paintInvalidationState, paintInvalidationContainer))
-        return;
-    if (!scrollbar)
+    bool isOverlay = scrollbar && scrollbar->isOverlayScrollbar();
+
+    // Calculate paint invalidation rect of the scrollbar, except overlay composited scrollbars because we invalidate the graphics layer only.
+    LayoutRect newPaintInvalidationRect;
+    if (scrollbar && !(graphicsLayer && isOverlay))
+        newPaintInvalidationRect = scrollControlPaintInvalidationRect(scrollbar->frameRect(), box, paintInvalidationState, paintInvalidationContainer);
+
+    bool needsPaintInvalidation = needsPaintInvalidationArg;
+    if (graphicsLayer && needsPaintInvalidation) {
+        graphicsLayer->setNeedsDisplay();
+        graphicsLayer->setContentsNeedsDisplay();
+        // If the scrollbar needs paint invalidation but didn't change location/size or the scrollbar is an
+        // overlay scrollbar (paint invalidation rect is empty), invalidating the graphics layer is enough.
+        // Otherwise invalidatePaintOfScrollControlIfNeeded() below will invalidate the old and new location
+        // of the scrollbar on the box's paint invalidation container to ensure newly expanded/shrunk areas
+        // of the box to be invalidated.
+        needsPaintInvalidation = false;
+    }
+
+    // Invalidate the box's display item client if the box's padding box size is affected by change of the
+    // non-overlay scrollbar width. We detect change of paint invalidation rect size instead of change of
+    // scrollbar width change, which may have some false-positives (e.g. the scrollbar changed length but
+    // not width) but won't invalidate more than expected because in the false-positive case the box must
+    // have changed size and have been invalidated.
+    LayoutSize newScrollbarUsedSpaceInBox;
+    if (!isOverlay)
+        newScrollbarUsedSpaceInBox = newPaintInvalidationRect.size();
+    LayoutSize previousScrollbarUsedSpaceInBox;
+    if (!previouslyWasOverlay)
+        previousScrollbarUsedSpaceInBox= previousPaintInvalidationRect.size();
+    if (newScrollbarUsedSpaceInBox != previousScrollbarUsedSpaceInBox)
+        paintInvalidationContainer.invalidateDisplayItemClientOnBacking(box, PaintInvalidationScroll, nullptr);
+
+    bool invalidated = invalidatePaintOfScrollControlIfNeeded(newPaintInvalidationRect, previousPaintInvalidationRect, needsPaintInvalidation, box, paintInvalidationContainer);
+
+    previousPaintInvalidationRect = newPaintInvalidationRect;
+    previouslyWasOverlay = isOverlay;
+
+    if (!invalidated || !scrollbar || graphicsLayer)
         return;
 
     paintInvalidationContainer.invalidateDisplayItemClientOnBacking(*scrollbar, PaintInvalidationScroll, &previousPaintInvalidationRect);
-    box.enclosingLayer()->setNeedsRepaint();
     if (scrollbar->isCustomScrollbar())
         toLayoutScrollbar(scrollbar)->invalidateDisplayItemClientsOfScrollbarParts(paintInvalidationContainer, previousPaintInvalidationRect);
 }
@@ -62,18 +100,12 @@
 void PaintInvalidationCapableScrollableArea::invalidatePaintOfScrollControlsIfNeeded(const PaintInvalidationState& paintInvalidationState, const LayoutBoxModelObject& paintInvalidationContainer)
 {
     LayoutBox& box = boxForScrollControlPaintInvalidation();
-    LayoutRect oldRect = m_horizontalScrollbarPreviousPaintInvalidationRect;
-    invalidatePaintOfScrollbarIfNeeded(horizontalScrollbar(), layerForHorizontalScrollbar(), m_horizontalScrollbarPreviousPaintInvalidationRect, horizontalScrollbarNeedsPaintInvalidation(), box, paintInvalidationState, paintInvalidationContainer);
-    bool scrollbarGeometryChanged = oldRect != m_horizontalScrollbarPreviousPaintInvalidationRect;
+    invalidatePaintOfScrollbarIfNeeded(horizontalScrollbar(), layerForHorizontalScrollbar(), m_horizontalScrollbarPreviouslyWasOverlay, m_horizontalScrollbarPreviousPaintInvalidationRect, horizontalScrollbarNeedsPaintInvalidation(), box, paintInvalidationState, paintInvalidationContainer);
+    invalidatePaintOfScrollbarIfNeeded(verticalScrollbar(), layerForVerticalScrollbar(), m_verticalScrollbarPreviouslyWasOverlay, m_verticalScrollbarPreviousPaintInvalidationRect, verticalScrollbarNeedsPaintInvalidation(), box, paintInvalidationState, paintInvalidationContainer);
 
-    oldRect = m_verticalScrollbarPreviousPaintInvalidationRect;
-    invalidatePaintOfScrollbarIfNeeded(verticalScrollbar(), layerForVerticalScrollbar(), m_verticalScrollbarPreviousPaintInvalidationRect, verticalScrollbarNeedsPaintInvalidation(), box, paintInvalidationState, paintInvalidationContainer);
-    scrollbarGeometryChanged |= oldRect != m_verticalScrollbarPreviousPaintInvalidationRect;
-
-    if (scrollbarGeometryChanged)
-        paintInvalidationContainer.invalidateDisplayItemClientOnBacking(box, PaintInvalidationScroll, nullptr);
-
-    if (invalidatePaintOfScrollControlIfNeeded(scrollCornerRect(), m_scrollCornerPreviousPaintInvalidationRect, scrollCornerNeedsPaintInvalidation(), box, paintInvalidationState, paintInvalidationContainer)) {
+    LayoutRect scrollCornerPaintInvalidationRect = scrollControlPaintInvalidationRect(scrollCornerRect(), box, paintInvalidationState, paintInvalidationContainer);
+    if (invalidatePaintOfScrollControlIfNeeded(scrollCornerPaintInvalidationRect, m_scrollCornerPreviousPaintInvalidationRect, scrollCornerNeedsPaintInvalidation(), box, paintInvalidationContainer)) {
+        m_scrollCornerPreviousPaintInvalidationRect = scrollCornerPaintInvalidationRect;
         if (LayoutScrollbarPart* scrollCorner = this->scrollCorner())
             scrollCorner->invalidateDisplayItemClientsIncludingNonCompositingDescendants(&paintInvalidationContainer, PaintInvalidationScroll, &m_scrollCornerPreviousPaintInvalidationRect);
         if (LayoutScrollbarPart* resizer = this->resizer())
@@ -83,4 +115,11 @@
     clearNeedsPaintInvalidationForScrollControls();
 }
 
+void PaintInvalidationCapableScrollableArea::clearPreviousPaintInvalidationRects()
+{
+    m_horizontalScrollbarPreviousPaintInvalidationRect = LayoutRect();
+    m_verticalScrollbarPreviousPaintInvalidationRect = LayoutRect();
+    m_scrollCornerPreviousPaintInvalidationRect = LayoutRect();
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/PaintInvalidationCapableScrollableArea.h b/third_party/WebKit/Source/core/paint/PaintInvalidationCapableScrollableArea.h
index 1120378d..01ec39e 100644
--- a/third_party/WebKit/Source/core/paint/PaintInvalidationCapableScrollableArea.h
+++ b/third_party/WebKit/Source/core/paint/PaintInvalidationCapableScrollableArea.h
@@ -21,14 +21,24 @@
 // TODO(wangxianzhu): Combine this into PaintLayerScrollableArea when root-layer-scrolls launches.
 class CORE_EXPORT PaintInvalidationCapableScrollableArea : public ScrollableArea {
 public:
-    void willRemoveScrollbar(Scrollbar*, ScrollbarOrientation) override;
+    PaintInvalidationCapableScrollableArea()
+        : m_horizontalScrollbarPreviouslyWasOverlay(false)
+        , m_verticalScrollbarPreviouslyWasOverlay(false) { }
+
+    void willRemoveScrollbar(Scrollbar&, ScrollbarOrientation) override;
+
     void invalidatePaintOfScrollControlsIfNeeded(const PaintInvalidationState&, const LayoutBoxModelObject& paintInvalidationContainer);
 
+    // Should be called when the previous paint invalidation rects are no longer valid.
+    void clearPreviousPaintInvalidationRects();
+
 private:
     virtual LayoutBox& boxForScrollControlPaintInvalidation() const = 0;
     virtual LayoutScrollbarPart* scrollCorner() const = 0;
     virtual LayoutScrollbarPart* resizer() const = 0;
 
+    bool m_horizontalScrollbarPreviouslyWasOverlay;
+    bool m_verticalScrollbarPreviouslyWasOverlay;
     LayoutRect m_horizontalScrollbarPreviousPaintInvalidationRect;
     LayoutRect m_verticalScrollbarPreviousPaintInvalidationRect;
     LayoutRect m_scrollCornerPreviousPaintInvalidationRect;
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index df78365..652637c 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -2165,7 +2165,7 @@
 
     // The root layer is always just the size of the document.
     if (isRootLayer())
-        return LayoutRect(m_layoutObject->view()->unscaledDocumentRect());
+        return LayoutRect(m_layoutObject->view()->documentRect());
 
     // The layer created for the LayoutFlowThread is just a helper for painting and hit-testing,
     // and should not contribute to the bounding box. The LayoutMultiColumnSets will contribute
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.h b/third_party/WebKit/Source/core/paint/PaintLayer.h
index b49b421e..d2d6ad4 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.h
@@ -156,13 +156,13 @@
 // A good example of this is PaintLayerScrollableArea, which can only happen
 // be instanciated for LayoutBoxes. With the current design, it's hard to know
 // that by reading the code.
-class CORE_EXPORT PaintLayer {
+class CORE_EXPORT PaintLayer : public DisplayItemClient {
     WTF_MAKE_NONCOPYABLE(PaintLayer);
 public:
     PaintLayer(LayoutBoxModelObject*, PaintLayerType);
     ~PaintLayer();
 
-    String debugName() const;
+    String debugName() const final;
 
     LayoutBoxModelObject* layoutObject() const { return m_layoutObject; }
     LayoutBox* layoutBox() const { return m_layoutObject && m_layoutObject->isBox() ? toLayoutBox(m_layoutObject) : 0; }
@@ -618,9 +618,6 @@
     ClipRects* previousPaintingClipRects() const { return m_previousPaintingClipRects.get(); }
     void setPreviousPaintingClipRects(ClipRects* clipRects) { m_previousPaintingClipRects = clipRects; }
 
-    // For subsequence display items.
-    DisplayItemClient displayItemClient() const { return toDisplayItemClient(this); }
-
     PaintTiming* paintTiming();
 
 private:
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
index edaa4dd..67d07a2 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
@@ -262,7 +262,7 @@
     LayoutRect rootRelativeBounds;
     bool rootRelativeBoundsComputed = false;
 
-    if (paintingInfo.ancestorHasClipPathClipping && m_paintLayer.layoutObject()->style()->position() != StaticPosition)
+    if (paintingInfo.ancestorHasClipPathClipping && m_paintLayer.layoutObject()->isPositioned())
         UseCounter::count(m_paintLayer.layoutObject()->document(), UseCounter::ClipPathOfPositionedElement);
 
     // These helpers output clip and compositing operations using a RAII pattern. Stack-allocated-varibles are destructed in the reverse order of construction,
@@ -461,7 +461,7 @@
             if (clipRectForFragment.isEmpty())
                 continue;
             if (needsToClip(paintingInfo, clipRectForFragment)) {
-                if (m_paintLayer.layoutObject()->style()->position() != StaticPosition && clipRectForFragment.isClippedByClipCss())
+                if (m_paintLayer.layoutObject()->isPositioned() && clipRectForFragment.isClippedByClipCss())
                     UseCounter::count(m_paintLayer.layoutObject()->document(), UseCounter::ClipCssOfPositionedElement);
                 clipRecorder.emplace(*context, *parentLayer->layoutObject(), DisplayItem::ClipLayerParent, clipRectForFragment, &paintingInfo, fragment.paginationOffset, paintFlags);
             }
@@ -567,7 +567,7 @@
             clipRecorder.emplace(*context, *m_paintLayer.layoutObject(), DisplayItem::ClipLayerOverflowControls, fragment.backgroundRect, &localPaintingInfo, fragment.paginationOffset, paintFlags);
         if (PaintLayerScrollableArea* scrollableArea = m_paintLayer.scrollableArea()) {
             CullRect cullRect(pixelSnappedIntRect(fragment.backgroundRect.rect()));
-            ScrollableAreaPainter(*scrollableArea).paintOverflowControls(context, roundedIntPoint(toPoint(fragment.layerBounds.location() - m_paintLayer.layoutBoxLocation())), cullRect, true);
+            ScrollableAreaPainter(*scrollableArea).paintOverflowControls(*context, roundedIntPoint(toPoint(fragment.layerBounds.location() - m_paintLayer.layoutBoxLocation())), cullRect, true);
         }
     }
 }
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
index 9357362..fb3fb9f 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
@@ -102,7 +102,7 @@
         Element* element = toElement(node);
         m_scrollOffset = element->savedLayerScrollOffset();
         if (!m_scrollOffset.isZero())
-            scrollAnimator()->setCurrentPosition(FloatPoint(m_scrollOffset.width(), m_scrollOffset.height()));
+            scrollAnimator().setCurrentPosition(FloatPoint(m_scrollOffset.width(), m_scrollOffset.height()));
         element->setSavedLayerScrollOffset(IntSize());
     }
     updateResizerAreaSet();
@@ -239,7 +239,7 @@
     if (!verticalScrollbar && !horizontalScrollbar) {
         // FIXME: This isn't right. We need to know the thickness of custom scrollbars
         // even when they don't exist in order to set the resizer square size properly.
-        horizontalThickness = ScrollbarTheme::theme()->scrollbarThickness();
+        horizontalThickness = ScrollbarTheme::theme().scrollbarThickness();
         verticalThickness = horizontalThickness;
     } else if (verticalScrollbar && !horizontalScrollbar) {
         horizontalThickness = verticalScrollbar->width();
@@ -271,7 +271,7 @@
     return IntRect();
 }
 
-IntRect PaintLayerScrollableArea::convertFromScrollbarToContainingWidget(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
+IntRect PaintLayerScrollableArea::convertFromScrollbarToContainingWidget(const Scrollbar& scrollbar, const IntRect& scrollbarRect) const
 {
     LayoutView* view = box().view();
     if (!view)
@@ -283,7 +283,7 @@
     return view->frameView()->convertFromLayoutObject(box(), rect);
 }
 
-IntRect PaintLayerScrollableArea::convertFromContainingWidgetToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
+IntRect PaintLayerScrollableArea::convertFromContainingWidgetToScrollbar(const Scrollbar& scrollbar, const IntRect& parentRect) const
 {
     LayoutView* view = box().view();
     if (!view)
@@ -294,7 +294,7 @@
     return rect;
 }
 
-IntPoint PaintLayerScrollableArea::convertFromScrollbarToContainingWidget(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const
+IntPoint PaintLayerScrollableArea::convertFromScrollbarToContainingWidget(const Scrollbar& scrollbar, const IntPoint& scrollbarPoint) const
 {
     LayoutView* view = box().view();
     if (!view)
@@ -305,7 +305,7 @@
     return view->frameView()->convertFromLayoutObject(box(), point);
 }
 
-IntPoint PaintLayerScrollableArea::convertFromContainingWidgetToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
+IntPoint PaintLayerScrollableArea::convertFromContainingWidgetToScrollbar(const Scrollbar& scrollbar, const IntPoint& parentPoint) const
 {
     LayoutView* view = box().view();
     if (!view)
@@ -677,9 +677,6 @@
                 m_inOverflowRelayout = true;
                 SubtreeLayoutScope layoutScope(box());
                 layoutScope.setNeedsLayout(&box(), LayoutInvalidationReason::ScrollbarChanged);
-                // TODO(wangxianzhu): Remove the following statement when paint invalidation
-                // can detect client box changes. crbug.com/560418.
-                box().setShouldDoFullPaintInvalidation();
                 if (box().isLayoutBlock()) {
                     LayoutBlock& block = toLayoutBlock(box());
                     block.scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged);
@@ -912,13 +909,13 @@
     return x;
 }
 
-IntSize PaintLayerScrollableArea::scrollbarOffset(const Scrollbar* scrollbar) const
+IntSize PaintLayerScrollableArea::scrollbarOffset(const Scrollbar& scrollbar) const
 {
-    if (scrollbar == verticalScrollbar())
+    if (&scrollbar == verticalScrollbar())
         return IntSize(verticalScrollbarStart(0, box().size().width()), box().borderTop());
 
-    if (scrollbar == horizontalScrollbar())
-        return IntSize(horizontalScrollbarStart(0), box().size().height() - box().borderBottom() - scrollbar->height());
+    if (&scrollbar == horizontalScrollbar())
+        return IntSize(horizontalScrollbarStart(0), box().size().height() - box().borderBottom() - scrollbar.height());
 
     ASSERT_NOT_REACHED();
     return IntSize();
@@ -988,8 +985,7 @@
     if (hasScrollbar == hasHorizontalScrollbar())
         return;
 
-    setScrollbarNeedsPaintInvalidation(horizontalScrollbar());
-
+    setScrollbarNeedsPaintInvalidation(HorizontalScrollbar);
 
     m_scrollbarManager.setHasHorizontalScrollbar(hasScrollbar);
 
@@ -1011,7 +1007,7 @@
     if (hasScrollbar == hasVerticalScrollbar())
         return;
 
-    setScrollbarNeedsPaintInvalidation(verticalScrollbar());
+    setScrollbarNeedsPaintInvalidation(VerticalScrollbar);
 
     m_scrollbarManager.setHasVerticalScrollbar(hasScrollbar);
 
@@ -1488,23 +1484,23 @@
 PassRefPtrWillBeRawPtr<Scrollbar> PaintLayerScrollableArea::ScrollbarManager::createScrollbar(ScrollbarOrientation orientation)
 {
     ASSERT(orientation == HorizontalScrollbar ? !m_hBarIsAttached : !m_vBarIsAttached);
-    RefPtrWillBeRawPtr<Scrollbar> widget = nullptr;
+    RefPtrWillBeRawPtr<Scrollbar> scrollbar = nullptr;
     const LayoutObject& actualLayoutObject = layoutObjectForScrollbar(m_scrollableArea->box());
     bool hasCustomScrollbarStyle = actualLayoutObject.isBox() && actualLayoutObject.styleRef().hasPseudoStyle(SCROLLBAR);
     if (hasCustomScrollbarStyle) {
-        widget = LayoutScrollbar::createCustomScrollbar(m_scrollableArea.get(), orientation, actualLayoutObject.node());
+        scrollbar = LayoutScrollbar::createCustomScrollbar(m_scrollableArea.get(), orientation, actualLayoutObject.node());
     } else {
         ScrollbarControlSize scrollbarSize = RegularScrollbar;
         if (actualLayoutObject.styleRef().hasAppearance())
             scrollbarSize = LayoutTheme::theme().scrollbarControlSizeForPart(actualLayoutObject.styleRef().appearance());
-        widget = Scrollbar::create(m_scrollableArea.get(), orientation, scrollbarSize);
+        scrollbar = Scrollbar::create(m_scrollableArea.get(), orientation, scrollbarSize);
         if (orientation == HorizontalScrollbar)
-            m_scrollableArea->didAddScrollbar(widget.get(), HorizontalScrollbar);
+            m_scrollableArea->didAddScrollbar(*scrollbar, HorizontalScrollbar);
         else
-            m_scrollableArea->didAddScrollbar(widget.get(), VerticalScrollbar);
+            m_scrollableArea->didAddScrollbar(*scrollbar, VerticalScrollbar);
     }
-    m_scrollableArea->box().document().view()->addChild(widget.get());
-    return widget.release();
+    m_scrollableArea->box().document().view()->addChild(scrollbar.get());
+    return scrollbar.release();
 }
 
 void PaintLayerScrollableArea::ScrollbarManager::destroyScrollbar(ScrollbarOrientation orientation)
@@ -1514,10 +1510,10 @@
     if (!scrollbar)
         return;
 
-    m_scrollableArea->setScrollbarNeedsPaintInvalidation(scrollbar.get());
+    m_scrollableArea->setScrollbarNeedsPaintInvalidation(orientation);
 
     if (!scrollbar->isCustomScrollbar())
-        m_scrollableArea->willRemoveScrollbar(scrollbar.get(), orientation);
+        m_scrollableArea->willRemoveScrollbar(*scrollbar, orientation);
 
     toFrameView(scrollbar->parent())->removeChild(scrollbar.get());
     scrollbar->disconnectFromScrollableArea();
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h
index 46ace1f5..bb1973e9 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h
@@ -193,10 +193,10 @@
     bool isActive() const override;
     bool isScrollCornerVisible() const override;
     IntRect scrollCornerRect() const override;
-    IntRect convertFromScrollbarToContainingWidget(const Scrollbar*, const IntRect&) const override;
-    IntRect convertFromContainingWidgetToScrollbar(const Scrollbar*, const IntRect&) const override;
-    IntPoint convertFromScrollbarToContainingWidget(const Scrollbar*, const IntPoint&) const override;
-    IntPoint convertFromContainingWidgetToScrollbar(const Scrollbar*, const IntPoint&) const override;
+    IntRect convertFromScrollbarToContainingWidget(const Scrollbar&, const IntRect&) const override;
+    IntRect convertFromContainingWidgetToScrollbar(const Scrollbar&, const IntRect&) const override;
+    IntPoint convertFromScrollbarToContainingWidget(const Scrollbar&, const IntPoint&) const override;
+    IntPoint convertFromContainingWidgetToScrollbar(const Scrollbar&, const IntPoint&) const override;
     int scrollSize(ScrollbarOrientation) const override;
     IntPoint scrollPosition() const override;
     DoublePoint scrollPositionDouble() const override;
@@ -348,7 +348,7 @@
 
     LayoutUnit verticalScrollbarStart(int minX, int maxX) const;
     LayoutUnit horizontalScrollbarStart(int minX) const;
-    IntSize scrollbarOffset(const Scrollbar*) const;
+    IntSize scrollbarOffset(const Scrollbar&) const;
 
     void setHasHorizontalScrollbar(bool hasScrollbar);
     void setHasVerticalScrollbar(bool hasScrollbar);
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
index 3969099..dc0d13c 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -9,6 +9,7 @@
 #include "core/layout/LayoutView.h"
 #include "core/paint/ObjectPaintProperties.h"
 #include "core/paint/PaintLayer.h"
+#include "platform/graphics/paint/ClipPaintPropertyNode.h"
 #include "platform/graphics/paint/TransformPaintPropertyNode.h"
 #include "platform/transforms/TransformationMatrix.h"
 
@@ -21,8 +22,11 @@
 struct PaintPropertyTreeBuilderContext {
     PaintPropertyTreeBuilderContext()
         : currentTransform(nullptr)
+        , currentClip(nullptr)
         , transformForOutOfFlowPositioned(nullptr)
+        , clipForOutOfFlowPositioned(nullptr)
         , transformForFixedPositioned(nullptr)
+        , clipForFixedPositioned(nullptr)
         , currentEffect(nullptr) { }
 
     // The combination of a transform and paint offset describes a linear space.
@@ -31,18 +35,30 @@
     // the space with its own layout location.
     TransformPaintPropertyNode* currentTransform;
     LayoutPoint paintOffset;
+    // The clip node describes the accumulated raster clip for the current subtree.
+    // Note that the computed raster region in canvas space for a clip node is independent from
+    // the transform and paint offset above. Also the actual raster region may be affected
+    // by layerization and occlusion tracking.
+    ClipPaintPropertyNode* currentClip;
 
     // Separate context for out-of-flow positioned and fixed positioned elements are needed
-    // because they don't use DOM parent as their positioning parent (i.e. containing block).
+    // because they don't use DOM parent as their containing block.
     // These additional contexts normally pass through untouched, and are only copied from
-    // the main context when the current element serves as the positioning parent of corresponding
+    // the main context when the current element serves as the containing block of corresponding
     // positioned descendants.
+    // Overflow clips are also inherited by containing block tree instead of DOM tree, thus they
+    // are included in the additional context too.
     TransformPaintPropertyNode* transformForOutOfFlowPositioned;
     LayoutPoint paintOffsetForOutOfFlowPositioned;
+    ClipPaintPropertyNode* clipForOutOfFlowPositioned;
 
     TransformPaintPropertyNode* transformForFixedPositioned;
     LayoutPoint paintOffsetForFixedPositioned;
+    ClipPaintPropertyNode* clipForFixedPositioned;
 
+    // The effect hierarchy is applied by the stacking context tree. It is guaranteed that every
+    // DOM descendant is also a stacking context descendant. Therefore, we don't need extra
+    // bookkeeping for effect nodes and can generate the effect tree from a DOM-order traversal.
     EffectPaintPropertyNode* currentEffect;
 };
 
@@ -64,6 +80,10 @@
     localContext.transformForFixedPositioned = newTransformNodeForPreTranslation.get();
     localContext.paintOffsetForFixedPositioned = LayoutPoint();
 
+    FloatRoundedRect contentClip(IntRect(IntPoint(), frameView.visibleContentSize()));
+    RefPtr<ClipPaintPropertyNode> newClipNodeForContentClip = ClipPaintPropertyNode::create(newTransformNodeForPreTranslation.get(), contentClip, localContext.currentClip);
+    localContext.currentClip = localContext.clipForOutOfFlowPositioned = localContext.clipForFixedPositioned = newClipNodeForContentClip.get();
+
     // This is going away in favor of Settings::rootLayerScrolls.
     DoubleSize scrollOffset = frameView.scrollOffsetDouble();
     TransformationMatrix frameScroll;
@@ -74,6 +94,7 @@
 
     frameView.setPreTranslation(newTransformNodeForPreTranslation.release());
     frameView.setScrollTranslation(newTransformNodeForScrollTranslation.release());
+    frameView.setContentClip(newClipNodeForContentClip.release());
 
     if (LayoutView* layoutView = frameView.layoutView())
         walk(*layoutView, localContext);
@@ -96,6 +117,7 @@
     case AbsolutePosition:
         context.currentTransform = context.transformForOutOfFlowPositioned;
         context.paintOffset = context.paintOffsetForOutOfFlowPositioned;
+        context.currentClip = context.clipForOutOfFlowPositioned;
         break;
     case StickyPosition:
         context.paintOffset += boxModelObject.offsetForInFlowPosition();
@@ -103,6 +125,7 @@
     case FixedPosition:
         context.currentTransform = context.transformForFixedPositioned;
         context.paintOffset = context.paintOffsetForFixedPositioned;
+        context.currentClip = context.clipForFixedPositioned;
         break;
     default:
         ASSERT_NOT_REACHED();
@@ -183,6 +206,41 @@
     return newEffectNode.release();
 }
 
+static PassRefPtr<ClipPaintPropertyNode> createOverflowClipIfNeeded(const LayoutObject& object, PaintPropertyTreeBuilderContext& context)
+{
+    if (!object.isBox())
+        return nullptr;
+    const LayoutBox& box = toLayoutBox(object);
+
+    // The <input> elements can't have contents thus CSS overflow property doesn't apply.
+    // However for layout purposes we do generate child layout objects for them, e.g. button label.
+    // We should clip the overflow from those children. This is called control clip and we
+    // technically treat them like overflow clip.
+    LayoutRect clipRect;
+    if (box.hasControlClip())
+        clipRect = box.controlClipRect(context.paintOffset);
+    else if (box.hasOverflowClip())
+        clipRect = box.overflowClipRect(context.paintOffset);
+    else
+        return nullptr;
+
+    RefPtr<ClipPaintPropertyNode> newClipNodeForBorderRadiusClip;
+    const ComputedStyle& style = box.styleRef();
+    if (style.hasBorderRadius()) {
+        newClipNodeForBorderRadiusClip = ClipPaintPropertyNode::create(
+            context.currentTransform,
+            style.getRoundedInnerBorderFor(LayoutRect(context.paintOffset, box.size())),
+            context.currentClip);
+    }
+
+    RefPtr<ClipPaintPropertyNode> newClipNodeForOverflowClip = ClipPaintPropertyNode::create(
+        context.currentTransform,
+        FloatRoundedRect(FloatRect(clipRect)),
+        newClipNodeForBorderRadiusClip ? newClipNodeForBorderRadiusClip.release() : context.currentClip);
+    context.currentClip = newClipNodeForOverflowClip.get();
+    return newClipNodeForOverflowClip.release();
+}
+
 static FloatPoint perspectiveOrigin(const LayoutBox& box)
 {
     const ComputedStyle& style = box.styleRef();
@@ -230,14 +288,16 @@
     // uses transforms. Therefore, we only need to check createdNewTransform and isSVGRoot() to
     // ensure out-of-flow and fixed positioning is correct at the svg->html boundary.
 
-    if (object.styleRef().position() != StaticPosition || createdNewTransform || object.isSVGRoot()) {
+    if (object.isPositioned() || createdNewTransform || object.isSVGRoot()) {
         context.transformForOutOfFlowPositioned = context.currentTransform;
         context.paintOffsetForOutOfFlowPositioned = context.paintOffset;
+        context.clipForOutOfFlowPositioned = context.currentClip;
     }
 
     if (createdNewTransform || object.isSVGRoot()) {
         context.transformForFixedPositioned = context.currentTransform;
         context.paintOffsetForFixedPositioned = context.paintOffset;
+        context.clipForFixedPositioned = context.currentClip;
     }
 }
 
@@ -249,15 +309,19 @@
     RefPtr<TransformPaintPropertyNode> newTransformNodeForPaintOffsetTranslation = createPaintOffsetTranslationIfNeeded(object, localContext);
     RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = createTransformIfNeeded(object, localContext);
     RefPtr<EffectPaintPropertyNode> newEffectNode = createEffectIfNeeded(object, localContext);
+    RefPtr<ClipPaintPropertyNode> newClipNodeForOverflowClip = createOverflowClipIfNeeded(object, localContext);
+    // TODO(trchen): Insert flattening transform here, as specified by
+    // http://www.w3.org/TR/css3-transforms/#transform-style-property
     RefPtr<TransformPaintPropertyNode> newTransformNodeForPerspective = createPerspectiveIfNeeded(object, localContext);
     RefPtr<TransformPaintPropertyNode> newTransformNodeForScrollTranslation = createScrollTranslationIfNeeded(object, localContext);
     updateOutOfFlowContext(object, newTransformNodeForTransform, localContext);
 
-    if (newTransformNodeForPaintOffsetTranslation || newTransformNodeForTransform || newEffectNode || newTransformNodeForPerspective || newTransformNodeForScrollTranslation) {
+    if (newTransformNodeForPaintOffsetTranslation || newTransformNodeForTransform || newEffectNode || newClipNodeForOverflowClip || newTransformNodeForPerspective || newTransformNodeForScrollTranslation) {
         OwnPtr<ObjectPaintProperties> updatedPaintProperties = ObjectPaintProperties::create(
             newTransformNodeForPaintOffsetTranslation.release(),
             newTransformNodeForTransform.release(),
             newEffectNode.release(),
+            newClipNodeForOverflowClip.release(),
             newTransformNodeForPerspective.release(),
             newTransformNodeForScrollTranslation.release());
         object.setObjectPaintProperties(updatedPaintProperties.release());
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
index 7f22a30..3ec7562 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
@@ -57,12 +57,18 @@
 {
     loadTestData("fixed-position.html");
 
+    FrameView* frameView = document().view();
+
     // target1 is a fixed-position element inside an absolute-position scrolling element.
     // It should be attached under the viewport to skip scrolling and offset of the parent.
     Element* target1 = document().getElementById("target1");
     ObjectPaintProperties* target1Properties = target1->layoutObject()->objectPaintProperties();
     EXPECT_EQ(TransformationMatrix().translate(200, 150), target1Properties->paintOffsetTranslation()->matrix());
-    EXPECT_EQ(document().view()->preTranslation(), target1Properties->paintOffsetTranslation()->parent());
+    EXPECT_EQ(frameView->preTranslation(), target1Properties->paintOffsetTranslation()->parent());
+    EXPECT_EQ(target1Properties->paintOffsetTranslation(), target1Properties->overflowClip()->localTransformSpace());
+    EXPECT_EQ(FloatRoundedRect(0, 0, 100, 100), target1Properties->overflowClip()->clipRect());
+    // Likewise, it inherits clip from the viewport, skipping overflow clip of the scroller.
+    EXPECT_EQ(frameView->contentClip(), target1Properties->overflowClip()->parent());
 
     // target2 is a fixed-position element inside a transformed scrolling element.
     // It should be attached under the scrolled box of the transformed element.
@@ -72,6 +78,9 @@
     ObjectPaintProperties* scrollerProperties = scroller->layoutObject()->objectPaintProperties();
     EXPECT_EQ(TransformationMatrix().translate(200, 150), target2Properties->paintOffsetTranslation()->matrix());
     EXPECT_EQ(scrollerProperties->scrollTranslation(), target2Properties->paintOffsetTranslation()->parent());
+    EXPECT_EQ(target2Properties->paintOffsetTranslation(), target2Properties->overflowClip()->localTransformSpace());
+    EXPECT_EQ(FloatRoundedRect(0, 0, 100, 100), target2Properties->overflowClip()->clipRect());
+    EXPECT_EQ(scrollerProperties->overflowClip(), target2Properties->overflowClip()->parent());
 }
 
 TEST_F(PaintPropertyTreeBuilderTest, PositionAndScroll)
@@ -85,6 +94,9 @@
     ObjectPaintProperties* scrollerProperties = scroller->layoutObject()->objectPaintProperties();
     EXPECT_EQ(TransformationMatrix().translate(0, -100), scrollerProperties->scrollTranslation()->matrix());
     EXPECT_EQ(frameView->scrollTranslation(), scrollerProperties->scrollTranslation()->parent());
+    EXPECT_EQ(frameView->scrollTranslation(), scrollerProperties->overflowClip()->localTransformSpace());
+    EXPECT_EQ(FloatRoundedRect(120, 340, 385, 285), scrollerProperties->overflowClip()->clipRect());
+    EXPECT_EQ(frameView->contentClip(), scrollerProperties->overflowClip()->parent());
 
     // The relative-positioned element should have accumulated box offset (exclude scrolling),
     // and should be affected by ancestor scroll transforms.
@@ -92,12 +104,18 @@
     ObjectPaintProperties* relPosProperties = relPos->layoutObject()->objectPaintProperties();
     EXPECT_EQ(TransformationMatrix().translate(680, 1120), relPosProperties->paintOffsetTranslation()->matrix());
     EXPECT_EQ(scrollerProperties->scrollTranslation(), relPosProperties->paintOffsetTranslation()->parent());
+    EXPECT_EQ(relPosProperties->transform(), relPosProperties->overflowClip()->localTransformSpace());
+    EXPECT_EQ(FloatRoundedRect(0, 0, 385, 0), relPosProperties->overflowClip()->clipRect());
+    EXPECT_EQ(scrollerProperties->overflowClip(), relPosProperties->overflowClip()->parent());
 
     // The absolute-positioned element should not be affected by non-positioned scroller at all.
     Element* absPos = document().getElementById("abs-pos");
     ObjectPaintProperties* absPosProperties = absPos->layoutObject()->objectPaintProperties();
     EXPECT_EQ(TransformationMatrix().translate(123, 456), absPosProperties->paintOffsetTranslation()->matrix());
     EXPECT_EQ(frameView->scrollTranslation(), absPosProperties->paintOffsetTranslation()->parent());
+    EXPECT_EQ(absPosProperties->transform(), absPosProperties->overflowClip()->localTransformSpace());
+    EXPECT_EQ(FloatRoundedRect(), absPosProperties->overflowClip()->clipRect());
+    EXPECT_EQ(frameView->contentClip(), absPosProperties->overflowClip()->parent());
 }
 
 TEST_F(PaintPropertyTreeBuilderTest, FrameScrollingTraditional)
@@ -112,6 +130,9 @@
     EXPECT_EQ(nullptr, frameView->preTranslation()->parent());
     EXPECT_EQ(TransformationMatrix().translate(0, -100), frameView->scrollTranslation()->matrix());
     EXPECT_EQ(frameView->preTranslation(), frameView->scrollTranslation()->parent());
+    EXPECT_EQ(frameView->preTranslation(), frameView->contentClip()->localTransformSpace());
+    EXPECT_EQ(FloatRoundedRect(0, 0, 785, 600), frameView->contentClip()->clipRect());
+    EXPECT_EQ(nullptr, frameView->contentClip()->parent());
 
     LayoutView* layoutView = document().layoutView();
     ObjectPaintProperties* layoutViewProperties = layoutView->objectPaintProperties();
@@ -469,4 +490,71 @@
     EXPECT_EQ(containerProperties->transform(), fixedProperties->paintOffsetTranslation()->parent());
 }
 
+TEST_F(PaintPropertyTreeBuilderTest, ControlClip)
+{
+    setBodyInnerHTML(
+        "<style>"
+        "  body {"
+        "    margin: 0;"
+        "  }"
+        "  input {"
+        "    border-width: 5px;"
+        "    padding: 0;"
+        "  }"
+        "</style>"
+        "<input id='button' type='button' style='width:345px; height:123px' value='some text'/>");
+
+    FrameView* frameView = document().view();
+    LayoutObject& button = *document().getElementById("button")->layoutObject();
+    ObjectPaintProperties* buttonProperties = button.objectPaintProperties();
+    EXPECT_EQ(frameView->scrollTranslation(), buttonProperties->overflowClip()->localTransformSpace());
+    EXPECT_EQ(FloatRoundedRect(5, 5, 335, 113), buttonProperties->overflowClip()->clipRect());
+    EXPECT_EQ(frameView->contentClip(), buttonProperties->overflowClip()->parent());
+}
+
+TEST_F(PaintPropertyTreeBuilderTest, BorderRadiusClip)
+{
+    setBodyInnerHTML(
+        "<style>"
+        " body {"
+        "   margin: 0px;"
+        " }"
+        " #div {"
+        "   border-radius: 12px 34px 56px 78px;"
+        "   border-top: 45px solid;"
+        "   border-right: 50px solid;"
+        "   border-bottom: 55px solid;"
+        "   border-left: 60px solid;"
+        "   width: 500px;"
+        "   height: 400px;"
+        "   overflow: scroll;"
+        " }"
+        "</style>"
+        "<div id='div'></div>");
+
+    FrameView* frameView = document().view();
+    LayoutObject& div = *document().getElementById("div")->layoutObject();
+    ObjectPaintProperties* divProperties = div.objectPaintProperties();
+    EXPECT_EQ(frameView->scrollTranslation(), divProperties->overflowClip()->localTransformSpace());
+    // The overflow clip rect includes only the padding box.
+    // padding box = border box(500+60+50, 400+45+55) - border outset(60+50, 45+55) - scrollbars(15, 15)
+    EXPECT_EQ(FloatRoundedRect(60, 45, 485, 385), divProperties->overflowClip()->clipRect());
+    const ClipPaintPropertyNode* borderRadiusClip = divProperties->overflowClip()->parent();
+    EXPECT_EQ(frameView->scrollTranslation(), borderRadiusClip->localTransformSpace());
+    // The border radius clip is the area enclosed by inner border edge, including the scrollbars.
+    // As the border-radius is specified in outer radius, the inner radius is calculated by:
+    // inner radius = max(outer radius - border width, 0)
+    // In the case that two adjacent borders have different width, the inner radius of the corner
+    // may transition from one value to the other. i.e. being an ellipse.
+    EXPECT_EQ(
+        FloatRoundedRect(
+            FloatRect(60, 45, 500, 400), // = border box(610, 500) - border outset(110, 100)
+            FloatSize(0, 0), //   (top left)     = max((12, 12) - (60, 45), (0, 0))
+            FloatSize(0, 0), //   (top right)    = max((34, 34) - (50, 45), (0, 0))
+            FloatSize(18, 23), // (bottom left)  = max((78, 78) - (60, 55), (0, 0))
+            FloatSize(6, 1)), //  (bottom right) = max((56, 56) - (50, 55), (0, 0))
+        borderRadiusClip->clipRect());
+    EXPECT_EQ(frameView->contentClip(), borderRadiusClip->parent());
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/PartPainter.cpp b/third_party/WebKit/Source/core/paint/PartPainter.cpp
index 6dca6dfc..0305aea 100644
--- a/third_party/WebKit/Source/core/paint/PartPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/PartPainter.cpp
@@ -92,7 +92,7 @@
     }
 
     if (m_layoutPart.canResize())
-        ScrollableAreaPainter(*m_layoutPart.layer()->scrollableArea()).paintResizer(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.cullRect());
+        ScrollableAreaPainter(*m_layoutPart.layer()->scrollableArea()).paintResizer(*paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.cullRect());
 }
 
 void PartPainter::paintContents(const PaintInfo& paintInfo, const LayoutPoint& paintOffset)
@@ -115,7 +115,7 @@
         AffineTransform::translation(widgetPaintOffset.width(), widgetPaintOffset.height()));
 
     CullRect adjustedCullRect(paintInfo.cullRect(), -widgetPaintOffset);
-    widget->paint(paintInfo.context, adjustedCullRect);
+    widget->paint(*paintInfo.context, adjustedCullRect);
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/ScrollRecorder.cpp b/third_party/WebKit/Source/core/paint/ScrollRecorder.cpp
index 5facf1b..290fd2c9 100644
--- a/third_party/WebKit/Source/core/paint/ScrollRecorder.cpp
+++ b/third_party/WebKit/Source/core/paint/ScrollRecorder.cpp
@@ -11,7 +11,7 @@
 
 namespace blink {
 
-ScrollRecorder::ScrollRecorder(GraphicsContext& context, const DisplayItemClientWrapper& client, PaintPhase phase, const IntSize& currentOffset)
+ScrollRecorder::ScrollRecorder(GraphicsContext& context, const DisplayItemClient& client, PaintPhase phase, const IntSize& currentOffset)
     : m_client(client)
     , m_beginItemType(DisplayItem::paintPhaseToScrollType(phase))
     , m_context(context)
diff --git a/third_party/WebKit/Source/core/paint/ScrollRecorder.h b/third_party/WebKit/Source/core/paint/ScrollRecorder.h
index 4f45e3b..90b57eb 100644
--- a/third_party/WebKit/Source/core/paint/ScrollRecorder.h
+++ b/third_party/WebKit/Source/core/paint/ScrollRecorder.h
@@ -20,10 +20,10 @@
 class CORE_EXPORT ScrollRecorder {
     USING_FAST_MALLOC(ScrollRecorder);
 public:
-    ScrollRecorder(GraphicsContext&, const DisplayItemClientWrapper&, PaintPhase, const IntSize& currentOffset);
+    ScrollRecorder(GraphicsContext&, const DisplayItemClient&, PaintPhase, const IntSize& currentOffset);
     ~ScrollRecorder();
 private:
-    DisplayItemClientWrapper m_client;
+    const DisplayItemClient& m_client;
     DisplayItem::Type m_beginItemType;
     GraphicsContext& m_context;
 };
diff --git a/third_party/WebKit/Source/core/paint/ScrollableAreaPainter.cpp b/third_party/WebKit/Source/core/paint/ScrollableAreaPainter.cpp
index 8b62703b..b6d9682b 100644
--- a/third_party/WebKit/Source/core/paint/ScrollableAreaPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/ScrollableAreaPainter.cpp
@@ -18,7 +18,7 @@
 
 namespace blink {
 
-void ScrollableAreaPainter::paintResizer(GraphicsContext* context, const IntPoint& paintOffset, const CullRect& cullRect)
+void ScrollableAreaPainter::paintResizer(GraphicsContext& context, const IntPoint& paintOffset, const CullRect& cullRect)
 {
     if (scrollableArea().box().style()->resize() == RESIZE_NONE)
         return;
@@ -35,28 +35,28 @@
         return;
     }
 
-    if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*context, scrollableArea().box(), DisplayItem::Resizer, paintOffset))
+    if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, scrollableArea().box(), DisplayItem::Resizer, paintOffset))
         return;
 
-    LayoutObjectDrawingRecorder recorder(*context, scrollableArea().box(), DisplayItem::Resizer, absRect, paintOffset);
+    LayoutObjectDrawingRecorder recorder(context, scrollableArea().box(), DisplayItem::Resizer, absRect, paintOffset);
 
     drawPlatformResizerImage(context, absRect);
 
     // Draw a frame around the resizer (1px grey line) if there are any scrollbars present.
     // Clipping will exclude the right and bottom edges of this frame.
     if (!scrollableArea().hasOverlayScrollbars() && scrollableArea().hasScrollbar()) {
-        GraphicsContextStateSaver stateSaver(*context);
-        context->clip(absRect);
+        GraphicsContextStateSaver stateSaver(context);
+        context.clip(absRect);
         IntRect largerCorner = absRect;
         largerCorner.setSize(IntSize(largerCorner.width() + 1, largerCorner.height() + 1));
-        context->setStrokeColor(Color(217, 217, 217));
-        context->setStrokeThickness(1.0f);
-        context->setFillColor(Color::transparent);
-        context->drawRect(largerCorner);
+        context.setStrokeColor(Color(217, 217, 217));
+        context.setStrokeThickness(1.0f);
+        context.setFillColor(Color::transparent);
+        context.drawRect(largerCorner);
     }
 }
 
-void ScrollableAreaPainter::drawPlatformResizerImage(GraphicsContext* context, IntRect resizerCornerRect)
+void ScrollableAreaPainter::drawPlatformResizerImage(GraphicsContext& context, IntRect resizerCornerRect)
 {
     float deviceScaleFactor = blink::deviceScaleFactor(scrollableArea().box().frame());
 
@@ -74,18 +74,18 @@
     }
 
     if (scrollableArea().box().shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
-        context->save();
-        context->translate(resizerCornerRect.x() + cornerResizerSize.width(), resizerCornerRect.y() + resizerCornerRect.height() - cornerResizerSize.height());
-        context->scale(-1.0, 1.0);
-        context->drawImage(resizeCornerImage.get(), IntRect(IntPoint(), cornerResizerSize));
-        context->restore();
+        context.save();
+        context.translate(resizerCornerRect.x() + cornerResizerSize.width(), resizerCornerRect.y() + resizerCornerRect.height() - cornerResizerSize.height());
+        context.scale(-1.0, 1.0);
+        context.drawImage(resizeCornerImage.get(), IntRect(IntPoint(), cornerResizerSize));
+        context.restore();
         return;
     }
     IntRect imageRect(resizerCornerRect.maxXMaxYCorner() - cornerResizerSize, cornerResizerSize);
-    context->drawImage(resizeCornerImage.get(), imageRect);
+    context.drawImage(resizeCornerImage.get(), imageRect);
 }
 
-void ScrollableAreaPainter::paintOverflowControls(GraphicsContext* context, const IntPoint& paintOffset, const CullRect& cullRect, bool paintingOverlayControls)
+void ScrollableAreaPainter::paintOverflowControls(GraphicsContext& context, const IntPoint& paintOffset, const CullRect& cullRect, bool paintingOverlayControls)
 {
     // Don't do anything if we have no overflow.
     if (!scrollableArea().box().hasOverflowClip())
@@ -127,11 +127,11 @@
 
     {
         if (scrollableArea().horizontalScrollbar() && !scrollableArea().layerForHorizontalScrollbar()) {
-            TransformRecorder translateRecorder(*context, *scrollableArea().horizontalScrollbar(), AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y()));
+            TransformRecorder translateRecorder(context, *scrollableArea().horizontalScrollbar(), AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y()));
             scrollableArea().horizontalScrollbar()->paint(context, adjustedCullRect);
         }
         if (scrollableArea().verticalScrollbar() && !scrollableArea().layerForVerticalScrollbar()) {
-            TransformRecorder translateRecorder(*context, *scrollableArea().verticalScrollbar(), AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y()));
+            TransformRecorder translateRecorder(context, *scrollableArea().verticalScrollbar(), AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y()));
             scrollableArea().verticalScrollbar()->paint(context, adjustedCullRect);
         }
     }
@@ -166,7 +166,7 @@
     return false;
 }
 
-void ScrollableAreaPainter::paintScrollCorner(GraphicsContext* context, const IntPoint& paintOffset, const CullRect& adjustedCullRect)
+void ScrollableAreaPainter::paintScrollCorner(GraphicsContext& context, const IntPoint& paintOffset, const CullRect& adjustedCullRect)
 {
     IntRect absRect = scrollableArea().scrollCornerRect();
     if (absRect.isEmpty())
@@ -185,11 +185,11 @@
     if (scrollableArea().hasOverlayScrollbars())
         return;
 
-    if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*context, scrollableArea().box(), DisplayItem::ScrollbarCorner, paintOffset))
+    if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, scrollableArea().box(), DisplayItem::ScrollbarCorner, paintOffset))
         return;
 
-    LayoutObjectDrawingRecorder recorder(*context, scrollableArea().box(), DisplayItem::ScrollbarCorner, absRect, paintOffset);
-    context->fillRect(absRect, Color::white);
+    LayoutObjectDrawingRecorder recorder(context, scrollableArea().box(), DisplayItem::ScrollbarCorner, absRect, paintOffset);
+    context.fillRect(absRect, Color::white);
 }
 
 PaintLayerScrollableArea& ScrollableAreaPainter::scrollableArea() const
diff --git a/third_party/WebKit/Source/core/paint/ScrollableAreaPainter.h b/third_party/WebKit/Source/core/paint/ScrollableAreaPainter.h
index a941834e..3004a6f 100644
--- a/third_party/WebKit/Source/core/paint/ScrollableAreaPainter.h
+++ b/third_party/WebKit/Source/core/paint/ScrollableAreaPainter.h
@@ -21,12 +21,12 @@
 public:
     explicit ScrollableAreaPainter(PaintLayerScrollableArea& paintLayerScrollableArea) : m_scrollableArea(&paintLayerScrollableArea) { }
 
-    void paintResizer(GraphicsContext*, const IntPoint& paintOffset, const CullRect&);
-    void paintOverflowControls(GraphicsContext*, const IntPoint& paintOffset, const CullRect&, bool paintingOverlayControls);
-    void paintScrollCorner(GraphicsContext*, const IntPoint&, const CullRect&);
+    void paintResizer(GraphicsContext&, const IntPoint& paintOffset, const CullRect&);
+    void paintOverflowControls(GraphicsContext&, const IntPoint& paintOffset, const CullRect&, bool paintingOverlayControls);
+    void paintScrollCorner(GraphicsContext&, const IntPoint&, const CullRect&);
 
 private:
-    void drawPlatformResizerImage(GraphicsContext*, IntRect resizerCornerRect);
+    void drawPlatformResizerImage(GraphicsContext&, IntRect resizerCornerRect);
     bool overflowControlsIntersectRect(const CullRect&) const;
 
     PaintLayerScrollableArea& scrollableArea() const;
diff --git a/third_party/WebKit/Source/core/paint/ScrollbarPainter.cpp b/third_party/WebKit/Source/core/paint/ScrollbarPainter.cpp
index c1ef8c912..a5ca9c9 100644
--- a/third_party/WebKit/Source/core/paint/ScrollbarPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/ScrollbarPainter.cpp
@@ -13,7 +13,7 @@
 
 namespace blink {
 
-void ScrollbarPainter::paintPart(GraphicsContext* graphicsContext, ScrollbarPart partType, const IntRect& rect)
+void ScrollbarPainter::paintPart(GraphicsContext& graphicsContext, ScrollbarPart partType, const IntRect& rect)
 {
     const LayoutScrollbarPart* partLayoutObject = m_layoutScrollbar->getPart(partType);
     if (!partLayoutObject)
@@ -21,7 +21,7 @@
     paintIntoRect(*partLayoutObject, graphicsContext, m_layoutScrollbar->location(), LayoutRect(rect));
 }
 
-void ScrollbarPainter::paintIntoRect(const LayoutScrollbarPart& layoutScrollbarPart, GraphicsContext* graphicsContext, const LayoutPoint& paintOffset, const LayoutRect& rect)
+void ScrollbarPainter::paintIntoRect(const LayoutScrollbarPart& layoutScrollbarPart, GraphicsContext& graphicsContext, const LayoutPoint& paintOffset, const LayoutRect& rect)
 {
     // Make sure our dimensions match the rect.
     // FIXME: Setting these is a bad layering violation!
@@ -30,7 +30,7 @@
     const_cast<LayoutScrollbarPart&>(layoutScrollbarPart).setHeight(rect.height());
 
     // Now do the paint.
-    PaintInfo paintInfo(graphicsContext, pixelSnappedIntRect(rect), PaintPhaseBlockBackground, GlobalPaintNormalPhase, PaintLayerNoFlag);
+    PaintInfo paintInfo(&graphicsContext, pixelSnappedIntRect(rect), PaintPhaseBlockBackground, GlobalPaintNormalPhase, PaintLayerNoFlag);
     BlockPainter blockPainter(layoutScrollbarPart);
     blockPainter.paint(paintInfo, paintOffset);
     paintInfo.phase = PaintPhaseChildBlockBackgrounds;
diff --git a/third_party/WebKit/Source/core/paint/ScrollbarPainter.h b/third_party/WebKit/Source/core/paint/ScrollbarPainter.h
index e0e619a..347e48e8 100644
--- a/third_party/WebKit/Source/core/paint/ScrollbarPainter.h
+++ b/third_party/WebKit/Source/core/paint/ScrollbarPainter.h
@@ -23,8 +23,8 @@
 public:
     explicit ScrollbarPainter(const LayoutScrollbar& layoutScrollbar) : m_layoutScrollbar(&layoutScrollbar) { }
 
-    void paintPart(GraphicsContext*, ScrollbarPart, const IntRect&);
-    static void paintIntoRect(const LayoutScrollbarPart&, GraphicsContext*, const LayoutPoint& paintOffset, const LayoutRect&);
+    void paintPart(GraphicsContext&, ScrollbarPart, const IntRect&);
+    static void paintIntoRect(const LayoutScrollbarPart&, GraphicsContext&, const LayoutPoint& paintOffset, const LayoutRect&);
 
 private:
     RawPtrWillBeMember<const LayoutScrollbar> m_layoutScrollbar;
diff --git a/third_party/WebKit/Source/core/paint/Transform3DRecorder.cpp b/third_party/WebKit/Source/core/paint/Transform3DRecorder.cpp
index 08efe07..af546ffc 100644
--- a/third_party/WebKit/Source/core/paint/Transform3DRecorder.cpp
+++ b/third_party/WebKit/Source/core/paint/Transform3DRecorder.cpp
@@ -13,7 +13,7 @@
 
 Transform3DRecorder::Transform3DRecorder(
     GraphicsContext& context,
-    const DisplayItemClientWrapper& client,
+    const DisplayItemClient& client,
     DisplayItem::Type type,
     const TransformationMatrix& transform,
     const FloatPoint3D& transformOrigin)
diff --git a/third_party/WebKit/Source/core/paint/Transform3DRecorder.h b/third_party/WebKit/Source/core/paint/Transform3DRecorder.h
index 9ee402fb..939734d 100644
--- a/third_party/WebKit/Source/core/paint/Transform3DRecorder.h
+++ b/third_party/WebKit/Source/core/paint/Transform3DRecorder.h
@@ -19,7 +19,7 @@
 public:
     Transform3DRecorder(
         GraphicsContext&,
-        const DisplayItemClientWrapper&,
+        const DisplayItemClient&,
         DisplayItem::Type,
         const TransformationMatrix&,
         const FloatPoint3D& transformOrigin);
@@ -27,7 +27,7 @@
 
 private:
     GraphicsContext& m_context;
-    DisplayItemClientWrapper m_client;
+    const DisplayItemClient& m_client;
     DisplayItem::Type m_type;
     bool m_skipRecordingForIdentityTransform;
 };
diff --git a/third_party/WebKit/Source/core/paint/TransformRecorder.cpp b/third_party/WebKit/Source/core/paint/TransformRecorder.cpp
index 65afa6c..d2ba720 100644
--- a/third_party/WebKit/Source/core/paint/TransformRecorder.cpp
+++ b/third_party/WebKit/Source/core/paint/TransformRecorder.cpp
@@ -11,7 +11,7 @@
 
 namespace blink {
 
-TransformRecorder::TransformRecorder(GraphicsContext& context, const DisplayItemClientWrapper& client, const AffineTransform& transform)
+TransformRecorder::TransformRecorder(GraphicsContext& context, const DisplayItemClient& client, const AffineTransform& transform)
     : m_context(context)
     , m_client(client)
 {
diff --git a/third_party/WebKit/Source/core/paint/TransformRecorder.h b/third_party/WebKit/Source/core/paint/TransformRecorder.h
index e0e91e10..4ad228b 100644
--- a/third_party/WebKit/Source/core/paint/TransformRecorder.h
+++ b/third_party/WebKit/Source/core/paint/TransformRecorder.h
@@ -17,12 +17,12 @@
 class CORE_EXPORT TransformRecorder {
     STACK_ALLOCATED();
 public:
-    TransformRecorder(GraphicsContext&, const DisplayItemClientWrapper&, const AffineTransform&);
+    TransformRecorder(GraphicsContext&, const DisplayItemClient&, const AffineTransform&);
     ~TransformRecorder();
 
 private:
     GraphicsContext& m_context;
-    DisplayItemClientWrapper m_client;
+    const DisplayItemClient& m_client;
     bool m_skipRecordingForIdentityTransform;
 };
 
diff --git a/third_party/WebKit/Source/core/paint/ViewPainter.cpp b/third_party/WebKit/Source/core/paint/ViewPainter.cpp
index 8d0600fe..c2f67f8 100644
--- a/third_party/WebKit/Source/core/paint/ViewPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/ViewPainter.cpp
@@ -56,7 +56,7 @@
     if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, m_layoutView, DisplayItem::BoxDecorationBackground, LayoutPoint()))
         return;
 
-    IntRect documentRect = m_layoutView.unscaledDocumentRect();
+    IntRect documentRect = m_layoutView.documentRect();
     const Document& document = m_layoutView.document();
     const FrameView& frameView = *m_layoutView.frameView();
     bool isMainFrame = !document.ownerElement();
diff --git a/third_party/WebKit/Source/core/paint/test_data/fixed-position.html b/third_party/WebKit/Source/core/paint/test_data/fixed-position.html
index e1c5393c..f503085 100644
--- a/third_party/WebKit/Source/core/paint/test_data/fixed-position.html
+++ b/third_party/WebKit/Source/core/paint/test_data/fixed-position.html
@@ -18,6 +18,8 @@
     top: 150px;
     width: 100px;
     height: 100px;
+
+    overflow: hidden;
 }
 
 .transformed-scroll {
diff --git a/third_party/WebKit/Source/core/paint/test_data/position-and-scroll.html b/third_party/WebKit/Source/core/paint/test_data/position-and-scroll.html
index 7ad9ad61..22bdf638 100644
--- a/third_party/WebKit/Source/core/paint/test_data/position-and-scroll.html
+++ b/third_party/WebKit/Source/core/paint/test_data/position-and-scroll.html
@@ -22,6 +22,7 @@
     top: 780px;
 
     transform: translateZ(0);
+    overflow: hidden;
 }
 
 #abs-pos {
@@ -30,6 +31,7 @@
     top: 456px;
 
     transform: translateZ(0);
+    overflow: hidden;
 }
 </style>
 <div id="scroller">
diff --git a/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp b/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp
index 576fc4c..8c4803a 100644
--- a/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp
@@ -688,13 +688,6 @@
     bool hadUseCurrentView = m_useCurrentView;
     m_useCurrentView = false;
 
-    if (fragmentIdentifier.startsWith("xpointer(")) {
-        // FIXME: XPointer references are ignored (https://bugs.webkit.org/show_bug.cgi?id=17491)
-        if (layoutObject && hadUseCurrentView)
-            markForLayoutAndParentResourceInvalidation(layoutObject);
-        return;
-    }
-
     if (fragmentIdentifier.startsWith("svgView(")) {
         if (!view)
             view = currentView(); // Create the SVGViewSpec.
diff --git a/third_party/WebKit/Source/core/svg/SVGTests.idl b/third_party/WebKit/Source/core/svg/SVGTests.idl
index c5af5722..6f85b31 100644
--- a/third_party/WebKit/Source/core/svg/SVGTests.idl
+++ b/third_party/WebKit/Source/core/svg/SVGTests.idl
@@ -29,8 +29,7 @@
 [
     NoInterfaceObject, // Always used on target of 'implements'
 ] interface SVGTests {
-
-    [RuntimeEnabled=SVG1DOM, MeasureAs=SVG1DOM] readonly attribute SVGStringList requiredFeatures;
-    [RuntimeEnabled=SVG1DOM, MeasureAs=SVG1DOM] readonly attribute SVGStringList requiredExtensions;
-    [RuntimeEnabled=SVG1DOM, MeasureAs=SVG1DOM] readonly attribute SVGStringList systemLanguage;
+    [RuntimeEnabled=SVG1DOM, MeasureAs=SVG1DOMSVGTests] readonly attribute SVGStringList requiredFeatures;
+    [RuntimeEnabled=SVG1DOM, MeasureAs=SVG1DOMSVGTests] readonly attribute SVGStringList requiredExtensions;
+    [RuntimeEnabled=SVG1DOM, MeasureAs=SVG1DOMSVGTests] readonly attribute SVGStringList systemLanguage;
 };
diff --git a/third_party/WebKit/Source/core/svg/SVGViewElement.idl b/third_party/WebKit/Source/core/svg/SVGViewElement.idl
index 45ae255..a1ede9de 100644
--- a/third_party/WebKit/Source/core/svg/SVGViewElement.idl
+++ b/third_party/WebKit/Source/core/svg/SVGViewElement.idl
@@ -26,7 +26,7 @@
 // http://www.w3.org/TR/SVG2/linking.html#InterfaceSVGViewElement
 
 interface SVGViewElement : SVGElement {
-    [RuntimeEnabled=SVG1DOM, MeasureAs=SVG1DOM] readonly attribute SVGStringList viewTarget;
+    [RuntimeEnabled=SVG1DOM, Measure] readonly attribute SVGStringList viewTarget;
 };
 
 SVGViewElement implements SVGFitToViewBox;
diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp b/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp
index 2141f69..a3c2663 100644
--- a/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp
+++ b/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp
@@ -316,7 +316,7 @@
         TransformRecorder transformRecorder(imagePicture.context(), *this, transform);
 
         view->updateAllLifecyclePhases();
-        view->paint(&imagePicture.context(), CullRect(enclosingIntRect(srcRect)));
+        view->paint(imagePicture.context(), CullRect(enclosingIntRect(srcRect)));
         ASSERT(!view->needsLayout());
     }
 
diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImage.h b/third_party/WebKit/Source/core/svg/graphics/SVGImage.h
index db762d1..81342cd 100644
--- a/third_party/WebKit/Source/core/svg/graphics/SVGImage.h
+++ b/third_party/WebKit/Source/core/svg/graphics/SVGImage.h
@@ -42,7 +42,7 @@
 class SVGImageChromeClient;
 class SVGImageForContainer;
 
-class SVGImage final : public Image {
+class SVGImage final : public Image, public DisplayItemClient {
 public:
     static PassRefPtr<SVGImage> create(ImageObserver* observer)
     {
@@ -77,8 +77,7 @@
 
     void updateUseCounters(Document&) const;
 
-    DisplayItemClient displayItemClient() const { return toDisplayItemClient(this); }
-    String debugName() const { return "SVGImage"; }
+    String debugName() const final { return "SVGImage"; }
 
 private:
     friend class AXLayoutObject;
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index ef4671f..511576e 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -2517,11 +2517,7 @@
     ScrollableArea* scrollableArea = layer->scrollableArea();
     if (!scrollableArea)
         return false;
-    ScrollAnimatorBase* animator = layer->scrollableArea()->scrollAnimator();
-    if (!animator)
-        return false;
-
-    return animator->setScrollbarsVisibleForTesting(visible);
+    return layer->scrollableArea()->scrollAnimator().setScrollbarsVisibleForTesting(visible);
 }
 
 void Internals::forceRestrictIFramePermissions()
diff --git a/third_party/WebKit/Source/devtools/devtools.gypi b/third_party/WebKit/Source/devtools/devtools.gypi
index 0f513c1..99df49a 100644
--- a/third_party/WebKit/Source/devtools/devtools.gypi
+++ b/third_party/WebKit/Source/devtools/devtools.gypi
@@ -43,6 +43,7 @@
             '<@(devtools_host_js_files)',
             '<@(devtools_main_js_files)',
             '<@(devtools_platform_js_files)',
+            '<@(devtools_sass_js_files)',
             '<@(devtools_sdk_js_files)',
             '<@(devtools_toolbox_bootstrap_js_files)',
             '<@(devtools_ui_js_files)',
@@ -126,6 +127,9 @@
             'front_end/host/ResourceLoader.js',
             'front_end/host/UserMetrics.js',
         ],
+        'devtools_sass_js_files': [
+            'front_end/sass/SASSSupport.js',
+        ],
         'devtools_screencast_js_files': [
             'front_end/screencast/screencastView.css',
             'front_end/screencast/ScreencastApp.js',
@@ -329,6 +333,7 @@
             'front_end/profiler/module.json',
             'front_end/promises/module.json',
             'front_end/resources/module.json',
+            'front_end/sass/module.json',
             'front_end/security/module.json',
             'front_end/screencast/module.json',
             'front_end/script_formatter_worker/module.json',
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 5418b484..ba8c199c 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js
@@ -336,7 +336,7 @@
             return false;
         if (typeof this._scriptSource === "undefined")
             return false;
-        if (!this._uiSourceCode.workingCopy().startsWith(this._scriptSource))
+        if (!this._uiSourceCode.workingCopy().startsWith(this._scriptSource.trimRight()))
             return true;
         var suffix = this._uiSourceCode.workingCopy().substr(this._scriptSource.length);
         return !!suffix.length && !suffix.match(WebInspector.Script.sourceURLRegex);
diff --git a/third_party/WebKit/Source/devtools/front_end/common/TextRange.js b/third_party/WebKit/Source/devtools/front_end/common/TextRange.js
index 9c1bcd9..59ae5d9 100644
--- a/third_party/WebKit/Source/devtools/front_end/common/TextRange.js
+++ b/third_party/WebKit/Source/devtools/front_end/common/TextRange.js
@@ -276,6 +276,32 @@
     {
         var sourceRange = this.toSourceRange(text);
         return text.substring(0, sourceRange.offset) + replacement + text.substring(sourceRange.offset + sourceRange.length);
+    },
+
+    /**
+     * @param {string} text
+     * @return {string}
+     */
+    extract: function(text)
+    {
+        var sourceRange = this.toSourceRange(text);
+        return text.substr(sourceRange.offset, sourceRange.length);
+    },
+
+    /**
+     * @param {number} lineNumber
+     * @param {number} columnNumber
+     * @return {boolean}
+     */
+    containsLocation: function(lineNumber, columnNumber)
+    {
+        if (this.startLine === this.endLine)
+            return this.startLine === lineNumber && this.startColumn <= columnNumber && columnNumber <= this.endColumn;
+        if (this.startLine === lineNumber)
+            return this.startColumn <= columnNumber;
+        if (this.endLine === lineNumber)
+            return columnNumber <= this.endColumn;
+        return this.startLine < lineNumber && lineNumber < this.endLine;
     }
 }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/components/DOMPresentationUtils.js b/third_party/WebKit/Source/devtools/front_end/components/DOMPresentationUtils.js
index 8682ffb..af4a7d8 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/DOMPresentationUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/DOMPresentationUtils.js
@@ -232,7 +232,7 @@
     {
         for (var stackFrame of stackTrace) {
             var row = createElement("tr");
-            row.createChild("td").textContent = WebInspector.beautifyFunctionName(stackFrame.functionName);
+            row.createChild("td", "function-name").textContent = WebInspector.beautifyFunctionName(stackFrame.functionName);
             row.createChild("td").textContent = " @ ";
             row.createChild("td").appendChild(linkifier.linkifyConsoleCallFrame(target, stackFrame));
             contentElement.appendChild(row);
diff --git a/third_party/WebKit/Source/devtools/front_end/components/domUtils.css b/third_party/WebKit/Source/devtools/front_end/components/domUtils.css
index 09397a03..36a3c9e 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/domUtils.css
+++ b/third_party/WebKit/Source/devtools/front_end/components/domUtils.css
@@ -29,6 +29,12 @@
 
 .stack-preview-container td {
     white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+.stack-preview-container .function-name {
+    max-width: 80em;
 }
 
 .node-label-name {
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/Spectrum.js b/third_party/WebKit/Source/devtools/front_end/elements/Spectrum.js
index bd1c8f6..f7f4bea 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/Spectrum.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/Spectrum.js
@@ -270,9 +270,7 @@
                 shadow = colorElement.createChild("div", "spectrum-palette-color spectrum-palette-color-shadow");
                 shadow.style.background = palette.colors[i];
                 colorElement.title = WebInspector.UIString(palette.colors[i] + ". Long-click to show alternate shades.");
-                var controller = new WebInspector.LongClickController(colorElement);
-                controller.enable();
-                controller.addEventListener(WebInspector.LongClickController.Events.LongClick, this._showLightnessShades.bind(this, colorElement, palette.colors[i]));
+                new WebInspector.LongClickController(colorElement, this._showLightnessShades.bind(this, colorElement, palette.colors[i]));
             }
             this._paletteContainer.appendChild(colorElement);
         }
@@ -296,7 +294,7 @@
     /**
      * @param {!Element} colorElement
      * @param {string} colorText
-     * @param {!WebInspector.Event} event
+     * @param {!Event} event
      */
     _showLightnessShades: function(colorElement, colorText, event)
     {
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
index a394990..93e7a2b4 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
@@ -119,7 +119,7 @@
     },
 
     /**
-     * @param {!WebInspector.Event} event
+     * @param {!Event} event
      */
     _onAddButtonLongClick: function(event)
     {
@@ -141,7 +141,7 @@
 
         contextMenuDescriptors.sort(compareDescriptors);
 
-        var contextMenu = new WebInspector.ContextMenu(/** @type {!Event} */(event.data));
+        var contextMenu = new WebInspector.ContextMenu(event);
         for (var i = 0; i < contextMenuDescriptors.length; ++i) {
             var descriptor = contextMenuDescriptors[i];
             contextMenu.appendItem(descriptor.text, descriptor.handler);
@@ -2947,9 +2947,9 @@
 WebInspector.StylesSidebarPane.createAddNewRuleButton = function(stylesSidebarPane)
 {
     var button = new WebInspector.ToolbarButton(WebInspector.UIString("New Style Rule"), "add-toolbar-item");
-    button.makeLongClickEnabled();
     button.addEventListener("click", stylesSidebarPane._createNewRuleInViaInspectorStyleSheet, stylesSidebarPane);
-    button.addEventListener("longClickDown", stylesSidebarPane._onAddButtonLongClick, stylesSidebarPane);
+    button.element.createChild("div", "long-click-glyph toolbar-button-theme");
+    new WebInspector.LongClickController(button.element, stylesSidebarPane._onAddButtonLongClick.bind(stylesSidebarPane));
     WebInspector.context.addFlavorChangeListener(WebInspector.DOMNode, onNodeChanged);
     onNodeChanged();
     return button;
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js
index c5722c5..0b63980 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js
@@ -5,12 +5,11 @@
 /**
  * @constructor
  * @extends {WebInspector.VBox}
- * @param {!WebInspector.InspectedPagePlaceholder} inspectedPagePlaceholder
+ * @param {function()} pageResizeCallback
  */
-WebInspector.DeviceModeView = function(inspectedPagePlaceholder)
+WebInspector.DeviceModeView = function(pageResizeCallback)
 {
     WebInspector.VBox.call(this, true);
-    WebInspector.DeviceModeView._instance = this;
     this.setMinimumSize(150, 150);
     this.element.classList.add("device-mode-view");
     this.registerRequiredCSS("emulation/deviceModeView.css");
@@ -21,32 +20,25 @@
     // TODO(dgozman): remove CountUpdated event.
     this._showMediaInspectorSetting = WebInspector.settings.createSetting("showMediaQueryInspector", false);
     this._showMediaInspectorSetting.addChangeListener(this._updateUI, this);
-    this._showDeviceModeSetting = WebInspector.settings.createSetting("showDeviceMode", true);
-    this._showDeviceModeSetting.addChangeListener(this._showDeviceModeSettingChanged, this);
 
-    this._inspectedPagePlaceholder = inspectedPagePlaceholder;
+    this._pageResizeCallback = pageResizeCallback;
     this._createUI();
     WebInspector.zoomManager.addEventListener(WebInspector.ZoomManager.Events.ZoomChanged, this._updateUI, this);
-
-    this._openButton = new WebInspector.ToolbarButton(WebInspector.UIString("Show device toolbar"), "emulation-toolbar-item");
-    this._openButton.setVisible(!this._showDeviceModeSetting.get());
-    this._openButton.addEventListener("click", this._showDeviceModeSetting.set.bind(this._showDeviceModeSetting, true));
 };
 
-/** @type {!WebInspector.DeviceModeView} */
-WebInspector.DeviceModeView._instance;
-
 WebInspector.DeviceModeView.prototype = {
     _createUI: function()
     {
-        this._toolbar = new WebInspector.DeviceModeView.Toolbar(this._model, this._showMediaInspectorSetting, this._showDeviceModeSetting);
+        this._toolbar = new WebInspector.DeviceModeView.Toolbar(this._model, this._showMediaInspectorSetting);
         this.contentElement.appendChild(this._toolbar.element());
-        this._toolbar.element().classList.toggle("hidden", !this._showDeviceModeSetting.get());
 
         var contentClip = this.contentElement.createChild("div", "device-mode-content-clip vbox");
         this._mediaInspectorContainer = contentClip.createChild("div", "device-mode-media-container");
         this._contentArea = contentClip.createChild("div", "device-mode-content-area");
 
+        this._deviceBlueprints = this._contentArea.createChild("div", "fill");
+        WebInspector.emulatedDevicesList.addEventListener(WebInspector.EmulatedDevicesList.Events.StandardDevicesUpdated, this._updateBlueprints, this);
+
         this._screenArea = this._contentArea.createChild("div", "device-mode-screen-area");
         this._screenImage = this._screenArea.createChild("img", "device-mode-screen-image hidden");
         this._screenImage.addEventListener("load", this._onScreenImageLoaded.bind(this, true), false);
@@ -67,8 +59,12 @@
         this._createResizer(this._heightResizerElement, false, true);
 
         this._pageArea = this._screenArea.createChild("div", "device-mode-page-area");
-        this._inspectedPagePlaceholder.clearMinimumSizeAndMargins();
-        this._inspectedPagePlaceholder.show(this._pageArea);
+        this._pageArea.createChild("content");
+    },
+
+    toggleDeviceMode: function()
+    {
+        this._toolbar.toggleDeviceMode();
     },
 
     /**
@@ -142,11 +138,6 @@
         this._model.resumeScaleChanges();
     },
 
-    updatePageResizer: function()
-    {
-        // TODO(dgozman): remove once we switch over.
-    },
-
     _updateUI: function()
     {
         if (!this.isShowing())
@@ -156,6 +147,11 @@
         var resizePagePlaceholder = false;
         var resizeSelf = false;
 
+        if (this._cachedModelType !== this._model.type()) {
+            this._updateBlueprints();
+            this._cachedModelType = this._model.type();
+        }
+
         var cssScreenRect = this._model.screenRect().scale(1 / zoomFactor);
         if (!cssScreenRect.isEqual(this._cachedCssScreenRect)) {
             this._screenArea.style.left = cssScreenRect.left + "px";
@@ -198,12 +194,30 @@
         this._toolbar.update();
         this._loadScreenImage(this._model.screenImage());
         if (resizePagePlaceholder)
-            this._inspectedPagePlaceholder.onResize();
+            this._pageResizeCallback.call(null);
         this._mediaInspector.setAxisTransform(-cssScreenRect.left / this._model.scale(), this._model.scale());
         if (resizeSelf)
             this.onResize();
     },
 
+    _updateBlueprints: function()
+    {
+        this._deviceBlueprints.removeChildren();
+        if (this._model.type() !== WebInspector.DeviceModeModel.Type.Responsive)
+            return;
+        var devices = WebInspector.emulatedDevicesList.standard();
+        devices.sort((device1, device2) => device2.vertical.width * device2.vertical.height - device1.vertical.width * device1.vertical.height);
+        for (var device of devices) {
+            if (!device.show())
+                continue;
+            var blueprintContainer = this._deviceBlueprints.createChild("div", "device-mode-blueprint-container fill");
+            var blueprint = blueprintContainer.createChild("div", "device-mode-blueprint");
+            blueprint.style.width = device.vertical.width + "px";
+            blueprint.style.height = device.vertical.height + "px";
+            blueprint.createChild("span").textContent = device.title;
+        }
+    },
+
     /**
      * @param {string} srcset
      */
@@ -224,18 +238,6 @@
         this._screenImage.classList.toggle("hidden", !success);
     },
 
-    _showDeviceModeSettingChanged: function()
-    {
-        var show = this._showDeviceModeSetting.get();
-        this._openButton.setVisible(!show);
-        this._toolbar.element().classList.toggle("hidden", !show);
-        if (show)
-            this._toolbar.restore();
-        else
-            this._model.emulate(WebInspector.DeviceModeModel.Type.None, null, null);
-        this.onResize();
-    },
-
     /**
      * @override
      */
@@ -255,8 +257,7 @@
     wasShown: function()
     {
         this._mediaInspector.setEnabled(true);
-        if (this._showDeviceModeSetting.get())
-            this._toolbar.restore();
+        this._toolbar.restore();
     },
 
     /**
@@ -273,16 +274,12 @@
 /**
  * @param {!WebInspector.DeviceModeModel} model
  * @param {!WebInspector.Setting} showMediaInspectorSetting
- * @param {!WebInspector.Setting} showDeviceModeSetting
  * @constructor
  */
-WebInspector.DeviceModeView.Toolbar = function(model, showMediaInspectorSetting, showDeviceModeSetting)
+WebInspector.DeviceModeView.Toolbar = function(model, showMediaInspectorSetting)
 {
-    WebInspector.DeviceModeView.Toolbar._instance = this;
-
     this._model = model;
     this._showMediaInspectorSetting = showMediaInspectorSetting;
-    this._showDeviceModeSetting = showDeviceModeSetting;
     /** @type {!Map<!WebInspector.EmulatedDevice, !WebInspector.EmulatedDevice.Mode>} */
     this._lastMode = new Map();
     /** @type {?WebInspector.EmulatedDevice} */
@@ -365,9 +362,6 @@
     this._restored = false;
 }
 
-/** @type {!WebInspector.DeviceModeView.Toolbar} */
-WebInspector.DeviceModeView.Toolbar._instance;
-
 WebInspector.DeviceModeView.Toolbar.prototype = {
     /**
      * @param {!WebInspector.ContextMenu} contextMenu
@@ -433,9 +427,6 @@
 
         contextMenu.appendCheckboxItem(WebInspector.UIString("Show media queries"), this._toggleMediaInspector.bind(this), this._showMediaInspectorSetting.get(), this._model.type() === WebInspector.DeviceModeModel.Type.None);
         contextMenu.appendItem(WebInspector.UIString("Configure network\u2026"), this._openNetworkConfig.bind(this), false);
-
-        contextMenu.appendSeparator();
-        contextMenu.appendItem(WebInspector.UIString("Hide device toolbar"), this._showDeviceModeSetting.set.bind(this._showDeviceModeSetting, false), false);
     },
 
     _toggleMediaInspector: function()
@@ -760,12 +751,9 @@
         this._applyType(/** @type {!WebInspector.DeviceModeModel.Type} */ (this._persistenceSetting.get().type));
     },
 
-    _toggleDeviceMode: function()
+    toggleDeviceMode: function()
     {
-        if (!this._showDeviceModeSetting.get())
-            this._showDeviceModeSetting.set(true);
-        else
-            this._applyType(this._model.type() === WebInspector.DeviceModeModel.Type.None ? (this._previousModelType || WebInspector.DeviceModeModel.Type.Responsive) : WebInspector.DeviceModeModel.Type.None);
+        this._applyType(this._model.type() === WebInspector.DeviceModeModel.Type.None ? (this._previousModelType || WebInspector.DeviceModeModel.Type.Responsive) : WebInspector.DeviceModeModel.Type.None);
     },
 
     /**
@@ -799,29 +787,69 @@
      */
     handleAction: function(context, actionId)
     {
-        if (actionId === "emulation.toggle-device-mode" && WebInspector.DeviceModeView.Toolbar._instance) {
-            WebInspector.DeviceModeView.Toolbar._instance._toggleDeviceMode();
+        if (actionId === "emulation.toggle-device-mode" && WebInspector.DeviceModeView._wrapperInstance) {
+            WebInspector.DeviceModeView._wrapperInstance._toggleDeviceMode();
+            return true;
+        }
+        if (actionId === "emulation.toggle-device-toolbar" && WebInspector.DeviceModeView._wrapperInstance) {
+            WebInspector.DeviceModeView._wrapperInstance._toggleDeviceToolbar();
             return true;
         }
         return false;
     }
 }
 
+
 /**
+ * @extends {WebInspector.VBox}
+ * @param {!WebInspector.InspectedPagePlaceholder} inspectedPagePlaceholder
  * @constructor
- * @implements {WebInspector.ToolbarItem.Provider}
  */
-WebInspector.DeviceModeView.ButtonProvider = function()
+WebInspector.DeviceModeView.Wrapper = function(inspectedPagePlaceholder)
 {
+    WebInspector.VBox.call(this);
+    WebInspector.DeviceModeView._wrapperInstance = this;
+    this._inspectedPagePlaceholder = inspectedPagePlaceholder;
+    this._deviceModeView = new WebInspector.DeviceModeView(this._resizePlaceholder.bind(this));
+    this._showDeviceToolbarSetting = WebInspector.settings.createSetting("emulation.showDeviceToolbar", true);
+    this._showDeviceToolbarSetting.addChangeListener(this._update, this);
+    this._update();
 }
 
-WebInspector.DeviceModeView.ButtonProvider.prototype = {
-    /**
-     * @override
-     * @return {?WebInspector.ToolbarItem}
-     */
-    item: function()
+/** @type {!WebInspector.DeviceModeView.Wrapper} */
+WebInspector.DeviceModeView._wrapperInstance;
+
+WebInspector.DeviceModeView.Wrapper.prototype = {
+    _toggleDeviceMode: function()
     {
-        return WebInspector.DeviceModeView._instance ? WebInspector.DeviceModeView._instance._openButton : null;
-    }
+        if (this._showDeviceToolbarSetting.get())
+            this._deviceModeView.toggleDeviceMode();
+    },
+
+    _toggleDeviceToolbar: function()
+    {
+        this._showDeviceToolbarSetting.set(!this._showDeviceToolbarSetting.get());
+    },
+
+    _update: function()
+    {
+        if (this._showDeviceToolbarSetting.get()) {
+            this._deviceModeView.show(this.element);
+            this._inspectedPagePlaceholder.clearMinimumSizeAndMargins();
+            this._inspectedPagePlaceholder.show(this._deviceModeView.element);
+        } else {
+            this._deviceModeView.detach();
+            this._inspectedPagePlaceholder.restoreMinimumSizeAndMargins();
+            this._inspectedPagePlaceholder.show(this.element);
+            this._deviceModeView._model.emulate(WebInspector.DeviceModeModel.Type.None, null, null);
+        }
+    },
+
+    _resizePlaceholder: function()
+    {
+        if (this._showDeviceToolbarSetting.get())
+            this._inspectedPagePlaceholder.onResize();
+    },
+
+    __proto__: WebInspector.VBox.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css b/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css
index fad8e75..000f84cb 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css
@@ -152,3 +152,36 @@
     display: flex;
     background-color: #fcfcfc;
 }
+
+.device-mode-blueprint-container {
+    display: flex;
+    justify-content: center;
+    pointer-events: none;
+}
+
+.device-mode-blueprint {
+    display: flex;
+    border-left: 1px dashed #dcdcdc;
+    border-right: 1px dashed #dcdcdc;
+    border-bottom: 1px dashed #dcdcdc;
+    flex-direction: column;
+    justify-content: flex-end;
+    text-align: end;
+    color: #aaa;
+    pointer-events: initial;
+}
+
+.device-mode-blueprint:hover {
+    border-color: #aaa;
+}
+
+.device-mode-blueprint > span {
+    transition: opacity 150ms;
+    opacity: 0;
+    padding: 3px;
+}
+
+.device-mode-blueprint:hover > span {
+    opacity: 1;
+    display: initial;
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/module.json b/third_party/WebKit/Source/devtools/front_end/emulation/module.json
index effe9c7..92dca2e3 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/module.json
@@ -18,14 +18,6 @@
             "location": "main-toolbar-left"
         },
         {
-            "type": "@WebInspector.ToolbarItem.Provider",
-            "className": "WebInspector.DeviceModeView.ButtonProvider",
-            "condition": "can_dock",
-            "experiment": "deviceMode",
-            "order": 1,
-            "location": "main-toolbar-left"
-        },
-        {
             "type": "@WebInspector.ActionDelegate",
             "actionId": "emulation.toggle-device-mode",
             "className": "WebInspector.ToggleDeviceModeActionDelegate",
@@ -61,6 +53,13 @@
             ]
         },
         {
+            "type": "@WebInspector.ActionDelegate",
+            "actionId": "emulation.toggle-device-toolbar",
+            "className": "WebInspector.DeviceModeView.ActionDelegate",
+            "experiment": "deviceMode",
+            "title": "Toggle device toolbar"
+        },
+        {
             "type": "@WebInspector.Revealer",
             "contextTypes": ["WebInspector.OverridesSupport"],
             "className": "WebInspector.OverridesView.Revealer"
@@ -89,6 +88,12 @@
             "actionId": "emulation.show-sensors"
         },
         {
+            "type": "context-menu-item",
+            "location": "mainMenu/navigate",
+            "order": 10,
+            "actionId": "emulation.toggle-device-toolbar"
+        },
+        {
             "type": "drawer-view",
             "name": "sensors",
             "title": "Sensors",
diff --git a/third_party/WebKit/Source/devtools/front_end/inspector.json b/third_party/WebKit/Source/devtools/front_end/inspector.json
index ae221b3..b800cf3f 100644
--- a/third_party/WebKit/Source/devtools/front_end/inspector.json
+++ b/third_party/WebKit/Source/devtools/front_end/inspector.json
@@ -29,6 +29,7 @@
     { "name": "promises" },
     { "name": "snippets" },
     { "name": "diff" },
+    { "name": "sass" },
     { "name": "accessibility" },
     { "name": "animation" },
     { "name": "screencast", "condition": "remoteFrontend", "type": "remote" },
diff --git a/third_party/WebKit/Source/devtools/front_end/main/AdvancedApp.js b/third_party/WebKit/Source/devtools/front_end/main/AdvancedApp.js
index e807be6..9051ede 100644
--- a/third_party/WebKit/Source/devtools/front_end/main/AdvancedApp.js
+++ b/third_party/WebKit/Source/devtools/front_end/main/AdvancedApp.js
@@ -29,7 +29,7 @@
         this._inspectedPagePlaceholder = new WebInspector.InspectedPagePlaceholder();
         this._inspectedPagePlaceholder.addEventListener(WebInspector.InspectedPagePlaceholder.Events.Update, this._onSetInspectedPageBounds.bind(this), this);
         if (Runtime.experiments.isEnabled("deviceMode"))
-            this._responsiveDesignView = new WebInspector.DeviceModeView(this._inspectedPagePlaceholder);
+            this._responsiveDesignView = new WebInspector.DeviceModeView.Wrapper(this._inspectedPagePlaceholder);
         else
             this._responsiveDesignView = new WebInspector.ResponsiveDesignView(this._inspectedPagePlaceholder);
 
diff --git a/third_party/WebKit/Source/devtools/front_end/sass/SASSSupport.js b/third_party/WebKit/Source/devtools/front_end/sass/SASSSupport.js
new file mode 100644
index 0000000..4c9a9f6
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/sass/SASSSupport.js
@@ -0,0 +1,335 @@
+// 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.
+
+WebInspector.SASSSupport = {}
+
+/**
+ * @constructor
+ * @param {string} url
+ * @param {string} text
+ */
+WebInspector.SASSSupport.ASTDocument = function(url, text)
+{
+    this.url = url;
+    this.text = text;
+}
+
+/**
+ * @param {string} url
+ * @param {string} text
+ * @param {!WebInspector.TokenizerFactory} tokenizerFactory
+ * @return {!WebInspector.SASSSupport.AST}
+ */
+WebInspector.SASSSupport.parseSCSS = function(url, text, tokenizerFactory)
+{
+    var document = new WebInspector.SASSSupport.ASTDocument(url, text);
+    var result = WebInspector.SASSSupport._innerParseSCSS(document, tokenizerFactory);
+
+    var rules = [
+        new WebInspector.SASSSupport.Rule(document, "variables", result.variables),
+        new WebInspector.SASSSupport.Rule(document, "properties", result.properties),
+        new WebInspector.SASSSupport.Rule(document, "mixins", result.mixins)
+    ];
+
+    return new WebInspector.SASSSupport.AST(document, rules);
+}
+
+/** @enum {string} */
+WebInspector.SASSSupport.SCSSParserStates = {
+    Initial: "Initial",
+    PropertyName: "PropertyName",
+    PropertyValue: "PropertyValue",
+    VariableName: "VariableName",
+    VariableValue: "VariableValue",
+    MixinName: "MixinName",
+    MixinValue: "MixinValue",
+    Media: "Media",
+}
+
+/**
+ * @param {!WebInspector.SASSSupport.ASTDocument} document
+ * @param {!WebInspector.TokenizerFactory} tokenizerFactory
+ * @return {!{variables: !Array<!WebInspector.SASSSupport.Property>, properties: !Array<!WebInspector.SASSSupport.Property>, mixins: !Array<!WebInspector.SASSSupport.Property>}}
+ */
+WebInspector.SASSSupport._innerParseSCSS = function(document, tokenizerFactory)
+{
+    var lines = document.text.split("\n");
+    var properties = [];
+    var variables = [];
+    var mixins = [];
+
+    var States = WebInspector.SASSSupport.SCSSParserStates;
+    var state = States.Initial;
+    var propertyName, propertyValue;
+    var variableName, variableValue;
+    var mixinName, mixinValue;
+    var UndefTokenType = {};
+
+    /**
+     * @param {string} tokenValue
+     * @param {?string} tokenTypes
+     * @param {number} column
+     * @param {number} newColumn
+     */
+    function processToken(tokenValue, tokenTypes, column, newColumn)
+    {
+        var tokenType = tokenTypes ? tokenTypes.split(" ").keySet() : UndefTokenType;
+        switch (state) {
+        case States.Initial:
+            if (tokenType["css-variable-2"]) {
+                variableName = new WebInspector.SASSSupport.TextNode(document, tokenValue, new WebInspector.TextRange(lineNumber, column, lineNumber, newColumn));
+                state = States.VariableName;
+            } else if (tokenType["css-property"] || tokenType["css-meta"]) {
+                propertyName = new WebInspector.SASSSupport.TextNode(document, tokenValue, new WebInspector.TextRange(lineNumber, column, lineNumber, newColumn));
+                state = States.PropertyName;
+            } else if (tokenType["css-def"] && tokenValue === "@include") {
+                mixinName = new WebInspector.SASSSupport.TextNode(document, tokenValue, new WebInspector.TextRange(lineNumber, column, lineNumber, newColumn));
+                state = States.MixinName;
+            } else if (tokenType["css-comment"]) {
+                // Support only a one-line comments.
+                if (tokenValue.substring(0, 2) !== "/*" || tokenValue.substring(tokenValue.length - 2) !== "*/")
+                    break;
+                var uncommentedText = tokenValue.substring(2, tokenValue.length - 2);
+                var fakeRuleText = "a{\n" + uncommentedText + "}";
+                var fakeDocument = new WebInspector.SASSSupport.ASTDocument("", fakeRuleText);
+                var result = WebInspector.SASSSupport._innerParseSCSS(fakeDocument, tokenizerFactory);
+                if (result.properties.length === 1 && result.variables.length === 0 && result.mixins.length === 0) {
+                    var disabledProperty = result.properties[0];
+                    // We should offset property to current coordinates.
+                    var offset = column + 2;
+                    var nameRange = new WebInspector.TextRange(lineNumber, disabledProperty.name.range.startColumn + offset,
+                            lineNumber, disabledProperty.name.range.endColumn + offset);
+                    var valueRange = new WebInspector.TextRange(lineNumber, disabledProperty.value.range.startColumn + offset,
+                            lineNumber, disabledProperty.value.range.endColumn + offset);
+                    var name = new WebInspector.SASSSupport.TextNode(document, disabledProperty.name.text, nameRange);
+                    var value = new WebInspector.SASSSupport.TextNode(document, disabledProperty.value.text, valueRange);
+                    var range = new WebInspector.TextRange(lineNumber, column, lineNumber, newColumn);
+                    var property = new WebInspector.SASSSupport.Property(document, name, value, range, true);
+                    properties.push(property);
+                }
+            } else if (tokenType["css-def"] && tokenValue === "@media") {
+                state = States.Media;
+            }
+            break;
+        case States.VariableName:
+            if (tokenValue === ")" && tokenType === UndefTokenType) {
+                state = States.Initial;
+            } else if (tokenValue === ":" && tokenType === UndefTokenType) {
+                state = States.VariableValue;
+                variableValue = new WebInspector.SASSSupport.TextNode(document, "", WebInspector.TextRange.createFromLocation(lineNumber, newColumn));
+            } else if (tokenType !== UndefTokenType) {
+                state = States.Initial;
+            }
+            break;
+        case States.VariableValue:
+            if (tokenValue === ";" && tokenType === UndefTokenType) {
+                variableValue.range.endLine = lineNumber;
+                variableValue.range.endColumn = column;
+                var variable = new WebInspector.SASSSupport.Property(document, variableName, variableValue, variableName.range.clone(), false);
+                variable.range.endLine = lineNumber;
+                variable.range.endColumn = newColumn;
+                variables.push(variable);
+                state = States.Initial;
+            } else {
+                variableValue.text += tokenValue;
+            }
+            break;
+        case States.PropertyName:
+            if (tokenValue === ":" && tokenType === UndefTokenType) {
+                state = States.PropertyValue;
+                propertyName.range.endLine = lineNumber;
+                propertyName.range.endColumn = column;
+                propertyValue = new WebInspector.SASSSupport.TextNode(document, "", WebInspector.TextRange.createFromLocation(lineNumber, newColumn));
+            } else if (tokenType["css-property"]) {
+                propertyName.text += tokenValue;
+            }
+            break;
+        case States.PropertyValue:
+            if ((tokenValue === "}" || tokenValue === ";") && tokenType === UndefTokenType) {
+                propertyValue.range.endLine = lineNumber;
+                propertyValue.range.endColumn = column;
+                var property = new WebInspector.SASSSupport.Property(document, propertyName, propertyValue, propertyName.range.clone(), false);
+                property.range.endLine = lineNumber;
+                property.range.endColumn = newColumn;
+                properties.push(property);
+                state = States.Initial;
+            } else {
+                propertyValue.text += tokenValue;
+            }
+            break;
+        case States.MixinName:
+            if (tokenValue === "(" && tokenType === UndefTokenType) {
+                state = States.MixinValue;
+                mixinName.range.endLine = lineNumber;
+                mixinName.range.endColumn = column;
+                mixinValue = new WebInspector.SASSSupport.TextNode(document, "", WebInspector.TextRange.createFromLocation(lineNumber, newColumn));
+            } else if (tokenValue === ";" && tokenType === UndefTokenType) {
+                state = States.Initial;
+                mixinValue = null;
+            } else {
+                mixinName.text += tokenValue;
+            }
+            break;
+        case States.MixinValue:
+            if (tokenValue === ")" && tokenType === UndefTokenType) {
+                mixinValue.range.endLine = lineNumber;
+                mixinValue.range.endColumn = column;
+                var mixin = new WebInspector.SASSSupport.Property(document, mixinName, /** @type {!WebInspector.SASSSupport.TextNode} */(mixinValue), mixinName.range.clone(), false);
+                mixin.range.endLine = lineNumber;
+                mixin.range.endColumn = newColumn;
+                mixins.push(mixin);
+                state = States.Initial;
+            } else {
+                mixinValue.text += tokenValue;
+            }
+            break;
+        case States.Media:
+            if (tokenValue === "{" && tokenType === UndefTokenType)
+                state = States.Initial;
+            break;
+        default:
+            console.assert(false, "Unknown SASS parser state.");
+        }
+    }
+    var tokenizer = tokenizerFactory.createTokenizer("text/x-scss");
+    var lineNumber;
+    for (lineNumber = 0; lineNumber < lines.length; ++lineNumber) {
+        var line = lines[lineNumber];
+        tokenizer(line, processToken);
+        processToken("\n", null, line.length, line.length + 1);
+    }
+    return {
+        variables: variables,
+        properties: properties,
+        mixins: mixins
+    };
+}
+
+/**
+ * @constructor
+ * @param {!WebInspector.SASSSupport.ASTDocument} document
+ */
+WebInspector.SASSSupport.Node = function(document)
+{
+    this.document = document;
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.SASSSupport.Node}
+ * @param {!WebInspector.SASSSupport.ASTDocument} document
+ * @param {string} text
+ * @param {!WebInspector.TextRange} range
+ */
+WebInspector.SASSSupport.TextNode = function(document, text, range)
+{
+    WebInspector.SASSSupport.Node.call(this, document);
+    this.text = text;
+    this.range = range;
+}
+
+WebInspector.SASSSupport.TextNode.prototype = {
+    /**
+     * @return {!WebInspector.SASSSupport.TextNode}
+     */
+    clone: function()
+    {
+        return new WebInspector.SASSSupport.TextNode(this.document, this.text, this.range.clone());
+    },
+
+    __proto__: WebInspector.SASSSupport.Node.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.SASSSupport.Node}
+ * @param {!WebInspector.SASSSupport.ASTDocument} document
+ * @param {!WebInspector.SASSSupport.TextNode} name
+ * @param {!WebInspector.SASSSupport.TextNode} value
+ * @param {!WebInspector.TextRange} range
+ * @param {boolean} disabled
+ */
+WebInspector.SASSSupport.Property = function(document, name, value, range, disabled)
+{
+    WebInspector.SASSSupport.Node.call(this, document);
+    this.name = name;
+    this.value = value;
+    this.range = range;
+    this.name.parent = this;
+    this.value.parent = this;
+    this.disabled = disabled;
+}
+
+WebInspector.SASSSupport.Property.prototype = {
+    /**
+     * @return {!WebInspector.SASSSupport.Property}
+     */
+    clone: function()
+    {
+        return new WebInspector.SASSSupport.Property(this.document, this.name.clone(), this.value.clone(), this.range.clone(), this.disabled);
+    },
+
+    __proto__: WebInspector.SASSSupport.Node.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.SASSSupport.Node}
+ * @param {!WebInspector.SASSSupport.ASTDocument} document
+ * @param {string} selector
+ * @param {!Array<!WebInspector.SASSSupport.Property>} properties
+ */
+WebInspector.SASSSupport.Rule = function(document, selector, properties)
+{
+    WebInspector.SASSSupport.Node.call(this, document);
+    this.selector = selector;
+    this.properties = properties;
+    for (var i = 0; i < this.properties.length; ++i)
+        this.properties[i].parent = this;
+}
+
+WebInspector.SASSSupport.Rule.prototype = {
+    /**
+     * @return {!WebInspector.SASSSupport.Rule}
+     */
+    clone: function()
+    {
+        var properties = [];
+        for (var i = 0; i < this.properties.length; ++i)
+            properties.push(this.properties[i].clone());
+        return new WebInspector.SASSSupport.Rule(this.document, this.selector, properties);
+    },
+
+    __proto__: WebInspector.SASSSupport.Node.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.SASSSupport.Node}
+ * @param {!WebInspector.SASSSupport.ASTDocument} document
+ * @param {!Array<!WebInspector.SASSSupport.Rule>} rules
+ */
+WebInspector.SASSSupport.AST = function(document, rules)
+{
+    WebInspector.SASSSupport.Node.call(this, document);
+    this.rules = rules;
+    for (var i = 0; i < rules.length; ++i)
+        rules[i].parent = this;
+}
+
+WebInspector.SASSSupport.AST.prototype = {
+    /**
+     * @return {!WebInspector.SASSSupport.AST}
+     */
+    clone: function()
+    {
+        var rules = [];
+        for (var i = 0; i < this.rules.length; ++i)
+            rules.push(this.rules[i].clone());
+        return new WebInspector.SASSSupport.AST(this.document, rules);
+    },
+
+    __proto__: WebInspector.SASSSupport.Node.prototype
+}
+
diff --git a/third_party/WebKit/Source/devtools/front_end/sass/module.json b/third_party/WebKit/Source/devtools/front_end/sass/module.json
new file mode 100644
index 0000000..fccff85d
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/sass/module.json
@@ -0,0 +1,6 @@
+{
+    "dependencies": ["platform", "common", "diff"],
+    "scripts": [
+        "SASSSupport.js"
+    ]
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js
index 34ae65a..ec4c6aa 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js
@@ -1855,8 +1855,17 @@
      */
     _trimSourceURL: function(text)
     {
-        var sourceURLRegex = /\n[\040\t]*\/\*#[\040\t]sourceURL=[\040\t]*([^\s]*)[\040\t]*\*\/[\040\t]*$/mg;
-        return text.replace(sourceURLRegex, "");
+        var sourceURLIndex = text.lastIndexOf("/*# sourceURL=");
+        if (sourceURLIndex === -1)
+            return text;
+        var sourceURLLineIndex = text.lastIndexOf("\n", sourceURLIndex);
+        if (sourceURLLineIndex === -1)
+            return text;
+        var sourceURLLine = text.substr(sourceURLLineIndex + 1).split("\n", 1)[0];
+        var sourceURLRegex = /[\040\t]*\/\*# sourceURL=[\040\t]*([^\s]*)[\040\t]*\*\/[\040\t]*$/;
+        if (sourceURLLine.search(sourceURLRegex) === -1)
+            return text;
+        return text.substr(0, sourceURLLineIndex) + text.substr(sourceURLLineIndex + sourceURLLine.length + 1);
     },
 
     /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/Script.js b/third_party/WebKit/Source/devtools/front_end/sdk/Script.js
index d363656c..3d5c2d3 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/Script.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/Script.js
@@ -62,7 +62,7 @@
     SourceMapURLAdded: "SourceMapURLAdded",
 }
 
-WebInspector.Script.sourceURLRegex = /\n[\040\t]*\/\/#\ssourceURL=\s*(\S*?)\s*$/mg;
+WebInspector.Script.sourceURLRegex = /^[\040\t]*\/\/# sourceURL=\s*(\S*?)\s*$/m;
 
 /**
  * @param {string} source
@@ -70,7 +70,16 @@
  */
 WebInspector.Script._trimSourceURLComment = function(source)
 {
-    return source.replace(WebInspector.Script.sourceURLRegex, "");
+    var sourceURLIndex = source.lastIndexOf("//# sourceURL=");
+    if (sourceURLIndex === -1)
+        return source;
+    var sourceURLLineIndex = source.lastIndexOf("\n", sourceURLIndex);
+    if (sourceURLLineIndex === -1)
+        return source;
+    var sourceURLLine = source.substr(sourceURLLineIndex + 1).split("\n", 1)[0];
+    if (sourceURLLine.search(WebInspector.Script.sourceURLRegex) === -1)
+        return source;
+    return source.substr(0, sourceURLLineIndex) + source.substr(sourceURLLineIndex + sourceURLLine.length + 1);
 }
 
 
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
index dc69872..ef478dd 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
@@ -573,11 +573,11 @@
     _setUIControlsEnabled: function(enabled)
     {
         /**
-         * @param {!WebInspector.ToolbarButton} toolbarItem
+         * @param {!WebInspector.ToolbarButton} toolbarButton
          */
-        function handler(toolbarItem)
+        function handler(toolbarButton)
         {
-            toolbarItem.setEnabled(enabled);
+            toolbarButton.setEnabled(enabled);
         }
         this._recordingOptionUIControls.forEach(handler);
     },
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 20c5cbf..930972b 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
@@ -581,29 +581,31 @@
  */
 WebInspector.TimelineUIUtils._buildTraceEventDetailsSynchronously = function(event, model, linkifier, detailed, relatedNodesMap)
 {
-    var fragment = createDocumentFragment();
     var stats = {};
     var recordTypes = WebInspector.TimelineModel.RecordType;
 
     // This message may vary per event.name;
     var relatedNodeLabel;
 
-    var contentHelper = new WebInspector.TimelineDetailsContentHelper(model.target(), linkifier, relatedNodesMap, false);
-
-    if (event.warning)
-        contentHelper.appendWarningRow(event);
-
-    if (detailed) {
-        contentHelper.appendTextRow(WebInspector.UIString("Type"), WebInspector.TimelineUIUtils.eventTitle(event));
-        contentHelper.appendTextRow(WebInspector.UIString("Total Time"), Number.millisToString(event.duration || 0, true));
-        contentHelper.appendTextRow(WebInspector.UIString("Self Time"), Number.millisToString(event.selfTime, true));
-    }
-    if (event.previewElement)
-        contentHelper.appendElementRow(WebInspector.UIString("Preview"), event.previewElement);
+    var contentHelper = new WebInspector.TimelineDetailsContentHelper(model.target(), linkifier);
+    contentHelper.addSection(WebInspector.TimelineUIUtils.eventTitle(event), WebInspector.TimelineUIUtils.eventStyle(event).category);
 
     var eventData = event.args["data"];
     var initiator = event.initiator;
 
+    if (event.warning)
+        contentHelper.appendWarningRow(event);
+    if (event.name === recordTypes.JSFrame) {
+        var deoptReason = eventData["deoptReason"];
+        if (deoptReason && deoptReason != "no reason")
+            contentHelper.appendWarningRow(event, WebInspector.TimelineModel.WarningType.V8Deopt);
+    }
+
+    if (detailed) {
+        contentHelper.appendTextRow(WebInspector.UIString("Self Time"), Number.millisToString(event.selfTime, true));
+        contentHelper.appendTextRow(WebInspector.UIString("Total Time"), Number.millisToString(event.duration || 0, true));
+    }
+
     switch (event.name) {
     case recordTypes.GCEvent:
     case recordTypes.MajorGC:
@@ -615,9 +617,6 @@
         var detailsNode = WebInspector.TimelineUIUtils.buildDetailsNodeForTraceEvent(event, model.target(), linkifier);
         if (detailsNode)
             contentHelper.appendElementRow(WebInspector.UIString("Function"), detailsNode);
-        var deoptReason = eventData["deoptReason"];
-        if (deoptReason && deoptReason != "no reason")
-            contentHelper.appendWarningRow(event, WebInspector.TimelineModel.WarningType.V8Deopt);
         break;
     case recordTypes.TimerFire:
     case recordTypes.TimerInstall:
@@ -695,9 +694,6 @@
     case recordTypes.Layout:
         var beginData = event.args["beginData"];
         contentHelper.appendTextRow(WebInspector.UIString("Nodes That Need Layout"), beginData["dirtyObjects"]);
-        contentHelper.appendTextRow(WebInspector.UIString("Layout Tree Size"), beginData["totalObjects"]);
-        contentHelper.appendTextRow(WebInspector.UIString("Layout Scope"),
-                                    beginData["partialLayout"] ? WebInspector.UIString("Partial") : WebInspector.UIString("Whole document"));
         relatedNodeLabel = WebInspector.UIString("Layout root");
         break;
     case recordTypes.ConsoleTime:
@@ -751,25 +747,26 @@
         break;
     }
 
-    var relatedNode = contentHelper.nodeForBackendId(event.backendNodeId);
+    var relatedNode = relatedNodesMap && relatedNodesMap.get(event.backendNodeId);
     if (relatedNode)
         contentHelper.appendElementRow(relatedNodeLabel || WebInspector.UIString("Related Node"), WebInspector.DOMPresentationUtils.linkifyNodeReference(relatedNode));
 
-    if (eventData && eventData["scriptName"] && event.name !== recordTypes.FunctionCall)
-        contentHelper.appendLocationRow(WebInspector.UIString("Function Call"), eventData["scriptName"], eventData["scriptLine"]);
+    if (event.previewElement) {
+        contentHelper.addSection(WebInspector.UIString("Preview"));
+        contentHelper.appendElementRow("", event.previewElement);
+    }
 
     if (event.stackTrace || (event.initiator && event.initiator.stackTrace) || event.invalidationTrackingEvents)
-        WebInspector.TimelineUIUtils._generateCauses(event, model.target(), contentHelper);
+        WebInspector.TimelineUIUtils._generateCauses(event, model.target(), relatedNodesMap, contentHelper);
 
     var showPieChart = detailed && WebInspector.TimelineUIUtils._aggregatedStatsForTraceEvent(stats, model, event);
     if (showPieChart) {
+        contentHelper.addSection(WebInspector.UIString("Aggregated Time"));
         var pieChart = WebInspector.TimelineUIUtils.generatePieChart(stats, WebInspector.TimelineUIUtils.eventStyle(event).category, event.selfTime);
-        contentHelper.appendElementRow(WebInspector.UIString("Aggregated Time"), pieChart);
+        contentHelper.appendElementRow("", pieChart);
     }
 
-    fragment.appendChild(contentHelper.element);
-
-    return fragment;
+    return contentHelper.fragment;
 }
 
 WebInspector.TimelineUIUtils._aggregatedStatsKey = Symbol("aggregatedStats");
@@ -778,7 +775,7 @@
  * @param {!WebInspector.TimelineModel} model
  * @param {number} startTime
  * @param {number} endTime
- * @return {!Element}
+ * @return {!DocumentFragment}
  */
 WebInspector.TimelineUIUtils.buildRangeStats = function(model, startTime, endTime)
 {
@@ -819,15 +816,14 @@
         aggregatedTotal += aggregatedStats[categoryName];
     aggregatedStats["idle"] = Math.max(0, endTime - startTime - aggregatedTotal);
 
-    var contentHelper = new WebInspector.TimelineDetailsContentHelper(null, null, null, false);
-    var pieChart = WebInspector.TimelineUIUtils.generatePieChart(aggregatedStats);
-
     var startOffset = startTime - model.minimumRecordTime();
     var endOffset = endTime - model.minimumRecordTime();
-    contentHelper.appendTextRow(WebInspector.UIString("Range"), WebInspector.UIString("%s \u2013 %s", Number.millisToString(startOffset), Number.millisToString(endOffset)));
-    contentHelper.appendElementRow(WebInspector.UIString("Aggregated Time"), pieChart);
 
-    return contentHelper.element;
+    var contentHelper = new WebInspector.TimelineDetailsContentHelper(null, null);
+    contentHelper.addSection(WebInspector.UIString("Range:  %s \u2013 %s", Number.millisToString(startOffset), Number.millisToString(endOffset)));
+    var pieChart = WebInspector.TimelineUIUtils.generatePieChart(aggregatedStats);
+    contentHelper.appendElementRow("", pieChart);
+    return contentHelper.fragment;
 }
 
 /**
@@ -888,9 +884,8 @@
  */
 WebInspector.TimelineUIUtils.buildNetworkRequestDetails = function(request, model, linkifier)
 {
-    var fragment = createDocumentFragment();
     var target = model.target();
-    var contentHelper = new WebInspector.TimelineDetailsContentHelper(target, linkifier, null, true);
+    var contentHelper = new WebInspector.TimelineDetailsContentHelper(target, linkifier);
 
     var info = WebInspector.TimelineUIUtils.buildNetworkRequestInfo(request);
     for (var item of info) {
@@ -928,8 +923,7 @@
     {
         if (element)
             contentHelper.appendElementRow(WebInspector.UIString("Preview"), request.previewElement);
-        fragment.appendChild(contentHelper.element);
-        return fragment;
+        return contentHelper.fragment;
     }
     return previewPromise.then(appendPreview);
 }
@@ -937,9 +931,10 @@
 /**
  * @param {!WebInspector.TracingModel.Event} event
  * @param {?WebInspector.Target} target
+ * @param {?Map<number, ?WebInspector.DOMNode>} relatedNodesMap
  * @param {!WebInspector.TimelineDetailsContentHelper} contentHelper
  */
-WebInspector.TimelineUIUtils._generateCauses = function(event, target, contentHelper)
+WebInspector.TimelineUIUtils._generateCauses = function(event, target, relatedNodesMap, contentHelper)
 {
     var recordTypes = WebInspector.TimelineModel.RecordType;
 
@@ -968,12 +963,14 @@
     }
 
     // Direct cause.
-    if (event.stackTrace)
+    if (event.stackTrace && event.stackTrace.length) {
+        contentHelper.addSection(WebInspector.UIString("Call Stacks"));
         contentHelper.appendStackTrace(stackLabel || WebInspector.UIString("Stack Trace"), event.stackTrace);
+    }
 
     // Indirect causes.
     if (event.invalidationTrackingEvents && target) { // Full invalidation tracking (experimental).
-        WebInspector.TimelineUIUtils._generateInvalidations(event, target, contentHelper);
+        WebInspector.TimelineUIUtils._generateInvalidations(event, target, relatedNodesMap, contentHelper);
     } else if (initiator && initiator.stackTrace) { // Partial invalidation tracking.
         contentHelper.appendStackTrace(callSiteStackLabel || WebInspector.UIString("First Invalidated"), initiator.stackTrace);
     }
@@ -982,9 +979,10 @@
 /**
  * @param {!WebInspector.TracingModel.Event} event
  * @param {!WebInspector.Target} target
+ * @param {?Map<number, ?WebInspector.DOMNode>} relatedNodesMap
  * @param {!WebInspector.TimelineDetailsContentHelper} contentHelper
  */
-WebInspector.TimelineUIUtils._generateInvalidations = function(event, target, contentHelper)
+WebInspector.TimelineUIUtils._generateInvalidations = function(event, target, relatedNodesMap, contentHelper)
 {
     if (!event.invalidationTrackingEvents)
         return;
@@ -999,7 +997,7 @@
 
     Object.keys(invalidations).forEach(function(type) {
         WebInspector.TimelineUIUtils._generateInvalidationsForType(
-            type, target, invalidations[type], contentHelper);
+            type, target, invalidations[type], relatedNodesMap, contentHelper);
     });
 }
 
@@ -1007,9 +1005,10 @@
  * @param {string} type
  * @param {!WebInspector.Target} target
  * @param {!Array.<!WebInspector.InvalidationTrackingEvent>} invalidations
+ * @param {?Map<number, ?WebInspector.DOMNode>} relatedNodesMap
  * @param {!WebInspector.TimelineDetailsContentHelper} contentHelper
  */
-WebInspector.TimelineUIUtils._generateInvalidationsForType = function(type, target, invalidations, contentHelper)
+WebInspector.TimelineUIUtils._generateInvalidationsForType = function(type, target, invalidations, relatedNodesMap, contentHelper)
 {
     var title;
     switch (type) {
@@ -1035,7 +1034,7 @@
 
     var invalidationGroups = groupInvalidationsByCause(invalidations);
     invalidationGroups.forEach(function(group) {
-        var groupElement = new WebInspector.TimelineUIUtils.InvalidationsGroupElement(target, contentHelper, group);
+        var groupElement = new WebInspector.TimelineUIUtils.InvalidationsGroupElement(target, relatedNodesMap, contentHelper, group);
         invalidationsTreeOutline.appendChild(groupElement);
     });
     contentHelper.element.appendChild(detailsNode);
@@ -1085,11 +1084,12 @@
 /**
   * @constructor
   * @param {!WebInspector.Target} target
+  * @param {?Map<number, ?WebInspector.DOMNode>} relatedNodesMap
   * @param {!WebInspector.TimelineDetailsContentHelper} contentHelper
   * @param {!Array.<!WebInspector.InvalidationTrackingEvent>} invalidations
   * @extends {TreeElement}
   */
-WebInspector.TimelineUIUtils.InvalidationsGroupElement = function(target, contentHelper, invalidations)
+WebInspector.TimelineUIUtils.InvalidationsGroupElement = function(target, relatedNodesMap, contentHelper, invalidations)
 {
     TreeElement.call(this, "", true);
 
@@ -1097,6 +1097,7 @@
     this.selectable = false;
     this.toggleOnClick = true;
 
+    this._relatedNodesMap = relatedNodesMap;
     this._contentHelper = contentHelper;
     this._invalidations = invalidations;
     this.title = this._createTitle(target);
@@ -1217,7 +1218,7 @@
      */
     _createInvalidationNode: function(invalidation, showUnknownNodes)
     {
-        var node = this._contentHelper.nodeForBackendId(invalidation.nodeId);
+        var node = (invalidation.nodeId && this._relatedNodesMap) ? this._relatedNodesMap.get(invalidation.nodeId) : null;
         if (node)
             return WebInspector.DOMPresentationUtils.linkifyNodeReference(node);
         if (invalidation.nodeName) {
@@ -1547,19 +1548,21 @@
 WebInspector.TimelineUIUtils.generateDetailsContentForFrame = function(frameModel, frame, filmStripFrame)
 {
     var pieChart = WebInspector.TimelineUIUtils.generatePieChart(frame.timeByCategory);
-    var contentHelper = new WebInspector.TimelineDetailsContentHelper(null, null, null, false);
+    var contentHelper = new WebInspector.TimelineDetailsContentHelper(null, null);
+    contentHelper.addSection(WebInspector.UIString("Frame"));
+
     var duration = WebInspector.TimelineUIUtils.frameDuration(frame);
     contentHelper.appendElementRow(WebInspector.UIString("Duration"), duration, frame.hasWarnings());
     if (filmStripFrame) {
         var filmStripPreview = createElementWithClass("img", "timeline-filmstrip-preview");
         filmStripFrame.imageDataPromise().then(onGotImageData.bind(null, filmStripPreview));
-        contentHelper.appendElementRow(WebInspector.UIString("Screenshot"), filmStripPreview);
+        contentHelper.appendElementRow("", filmStripPreview);
         filmStripPreview.addEventListener("click", frameClicked.bind(null, filmStripFrame), false);
     }
     var durationInMillis = frame.endTime - frame.startTime;
     contentHelper.appendTextRow(WebInspector.UIString("FPS"), Math.floor(1000 / durationInMillis));
     contentHelper.appendTextRow(WebInspector.UIString("CPU time"), Number.millisToString(frame.cpuTime, true));
-    contentHelper.appendElementRow(WebInspector.UIString("Aggregated Time"), pieChart);
+
     if (Runtime.experiments.isEnabled("layersPanel") && frame.layerTree) {
         contentHelper.appendElementRow(WebInspector.UIString("Layer tree"),
                                        WebInspector.Linkifier.linkifyUsingRevealer(frame.layerTree, WebInspector.UIString("show")));
@@ -1583,7 +1586,7 @@
         new WebInspector.FilmStripView.Dialog(filmStripFrame, 0);
     }
 
-    return contentHelper.element;
+    return contentHelper.fragment;
 }
 
 /**
@@ -1922,21 +1925,45 @@
  * @constructor
  * @param {?WebInspector.Target} target
  * @param {?WebInspector.Linkifier} linkifier
- * @param {?Map<number, ?WebInspector.DOMNode>} relatedNodesMap
- * @param {boolean} monospaceValues
  */
-WebInspector.TimelineDetailsContentHelper = function(target, linkifier, relatedNodesMap, monospaceValues)
+WebInspector.TimelineDetailsContentHelper = function(target, linkifier)
 {
+    this.fragment = createDocumentFragment();
+
     this._linkifier = linkifier;
     this._target = target;
-    this._relatedNodesMap = relatedNodesMap;
-    this.element = createElement("div");
-    this.element.className = "timeline-details-view-block";
-    this._monospaceValues = monospaceValues;
+
+    this.element = createElementWithClass("div", "timeline-details-view-block");
+    this._tableElement = this.element.createChild("div", "vbox timeline-details-chip-body");
+    this.fragment.appendChild(this.element);
 }
 
 WebInspector.TimelineDetailsContentHelper.prototype = {
     /**
+     * @param {string} title
+     * @param {!WebInspector.TimelineCategory=} category
+     */
+    addSection: function(title, category)
+    {
+        if (!this._tableElement.hasChildNodes()) {
+            this.element.removeChildren();
+        } else {
+            this.element = createElementWithClass("div", "timeline-details-view-block");
+            this.fragment.appendChild(this.element);
+        }
+
+        if (title) {
+            var titleElement = this.element.createChild("div", "timeline-details-chip-title");
+            if (category)
+                titleElement.createChild("div", "timeline-" + category.name);
+            titleElement.createTextChild(title);
+        }
+
+        this._tableElement = this.element.createChild("div", "vbox timeline-details-chip-body");
+        this.fragment.appendChild(this.element);
+    },
+
+    /**
      * @return {?WebInspector.Linkifier}
      */
     linkifier: function()
@@ -1945,40 +1972,32 @@
     },
 
     /**
-     * @param {?number} backendNodeId
-     * @return {?WebInspector.DOMNode}
-     */
-    nodeForBackendId: function(backendNodeId)
-    {
-        if (!backendNodeId || !this._relatedNodesMap)
-            return null;
-        return this._relatedNodesMap.get(backendNodeId) || null;
-    },
-
-    /**
      * @param {string} title
      * @param {string|number|boolean} value
      */
     appendTextRow: function(title, value)
     {
-        var rowElement = this.element.createChild("div", "timeline-details-view-row");
+        var rowElement = this._tableElement.createChild("div", "timeline-details-view-row");
         rowElement.createChild("div", "timeline-details-view-row-title").textContent = title;
-        rowElement.createChild("div", "timeline-details-view-row-value" + (this._monospaceValues ? " monospace" : "")).textContent = value;
+        rowElement.createChild("div", "timeline-details-view-row-value").textContent = value;
     },
 
     /**
      * @param {string} title
      * @param {!Node|string} content
      * @param {boolean=} isWarning
+     * @param {boolean=} isStacked
      */
-    appendElementRow: function(title, content, isWarning)
+    appendElementRow: function(title, content, isWarning, isStacked)
     {
-        var rowElement = this.element.createChild("div", "timeline-details-view-row");
+        var rowElement = this._tableElement.createChild("div", "timeline-details-view-row");
         if (isWarning)
             rowElement.classList.add("timeline-details-warning");
+        if (isStacked)
+            rowElement.classList.add("timeline-details-stack-values");
         var titleElement = rowElement.createChild("div", "timeline-details-view-row-title");
         titleElement.textContent = title;
-        var valueElement = rowElement.createChild("div", "timeline-details-view-row-value" + (this._monospaceValues ? " monospace" : ""));
+        var valueElement = rowElement.createChild("div", "timeline-details-view-row-value");
         if (content instanceof Node)
             valueElement.appendChild(content);
         else
@@ -2025,7 +2044,7 @@
         if (!this._linkifier || !this._target)
             return;
 
-        var rowElement = this.element.createChild("div", "timeline-details-view-row");
+        var rowElement = this._tableElement.createChild("div", "timeline-details-view-row");
         rowElement.createChild("div", "timeline-details-view-row-title").textContent = title;
         this.createChildStackTraceElement(rowElement, stackTrace);
     },
@@ -2038,11 +2057,9 @@
     {
         if (!this._linkifier || !this._target)
             return;
-
-        var stackTraceElement = parentElement.createChild("div", "timeline-details-view-row-value timeline-details-view-row-stack-trace monospace");
-
+        parentElement.classList.add("timeline-details-stack-values");
+        var stackTraceElement = parentElement.createChild("div", "timeline-details-view-row-value timeline-details-view-row-stack-trace");
         var callFrameElem = WebInspector.DOMPresentationUtils.buildStackTracePreviewContents(this._target, this._linkifier, stackTrace);
-
         stackTraceElement.appendChild(callFrameElem);
     },
 
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineView.js
index d8ecb87..fa1c702 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineView.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineView.js
@@ -340,7 +340,7 @@
                 idle -= aggregatedStats[category];
             aggregatedStats["idle"] = idle;
 
-            var contentHelper = new WebInspector.TimelineDetailsContentHelper(null, null, null, true);
+            var contentHelper = new WebInspector.TimelineDetailsContentHelper(null, null);
             var pieChart = WebInspector.TimelineUIUtils.generatePieChart(aggregatedStats);
             var title = WebInspector.TimelineUIUtils.eventTitle(presentationRecord.record().traceEvent());
             contentHelper.appendTextRow(WebInspector.UIString("Type"), title);
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css b/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
index 72c8320..77af074 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
@@ -675,35 +675,50 @@
 .timeline-details-view-block {
     flex: none;
     display: flex;
+    box-shadow: #ccc 1px 1px 3px;
+    background-color: white;
     flex-direction: column;
+    margin: 3px 4px;
+    padding-bottom: 5px;
 }
 
 .timeline-details-view-row {
+    padding-left: 10px;
+    flex-direction: row;
     display: flex;
-    box-shadow: #ccc 1px 1px 3px;
-    flex-direction: column;
-    background-color: white;
-    margin: 2px 3px;
-    padding: 3px 10px;
+    line-height: 21px;
+}
+
+.timeline-details-view-block .timeline-details-stack-values {
+    flex-direction: column !important;
+}
+
+.timeline-details-chip-title {
+    font-size: 13px;
+    padding: 8px;
+    display: flex;
+    align-items: center;
+}
+
+.timeline-details-chip-title > div {
+    width: 12px;
+    height: 12px;
+    display: inline-block;
+    margin-right: 4px;
+    content: " ";
 }
 
 .timeline-details-view-row-title {
     color: rgb(152, 152, 152);
-    line-height: 21px;
-    flex: none;
-    position: relative;
     overflow: hidden;
 }
 
-.timeline-details-warning .timeline-details-view-row-title::after {
-    width: 16px;
-    height: 16px;
-    background-color: red;
-    position: absolute;
-    right: -8px;
-    top: -8px;
-    transform: rotate(45deg);
-    content: "";
+.timeline-details-warning {
+    background-color: rgba(250, 209, 209, 0.48);
+}
+
+.timeline-details-warning .timeline-details-view-row-title {
+    color: red;
 }
 
 .timeline-details-warning .timeline-details-view-row-value {
@@ -713,14 +728,11 @@
 }
 
 .timeline-details-view-row-value {
-    padding-left: 20px;
-    min-height: 20px;
-    line-height: 20px;
     -webkit-user-select: text;
     white-space: nowrap;
     text-overflow: ellipsis;
     overflow: hidden;
-    margin-right: 5px;
+    padding-left: 10px;
 }
 
 .timeline-details-view-row-value .stack-preview-container {
@@ -748,6 +760,7 @@
 }
 
 .timeline-details-view-row-stack-trace {
+    padding: 4px 0;
     line-height: inherit;
 }
 
@@ -903,6 +916,7 @@
     max-width: 200px;
     max-height: 200px;
     cursor: pointer;
+    border: 1px solid #ddd;
 }
 
 .timeline-overview-popover .frame .time {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
index a053e1f9..e32db77 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
@@ -147,8 +147,8 @@
 {
     this.element = element;
     this.element.classList.add("toolbar-item");
-    this._enabled = true;
     this._visible = true;
+    this._enabled = true;
     this.element.addEventListener("mouseenter", this._mouseEnter.bind(this), false);
     this.element.addEventListener("mouseleave", this._mouseLeave.bind(this), false);
 }
@@ -302,26 +302,15 @@
     this.element.addEventListener("click", this._clicked.bind(this), false);
     this.element.addEventListener("mousedown", this._mouseDown.bind(this), false);
     this.element.addEventListener("mouseup", this._mouseUp.bind(this), false);
-    this._longClickController = new WebInspector.LongClickController(this.element);
-    this._longClickController.addEventListener(WebInspector.LongClickController.Events.LongClick, this._onLongClick.bind(this));
+    this._enabled = true;
 }
 
 WebInspector.AbstractToolbarButton.prototype = {
     /**
-     * @param {!WebInspector.Event} event
-     */
-    _onLongClick: function(event)
-    {
-        var nativeEvent = event.data;
-        this.dispatchEventToListeners("longClickDown", nativeEvent);
-    },
-
-    /**
      * @param {!Event} event
      */
     _clicked: function(event)
     {
-        this._longClickController.reset();
         var defaultPrevented = this.dispatchEventToListeners("click", event);
         event.consume(defaultPrevented);
     },
@@ -343,20 +332,11 @@
     },
 
     /**
-     * @override
-     */
-    _applyEnabledState: function()
-    {
-        this.element.disabled = !this._enabled;
-        this._longClickController.reset();
-    },
-
-    /**
      * @return {boolean}
      */
     enabled: function()
     {
-        throw "Not implemented";
+        return this._enabled;
     },
 
     /**
@@ -407,19 +387,6 @@
         throw "Not implemented";
     },
 
-    makeLongClickEnabled: function()
-    {
-        this._longClickController.enable();
-        this._longClickGlyph = this.element.createChild("div", "long-click-glyph toolbar-button-theme");
-    },
-
-    unmakeLongClickEnabled: function()
-    {
-        this._longClickController.disable();
-        if (this._longClickGlyph)
-            this.element.removeChild(this._longClickGlyph);
-    },
-
     __proto__: WebInspector.ToolbarItem.prototype
 }
 
@@ -446,15 +413,6 @@
 WebInspector.ToolbarButtonBase.prototype = {
     /**
      * @override
-     * @return {boolean}
-     */
-    enabled: function()
-    {
-        return this._enabled;
-    },
-
-    /**
-     * @override
      * @return {string}
      */
     title: function()
@@ -554,6 +512,8 @@
      */
     setEnabled: function(value)
     {
+        if (this._longClickController)
+            this._longClickController.reset();
         this._action.setEnabled(value);
     },
 
@@ -563,7 +523,7 @@
     _enabledStateChanged: function(event)
     {
         var enabled = /** @type {boolean} */ (event.data);
-        WebInspector.ToolbarButtonBase.prototype.setEnabled.call(this, enabled);
+        WebInspector.AbstractToolbarButton.prototype.setEnabled.call(this, enabled);
     },
 
     /**
@@ -572,7 +532,8 @@
      */
     _clicked: function(event)
     {
-        this._longClickController.reset();
+        if (this._longClickController)
+            this._longClickController.reset();
         this._action.execute();
     },
 
@@ -651,31 +612,24 @@
     setLongClickOptionsEnabled: function(buttonsProvider)
     {
         if (buttonsProvider) {
-            if (!this._longClickOptionsData) {
-                this.makeLongClickEnabled();
-
-                var longClickDownListener = this._showOptions.bind(this);
-                this.addEventListener("longClickDown", longClickDownListener, this);
-
-                this._longClickOptionsData = {
-                    longClickDownListener: longClickDownListener
-                };
+            if (!this._longClickController) {
+                this._longClickController = new WebInspector.LongClickController(this.element, this._showOptions.bind(this));
+                this._longClickGlyph = this.element.createChild("div", "long-click-glyph toolbar-button-theme");
+                this._longClickButtonsProvider = buttonsProvider;
             }
-            this._longClickOptionsData.buttonsProvider = buttonsProvider;
         } else {
-            if (!this._longClickOptionsData)
-                return;
-
-            this.removeEventListener("longClickDown", this._longClickOptionsData.longClickDownListener, this);
-            delete this._longClickOptionsData;
-
-            this.unmakeLongClickEnabled();
+            if (this._longClickController) {
+                this._longClickController.dispose();
+                delete this._longClickController;
+                this.element.removeChild(this._longClickGlyph);
+                delete this._longClickButtonsProvider;
+            }
         }
     },
 
     _showOptions: function()
     {
-        var buttons = this._longClickOptionsData.buttonsProvider();
+        var buttons = this._longClickButtonsProvider();
         var mainButtonClone = new WebInspector.ToolbarButton(this.title(), this._action.icon(), this._action.statesCount());
         mainButtonClone.addEventListener("click", clicked.bind(this));
 
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 cd75685..bb9a633e 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
@@ -1104,19 +1104,15 @@
  * @constructor
  * @extends {WebInspector.Object}
  * @param {!Element} element
+ * @param {function(!Event)} callback
  */
-WebInspector.LongClickController = function(element)
+WebInspector.LongClickController = function(element, callback)
 {
     this._element = element;
+    this._callback = callback;
+    this._enable();
 }
 
-/**
- * @enum {string}
- */
-WebInspector.LongClickController.Events = {
-    LongClick: "LongClick"
-};
-
 WebInspector.LongClickController.prototype = {
     reset: function()
     {
@@ -1126,7 +1122,7 @@
         }
     },
 
-    enable: function()
+    _enable: function()
     {
         if (this._longClickData)
             return;
@@ -1149,7 +1145,8 @@
         {
             if (e.which !== 1)
                 return;
-            this._longClickInterval = setTimeout(longClicked.bind(this, e), 200);
+            var callback = this._callback;
+            this._longClickInterval = setTimeout(callback.bind(null, e), 200);
         }
 
         /**
@@ -1162,18 +1159,9 @@
                 return;
             this.reset();
         }
-
-        /**
-         * @param {!Event} e
-         * @this {WebInspector.LongClickController}
-         */
-        function longClicked(e)
-        {
-            this.dispatchEventToListeners(WebInspector.LongClickController.Events.LongClick, e);
-        }
     },
 
-    disable: function()
+    dispose: function()
     {
         if (!this._longClickData)
             return;
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 fd7176c9..ef387fea 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
@@ -38,6 +38,27 @@
     z-index: 200;
 }
 
+:host-context(.platform-mac) .flame-chart-v-scroll {
+    right: 2px;
+    top: 3px;
+    bottom: 3px;
+    width: 15px;
+}
+
+/* force non-overlay scrollbars */
+:host-context(.platform-mac) ::-webkit-scrollbar {
+    width: 8px;
+}
+
+:host-context(.platform-mac) ::-webkit-scrollbar-thumb {
+    background-color: hsla(0, 0%, 56%, 0.6);
+    border-radius: 50px;
+}
+
+:host-context(.platform-mac) .flame-chart-v-scroll:hover::-webkit-scrollbar-thumb {
+    background-color: hsla(0, 0%, 25%, 0.6);
+}
+
 .flame-chart-selection-overlay {
     position: absolute;
     z-index: 100;
diff --git a/third_party/WebKit/Source/modules/accessibility/AXInlineTextBox.cpp b/third_party/WebKit/Source/modules/accessibility/AXInlineTextBox.cpp
index 5f1efc79..56f009b 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXInlineTextBox.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXInlineTextBox.cpp
@@ -128,8 +128,8 @@
     if (!m_inlineTextBox || !m_axObjectCache)
         return 0;
 
-    LayoutText* layoutText = m_inlineTextBox->layoutText();
-    return m_axObjectCache->getOrCreate(layoutText);
+    LineLayoutText lineLayoutText = m_inlineTextBox->lineLayoutItem();
+    return m_axObjectCache->getOrCreate(lineLayoutText);
 }
 
 // In addition to LTR and RTL direction, edit fields also support
diff --git a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
index a4fc1cf5..26df49e 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
@@ -275,14 +275,8 @@
     return false;
 }
 
-AccessibilityRole AXLayoutObject::determineAccessibilityRole()
+AccessibilityRole AXLayoutObject::nativeAccessibilityRoleIgnoringAria() const
 {
-    if (!m_layoutObject)
-        return UnknownRole;
-
-    if ((m_ariaRole = determineAriaRoleAttribute()) != UnknownRole)
-        return m_ariaRole;
-
     Node* node = m_layoutObject->node();
     LayoutBoxModelObject* cssBox = layoutBoxModelObject();
 
@@ -322,7 +316,18 @@
     if (m_layoutObject->isHR())
         return SplitterRole;
 
-    AccessibilityRole role = AXNodeObject::determineAccessibilityRoleUtil();
+    return AXNodeObject::nativeAccessibilityRoleIgnoringAria();
+}
+
+AccessibilityRole AXLayoutObject::determineAccessibilityRole()
+{
+    if (!m_layoutObject)
+        return UnknownRole;
+
+    if ((m_ariaRole = determineAriaRoleAttribute()) != UnknownRole)
+        return m_ariaRole;
+
+    AccessibilityRole role = nativeAccessibilityRoleIgnoringAria();
     if (role != UnknownRole)
         return role;
 
diff --git a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.h b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.h
index ef781e8..6abaa4b 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.h
+++ b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.h
@@ -63,6 +63,7 @@
     bool shouldNotifyActiveDescendant() const;
     ScrollableArea* getScrollableAreaIfScrollable() const final;
     AccessibilityRole determineAccessibilityRole() override;
+    AccessibilityRole nativeAccessibilityRoleIgnoringAria() const override;
     void checkCachedElementRect() const;
     void updateCachedElementRect() const;
 
diff --git a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
index d0fc039c..96bdd25 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
@@ -315,10 +315,11 @@
     return false;
 }
 
-AccessibilityRole AXNodeObject::determineAccessibilityRoleUtil()
+AccessibilityRole AXNodeObject::nativeAccessibilityRoleIgnoringAria() const
 {
     if (!node())
         return UnknownRole;
+
     // HTMLAnchorElement sets isLink only when it has hrefAttr.
     // We assume that it is also LinkRole if it has event listners even though it doesn't have hrefAttr.
     if (node()->isLink() || (isHTMLAnchorElement(*node()) && isClickable()))
@@ -509,7 +510,7 @@
     if (node()->isTextNode())
         return StaticTextRole;
 
-    AccessibilityRole role = determineAccessibilityRoleUtil();
+    AccessibilityRole role = nativeAccessibilityRoleIgnoringAria();
     if (role != UnknownRole)
         return role;
     if (node()->isElementNode()) {
@@ -1825,8 +1826,15 @@
     if (node() && isHTMLMapElement(node()))
         return false;
 
-    // Elements that should not have children
-    switch (roleValue()) {
+    AccessibilityRole role = roleValue();
+
+    // If an element has an ARIA role of presentation, we need to consider the native
+    // role when deciding whether it can have children or not - otherwise giving something
+    // a role of presentation could expose inner implementation details.
+    if (isPresentational())
+        role = nativeAccessibilityRoleIgnoringAria();
+
+    switch (role) {
     case ImageRole:
     case ButtonRole:
     case PopUpButtonRole:
diff --git a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.h b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.h
index e06aaa8..77a593a 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.h
+++ b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.h
@@ -61,7 +61,7 @@
     bool computeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override;
     const AXObject* inheritsPresentationalRoleFrom() const override;
     virtual AccessibilityRole determineAccessibilityRole();
-    AccessibilityRole determineAccessibilityRoleUtil();
+    virtual AccessibilityRole nativeAccessibilityRoleIgnoringAria() const;
     String accessibilityDescriptionForElements(WillBeHeapVector<RawPtrWillBeMember<Element>> &elements) const;
     void alterSliderValue(bool increase);
     String ariaAccessibilityDescription() const;
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
index feb0186..7c972cfd 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
@@ -711,6 +711,7 @@
         for (size_t i = 0; i < relatedObjects.size(); i++)
             nameObjects->append(relatedObjects[i]->object);
     }
+
     return text;
 }
 
diff --git a/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandle.cpp b/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandle.cpp
index 718dfd9..5d72de36 100644
--- a/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandle.cpp
+++ b/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandle.cpp
@@ -217,7 +217,7 @@
         {
             if (!m_readerContext->m_blobDataHandleForDrain)
                 return nullptr;
-            if (blobSizePolicy == DisallowBlobWithInvalidSize && m_readerContext->m_blobDataHandleForDrain->size() == kuint64max)
+            if (blobSizePolicy == DisallowBlobWithInvalidSize && m_readerContext->m_blobDataHandleForDrain->size() == UINT64_MAX)
                 return nullptr;
             RefPtr<BlobDataHandle> blobDataHandle = m_readerContext->m_blobDataHandleForDrain;
             m_readerContext->setDrained();
diff --git a/third_party/WebKit/Source/modules/fetch/FetchDataLoader.cpp b/third_party/WebKit/Source/modules/fetch/FetchDataLoader.cpp
index 107453c..690da89 100644
--- a/third_party/WebKit/Source/modules/fetch/FetchDataLoader.cpp
+++ b/third_party/WebKit/Source/modules/fetch/FetchDataLoader.cpp
@@ -39,7 +39,7 @@
         m_reader = handle->obtainReader(this);
         RefPtr<BlobDataHandle> blobHandle = m_reader->drainAsBlobDataHandle();
         if (blobHandle) {
-            ASSERT(blobHandle->size() != kuint64max);
+            ASSERT(blobHandle->size() != UINT64_MAX);
             m_reader.clear();
             if (blobHandle->type() != m_mimeType) {
                 // A new BlobDataHandle is created to override the Blob's type.
diff --git a/third_party/WebKit/Source/modules/modules.gypi b/third_party/WebKit/Source/modules/modules.gypi
index 9ff24ec..b0d94c1 100644
--- a/third_party/WebKit/Source/modules/modules.gypi
+++ b/third_party/WebKit/Source/modules/modules.gypi
@@ -374,6 +374,7 @@
       'quota/NavigatorStorageQuota.idl',
       'quota/WindowQuota.idl',
       'quota/WorkerNavigatorStorageQuota.idl',
+      'remoteplayback/HTMLMediaElementRemotePlayback.idl',
       'screen_orientation/ScreenScreenOrientation.idl',
       'serviceworkers/NavigatorServiceWorker.idl',
       'speech/WindowSpeech.idl',
@@ -1366,6 +1367,8 @@
       'quota/StorageUsageCallback.h',
       'quota/WorkerNavigatorStorageQuota.cpp',
       'quota/WorkerNavigatorStorageQuota.h',
+      'remoteplayback/HTMLMediaElementRemotePlayback.cpp',
+      'remoteplayback/HTMLMediaElementRemotePlayback.h',
       'screen_orientation/LockOrientationCallback.cpp',
       'screen_orientation/LockOrientationCallback.h',
       'screen_orientation/ScreenScreenOrientation.cpp',
diff --git a/third_party/WebKit/Source/modules/plugins/PluginOcclusionSupport.cpp b/third_party/WebKit/Source/modules/plugins/PluginOcclusionSupport.cpp
index d5545599..c623b0f 100644
--- a/third_party/WebKit/Source/modules/plugins/PluginOcclusionSupport.cpp
+++ b/third_party/WebKit/Source/modules/plugins/PluginOcclusionSupport.cpp
@@ -81,7 +81,7 @@
 
             // If the plugin does not have an explicit z-index it stacks behind the iframe.
             // This is for maintaining compatibility with IE.
-            if (ro2->style()->position() == StaticPosition) {
+            if (!ro2->isPositioned()) {
                 // The 0'th elements of these LayoutObject arrays represent the plugin node and
                 // the iframe.
                 const LayoutObject* pluginLayoutObject = pluginZstack[0];
diff --git a/third_party/WebKit/Source/modules/remoteplayback/DEPS b/third_party/WebKit/Source/modules/remoteplayback/DEPS
new file mode 100644
index 0000000..ab91c491
--- /dev/null
+++ b/third_party/WebKit/Source/modules/remoteplayback/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+    "-third_party/WebKit/Sources/modules",
+    "+third_party/WebKit/Sources/modules/remoteplayback",
+    "+third_party/WebKit/Sources/platform",
+]
diff --git a/third_party/WebKit/Source/modules/remoteplayback/HTMLMediaElementRemotePlayback.cpp b/third_party/WebKit/Source/modules/remoteplayback/HTMLMediaElementRemotePlayback.cpp
new file mode 100644
index 0000000..ce14296
--- /dev/null
+++ b/third_party/WebKit/Source/modules/remoteplayback/HTMLMediaElementRemotePlayback.cpp
@@ -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 "config.h"
+#include "modules/remoteplayback/HTMLMediaElementRemotePlayback.h"
+
+#include "core/dom/QualifiedName.h"
+#include "core/html/HTMLMediaElement.h"
+
+namespace blink {
+
+// static
+bool HTMLMediaElementRemotePlayback::fastHasAttribute(const QualifiedName& name, const HTMLMediaElement& element)
+{
+    ASSERT(name == HTMLNames::disableremoteplaybackAttr);
+    return element.fastHasAttribute(name);
+}
+
+// static
+void HTMLMediaElementRemotePlayback::setBooleanAttribute(const QualifiedName& name, HTMLMediaElement& element, bool value)
+{
+    ASSERT(name == HTMLNames::disableremoteplaybackAttr);
+    element.setBooleanAttribute(name, value);
+}
+
+}
diff --git a/third_party/WebKit/Source/modules/remoteplayback/HTMLMediaElementRemotePlayback.h b/third_party/WebKit/Source/modules/remoteplayback/HTMLMediaElementRemotePlayback.h
new file mode 100644
index 0000000..d46c654a
--- /dev/null
+++ b/third_party/WebKit/Source/modules/remoteplayback/HTMLMediaElementRemotePlayback.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 HTMLMediaElementRemotePlayback_h
+#define HTMLMediaElementRemotePlayback_h
+
+namespace blink {
+
+class HTMLMediaElement;
+class QualifiedName;
+
+// Class used to implement the Remote Playback API. It will be a supplement to
+// HTMLMediaElement later.
+class HTMLMediaElementRemotePlayback final {
+public:
+    static bool fastHasAttribute(const QualifiedName&, const HTMLMediaElement&);
+    static void setBooleanAttribute(const QualifiedName&, HTMLMediaElement&, bool);
+};
+
+} // namespace blink
+
+#endif // HTMLMediaElementRemotePlayback_h
diff --git a/third_party/WebKit/Source/modules/remoteplayback/HTMLMediaElementRemotePlayback.idl b/third_party/WebKit/Source/modules/remoteplayback/HTMLMediaElementRemotePlayback.idl
new file mode 100644
index 0000000..87e23c7
--- /dev/null
+++ b/third_party/WebKit/Source/modules/remoteplayback/HTMLMediaElementRemotePlayback.idl
@@ -0,0 +1,9 @@
+// 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.
+
+// https://w3c.github.io/remote-playback/#extension-to-the-htmlmediaelement
+
+partial interface HTMLMediaElement {
+    [Reflect] attribute boolean disableRemotePlayback;
+};
diff --git a/third_party/WebKit/Source/modules/remoteplayback/OWNERS b/third_party/WebKit/Source/modules/remoteplayback/OWNERS
new file mode 100644
index 0000000..dc2593f
--- /dev/null
+++ b/third_party/WebKit/Source/modules/remoteplayback/OWNERS
@@ -0,0 +1,2 @@
+avayvod@chromium.org
+mlamouri@chromium.org
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerClients.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerClients.cpp
index 8070617f..4533f1f 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerClients.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerClients.cpp
@@ -118,7 +118,7 @@
     }
 
     if (!context->securityOrigin()->canDisplay(parsedUrl)) {
-        resolver->reject(DOMException::create(SecurityError, "'" + parsedUrl.elidedString() + "' cannot be opened."));
+        resolver->reject(V8ThrowException::createTypeError(scriptState->isolate(), "'" + parsedUrl.elidedString() + "' cannot be opened."));
         return promise;
     }
 
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioNode.idl b/third_party/WebKit/Source/modules/webaudio/AudioNode.idl
index a9b07f9..9f6ef3b 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioNode.idl
+++ b/third_party/WebKit/Source/modules/webaudio/AudioNode.idl
@@ -39,15 +39,15 @@
     Conditional=WEB_AUDIO,
     GarbageCollected,
 ] interface AudioNode : EventTarget {
-    [RaisesException] AudioNode connect(AudioNode destination, optional unsigned long output = 0, optional unsigned long input = 0);
-    [RaisesException] void connect(AudioParam destination, optional unsigned long output = 0);
+    [RaisesException, MeasureAs=AudioNodeConnectToAudioNode] AudioNode connect(AudioNode destination, optional unsigned long output = 0, optional unsigned long input = 0);
+    [RaisesException, MeasureAs=AudioNodeConnectToAudioParam] void connect(AudioParam destination, optional unsigned long output = 0);
     void disconnect();
-    [RaisesException] void disconnect(unsigned long output);
-    [RaisesException] void disconnect(AudioNode destination);
-    [RaisesException] void disconnect(AudioNode destination, unsigned long output);
-    [RaisesException] void disconnect(AudioNode destination, unsigned long output, unsigned long input);
-    [RaisesException] void disconnect(AudioParam destination);
-    [RaisesException] void disconnect(AudioParam destination, unsigned long output);
+    [RaisesException, MeasureAs=AudioNodeDisconnectFromAudioNode] void disconnect(unsigned long output);
+    [RaisesException, MeasureAs=AudioNodeDisconnectFromAudioNode] void disconnect(AudioNode destination);
+    [RaisesException, MeasureAs=AudioNodeDisconnectFromAudioNode] void disconnect(AudioNode destination, unsigned long output);
+    [RaisesException, MeasureAs=AudioNodeDisconnectFromAudioNode] void disconnect(AudioNode destination, unsigned long output, unsigned long input);
+    [RaisesException, MeasureAs=AudioNodeDisconnectFromAudioParam] void disconnect(AudioParam destination);
+    [RaisesException, MeasureAs=AudioNodeDisconnectFromAudioParam] void disconnect(AudioParam destination, unsigned long output);
     readonly attribute AudioContext  context;
     readonly attribute unsigned long numberOfInputs;
     readonly attribute unsigned long numberOfOutputs;
diff --git a/third_party/WebKit/Source/modules/webaudio/BiquadDSPKernel.cpp b/third_party/WebKit/Source/modules/webaudio/BiquadDSPKernel.cpp
index 112fc98..f62315e 100644
--- a/third_party/WebKit/Source/modules/webaudio/BiquadDSPKernel.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/BiquadDSPKernel.cpp
@@ -27,6 +27,7 @@
 #include "modules/webaudio/BiquadDSPKernel.h"
 
 #include "platform/FloatConversion.h"
+#include "platform/audio/AudioUtilities.h"
 #include "wtf/Vector.h"
 #include <limits.h>
 
@@ -38,73 +39,82 @@
 // settings of the Biquad.
 static const double MaxBiquadDelayTime = 0.2;
 
-void BiquadDSPKernel::updateCoefficientsIfNecessary()
+void BiquadDSPKernel::updateCoefficientsIfNecessary(int framesToProcess)
 {
     if (biquadProcessor()->filterCoefficientsDirty()) {
-        double cutoffFrequency;
-        double Q;
-        double gain;
-        double detune; // in Cents
+        float cutoffFrequency[AudioUtilities::kRenderQuantumFrames];
+        float Q[AudioUtilities::kRenderQuantumFrames];
+        float gain[AudioUtilities::kRenderQuantumFrames];
+        float detune[AudioUtilities::kRenderQuantumFrames]; // in Cents
+
+        RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(
+            static_cast<unsigned>(framesToProcess) <= AudioUtilities::kRenderQuantumFrames);
 
         if (biquadProcessor()->hasSampleAccurateValues()) {
-            cutoffFrequency = biquadProcessor()->parameter1().finalValue();
-            Q = biquadProcessor()->parameter2().finalValue();
-            gain = biquadProcessor()->parameter3().finalValue();
-            detune = biquadProcessor()->parameter4().finalValue();
+            biquadProcessor()->parameter1().calculateSampleAccurateValues(cutoffFrequency, framesToProcess);
+            biquadProcessor()->parameter2().calculateSampleAccurateValues(Q, framesToProcess);
+            biquadProcessor()->parameter3().calculateSampleAccurateValues(gain, framesToProcess);
+            biquadProcessor()->parameter4().calculateSampleAccurateValues(detune, framesToProcess);
+            updateCoefficients(framesToProcess, cutoffFrequency, Q, gain, detune);
         } else {
-            cutoffFrequency = biquadProcessor()->parameter1().smoothedValue();
-            Q = biquadProcessor()->parameter2().smoothedValue();
-            gain = biquadProcessor()->parameter3().smoothedValue();
-            detune = biquadProcessor()->parameter4().smoothedValue();
+            cutoffFrequency[0] = biquadProcessor()->parameter1().smoothedValue();
+            Q[0] = biquadProcessor()->parameter2().smoothedValue();
+            gain[0] = biquadProcessor()->parameter3().smoothedValue();
+            detune[0] = biquadProcessor()->parameter4().smoothedValue();
+            updateCoefficients(1, cutoffFrequency, Q, gain, detune);
         }
-
-        updateCoefficients(cutoffFrequency, Q, gain, detune);
     }
 }
 
-void BiquadDSPKernel::updateCoefficients(double cutoffFrequency, double Q, double gain, double detune)
+void BiquadDSPKernel::updateCoefficients(int numberOfFrames, const float* cutoffFrequency, const float* Q, const float* gain, const float* detune)
 {
     // Convert from Hertz to normalized frequency 0 -> 1.
     double nyquist = this->nyquist();
-    double normalizedFrequency = cutoffFrequency / nyquist;
 
-    // Offset frequency by detune.
-    if (detune)
-        normalizedFrequency *= pow(2, detune / 1200);
 
-    // Configure the biquad with the new filter parameters for the appropriate type of filter.
-    switch (biquadProcessor()->type()) {
-    case BiquadProcessor::LowPass:
-        m_biquad.setLowpassParams(normalizedFrequency, Q);
-        break;
+    m_biquad.setHasSampleAccurateValues(numberOfFrames > 1);
 
-    case BiquadProcessor::HighPass:
-        m_biquad.setHighpassParams(normalizedFrequency, Q);
-        break;
+    for (int k = 0; k < numberOfFrames; ++k) {
+        double normalizedFrequency = cutoffFrequency[k] / nyquist;
 
-    case BiquadProcessor::BandPass:
-        m_biquad.setBandpassParams(normalizedFrequency, Q);
-        break;
+        // Offset frequency by detune.
+        if (detune[k])
+            normalizedFrequency *= pow(2, detune[k] / 1200);
 
-    case BiquadProcessor::LowShelf:
-        m_biquad.setLowShelfParams(normalizedFrequency, gain);
-        break;
+        // Configure the biquad with the new filter parameters for the appropriate type of filter.
+        switch (biquadProcessor()->type()) {
+        case BiquadProcessor::LowPass:
+            m_biquad.setLowpassParams(k, normalizedFrequency, Q[k]);
+            break;
 
-    case BiquadProcessor::HighShelf:
-        m_biquad.setHighShelfParams(normalizedFrequency, gain);
-        break;
+        case BiquadProcessor::HighPass:
+            m_biquad.setHighpassParams(k, normalizedFrequency, Q[k]);
+            break;
 
-    case BiquadProcessor::Peaking:
-        m_biquad.setPeakingParams(normalizedFrequency, Q, gain);
-        break;
+        case BiquadProcessor::BandPass:
+            m_biquad.setBandpassParams(k, normalizedFrequency, Q[k]);
+            break;
 
-    case BiquadProcessor::Notch:
-        m_biquad.setNotchParams(normalizedFrequency, Q);
-        break;
+        case BiquadProcessor::LowShelf:
+            m_biquad.setLowShelfParams(k, normalizedFrequency, gain[k]);
+            break;
 
-    case BiquadProcessor::Allpass:
-        m_biquad.setAllpassParams(normalizedFrequency, Q);
-        break;
+        case BiquadProcessor::HighShelf:
+            m_biquad.setHighShelfParams(k, normalizedFrequency, gain[k]);
+            break;
+
+        case BiquadProcessor::Peaking:
+            m_biquad.setPeakingParams(k, normalizedFrequency, Q[k], gain[k]);
+            break;
+
+        case BiquadProcessor::Notch:
+            m_biquad.setNotchParams(k, normalizedFrequency, Q[k]);
+            break;
+
+        case BiquadProcessor::Allpass:
+            m_biquad.setAllpassParams(k, normalizedFrequency, Q[k]);
+            break;
+        }
     }
 }
 
@@ -124,7 +134,7 @@
     {
         MutexTryLocker tryLocker(m_processLock);
         if (tryLocker.locked())
-            updateCoefficientsIfNecessary();
+            updateCoefficientsIfNecessary(framesToProcess);
     }
 
     m_biquad.process(source, destination, framesToProcess);
@@ -146,10 +156,10 @@
     for (int k = 0; k < nFrequencies; ++k)
         frequency[k] = narrowPrecisionToFloat(frequencyHz[k] / nyquist);
 
-    double cutoffFrequency;
-    double Q;
-    double gain;
-    double detune; // in Cents
+    float cutoffFrequency;
+    float Q;
+    float gain;
+    float detune; // in Cents
 
     {
         // Get a copy of the current biquad filter coefficients so we can update the biquad with
@@ -172,7 +182,7 @@
         detune = biquadProcessor()->parameter4().value();
     }
 
-    updateCoefficients(cutoffFrequency, Q, gain, detune);
+    updateCoefficients(1, &cutoffFrequency, &Q, &gain, &detune);
 
     m_biquad.getFrequencyResponse(nFrequencies, frequency.data(), magResponse, phaseResponse);
 }
diff --git a/third_party/WebKit/Source/modules/webaudio/BiquadDSPKernel.h b/third_party/WebKit/Source/modules/webaudio/BiquadDSPKernel.h
index fff8fa9..971ef5e 100644
--- a/third_party/WebKit/Source/modules/webaudio/BiquadDSPKernel.h
+++ b/third_party/WebKit/Source/modules/webaudio/BiquadDSPKernel.h
@@ -59,9 +59,9 @@
 
     // To prevent audio glitches when parameters are changed,
     // dezippering is used to slowly change the parameters.
-    void updateCoefficientsIfNecessary();
+    void updateCoefficientsIfNecessary(int);
     // Update the biquad cofficients with the given parameters
-    void updateCoefficients(double frequency, double Q, double gain, double detune);
+    void updateCoefficients(int, const float* frequency, const float* Q, const float* gain, const float* detune);
 
 private:
     // Synchronize process() with getting and setting the filter coefficients.
diff --git a/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteFileSystemPosix.cpp b/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteFileSystemPosix.cpp
index a1921a0..b0d3e76 100644
--- a/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteFileSystemPosix.cpp
+++ b/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteFileSystemPosix.cpp
@@ -142,27 +142,16 @@
 // usedFlags - the actual open mode flags that were used.
 int chromiumOpenInternal(sqlite3_vfs* vfs, const char* fileName, sqlite3_file* id, int desiredFlags, int* usedFlags)
 {
-    chromium_sqlite3_initialize_unix_sqlite3_file(id);
-    int fd = -1;
-    int result = chromium_sqlite3_get_reusable_file_handle(id, fileName, desiredFlags, &fd);
-    if (result != SQLITE_OK)
-        return result;
-
-    if (fd < 0) {
+    int fd = Platform::current()->databaseOpenFile(String(fileName), desiredFlags);
+    if ((fd < 0) && (desiredFlags & SQLITE_OPEN_READWRITE)) {
+        desiredFlags = (desiredFlags & ~(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)) | SQLITE_OPEN_READONLY;
         fd = Platform::current()->databaseOpenFile(String(fileName), desiredFlags);
-        if ((fd < 0) && (desiredFlags & SQLITE_OPEN_READWRITE)) {
-            int newFlags = (desiredFlags & ~(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)) | SQLITE_OPEN_READONLY;
-            fd = Platform::current()->databaseOpenFile(String(fileName), newFlags);
-        }
     }
-    if (fd < 0) {
-        chromium_sqlite3_destroy_reusable_file_handle(id);
+    if (fd < 0)
         return SQLITE_CANTOPEN;
-    }
 
     if (usedFlags)
         *usedFlags = desiredFlags;
-    chromium_sqlite3_update_reusable_file_handle(id, fd, desiredFlags);
 
     fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
 
@@ -170,10 +159,7 @@
     int fileType = desiredFlags & 0x00007F00;
     int noLock = (fileType != SQLITE_OPEN_MAIN_DB);
     sqlite3_vfs* wrappedVfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
-    result = chromium_sqlite3_fill_in_unix_sqlite3_file(wrappedVfs, fd, -1, id, fileName, noLock);
-    if (result != SQLITE_OK)
-        chromium_sqlite3_destroy_reusable_file_handle(id);
-    return result;
+    return chromium_sqlite3_fill_in_unix_sqlite3_file(wrappedVfs, fd, id, fileName, noLock, desiredFlags);
 }
 
 int chromiumOpen(sqlite3_vfs* vfs, const char* fileName, sqlite3_file* id, int desiredFlags, int* usedFlags)
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
index 129af53..a989062 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
@@ -158,10 +158,10 @@
     m_samplerUnits.clear();
     m_samplerUnits.resize(numCombinedTextureImageUnits);
 
-    GLint maxTransformFeedbackSeparateAttribs = 0;
-    webContext()->getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &maxTransformFeedbackSeparateAttribs);
+    m_maxTransformFeedbackSeparateAttribs = 0;
+    webContext()->getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &m_maxTransformFeedbackSeparateAttribs);
     m_boundIndexedTransformFeedbackBuffers.clear();
-    m_boundIndexedTransformFeedbackBuffers.resize(maxTransformFeedbackSeparateAttribs);
+    m_boundIndexedTransformFeedbackBuffers.resize(m_maxTransformFeedbackSeparateAttribs);
 
     GLint maxUniformBufferBindings = 0;
     webContext()->getIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxUniformBufferBindings);
@@ -2177,6 +2177,20 @@
     if (isContextLost() || !validateWebGLObject("transformFeedbackVaryings", program))
         return;
 
+    switch (bufferMode) {
+    case GL_SEPARATE_ATTRIBS:
+        if (varyings.size() > static_cast<size_t>(m_maxTransformFeedbackSeparateAttribs)) {
+            synthesizeGLError(GL_INVALID_VALUE, "transformFeedbackVaryings", "too many varyings");
+            return;
+        }
+        break;
+    case GL_INTERLEAVED_ATTRIBS:
+        break;
+    default:
+        synthesizeGLError(GL_INVALID_ENUM, "transformFeedbackVaryings", "invalid buffer mode");
+        return;
+    }
+
     Vector<CString> keepAlive; // Must keep these instances alive while looking at their data
     Vector<const char*> varyingStrings;
     for (size_t i = 0; i < varyings.size(); ++i) {
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
index ba0b485..a0654761 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
@@ -258,6 +258,7 @@
 
     PersistentHeapVectorWillBeHeapVector<Member<WebGLBuffer>> m_boundIndexedTransformFeedbackBuffers;
     PersistentHeapVectorWillBeHeapVector<Member<WebGLBuffer>> m_boundIndexedUniformBuffers;
+    GLint m_maxTransformFeedbackSeparateAttribs;
     size_t m_maxBoundUniformBufferIndex;
 
     PersistentWillBeMember<WebGLQuery> m_currentBooleanOcclusionQuery;
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index 1242951..fa91981 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -335,11 +335,19 @@
   }
 }
 
+# TODO(GYP): Delete this after we've converted everything to GN.
+# The _run targets exist only for compatibility w/ GYP.
+group("blink_heap_unittests_run") {
+  testonly = true
+  deps = [
+    ":blink_heap_unittests",
+  ]
+}
+
 # GYP: blink_heap_unittests
-test("heap_unittests") {
+test("blink_heap_unittests") {
   visibility = []  # Allow re-assignment of list.
   visibility = [ "*" ]
-  output_name = "blink_heap_unittests"
 
   sources = rebase_path(heap_gypi.platform_heap_test_files, ".", "heap")
   sources += [ "heap/RunAllTests.cpp" ]
@@ -371,10 +379,18 @@
   }
 }
 
-test("platform_unittests") {
+# TODO(GYP): Delete this after we've converted everything to GN.
+# The _run targets exist only for compatibility w/ GYP.
+group("blink_platform_unittests_run") {
+  testonly = true
+  deps = [
+    ":blink_platform_unittests",
+  ]
+}
+
+test("blink_platform_unittests") {
   visibility = []  # Allow re-assignment of list.
   visibility = [ "*" ]
-  output_name = "blink_platform_unittests"
 
   sources = platform_test_files
 
diff --git a/third_party/WebKit/Source/platform/DragImage.h b/third_party/WebKit/Source/platform/DragImage.h
index 12deee2b..440a7223 100644
--- a/third_party/WebKit/Source/platform/DragImage.h
+++ b/third_party/WebKit/Source/platform/DragImage.h
@@ -68,8 +68,6 @@
 private:
     DragImage(const SkBitmap&, float resolutionScale, InterpolationQuality);
 
-    DisplayItemClient displayItemClient() const { return toDisplayItemClient(this); }
-
     SkBitmap m_bitmap;
     float m_resolutionScale;
     InterpolationQuality m_interpolationQuality;
diff --git a/third_party/WebKit/Source/platform/PlatformMouseEvent.h b/third_party/WebKit/Source/platform/PlatformMouseEvent.h
index c1b2278..7051f90 100644
--- a/third_party/WebKit/Source/platform/PlatformMouseEvent.h
+++ b/third_party/WebKit/Source/platform/PlatformMouseEvent.h
@@ -66,7 +66,7 @@
     {
     }
 
-    PlatformMouseEvent(const IntPoint& position, const IntPoint& globalPosition, MouseButton button, PlatformEvent::Type type, int clickCount, Modifiers modifiers, SyntheticEventType synthesized, double timestamp)
+    PlatformMouseEvent(const IntPoint& position, const IntPoint& globalPosition, MouseButton button, PlatformEvent::Type type, int clickCount, Modifiers modifiers, SyntheticEventType synthesized, double timestamp, WebPointerProperties::PointerType pointerType = WebPointerProperties::PointerType::Unknown)
         : PlatformEvent(type, modifiers, timestamp)
         , m_position(position)
         , m_globalPosition(globalPosition)
@@ -74,6 +74,7 @@
         , m_clickCount(clickCount)
         , m_synthesized(synthesized)
     {
+        m_pointerProperties.pointerType = pointerType;
     }
 
     const WebPointerProperties& pointerProperties() const { return m_pointerProperties; }
diff --git a/third_party/WebKit/Source/platform/TraceEvent.h b/third_party/WebKit/Source/platform/TraceEvent.h
index c7eda72..20b6b7bc 100644
--- a/third_party/WebKit/Source/platform/TraceEvent.h
+++ b/third_party/WebKit/Source/platform/TraceEvent.h
@@ -269,8 +269,8 @@
     typedef MangleBehavior<false> DontMangle;
     typedef MangleBehavior<true> ForceMangle;
 
-    TraceID(const void* id, unsigned* flags) :
-        m_data(static_cast<unsigned long long>(reinterpret_cast<unsigned long>(id)))
+    TraceID(const void* id, unsigned* flags)
+        : m_data(static_cast<unsigned long long>(reinterpret_cast<uintptr_t>(id)))
     {
         *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
     }
diff --git a/third_party/WebKit/Source/platform/Widget.h b/third_party/WebKit/Source/platform/Widget.h
index d4697138..123bb8c 100644
--- a/third_party/WebKit/Source/platform/Widget.h
+++ b/third_party/WebKit/Source/platform/Widget.h
@@ -67,7 +67,7 @@
     void resize(int w, int h) { setFrameRect(IntRect(x(), y(), w, h)); }
     void resize(const IntSize& s) { setFrameRect(IntRect(location(), s)); }
 
-    virtual void paint(GraphicsContext*, const CullRect&) const { }
+    virtual void paint(GraphicsContext&, const CullRect&) const { }
     void invalidate() { invalidateRect(boundsRect()); }
     virtual void invalidateRect(const IntRect&) = 0;
 
diff --git a/third_party/WebKit/Source/platform/audio/AudioUtilities.h b/third_party/WebKit/Source/platform/audio/AudioUtilities.h
index 6e0d9cb..68bf2a3 100644
--- a/third_party/WebKit/Source/platform/audio/AudioUtilities.h
+++ b/third_party/WebKit/Source/platform/audio/AudioUtilities.h
@@ -31,6 +31,10 @@
 namespace blink {
 namespace AudioUtilities {
 
+// Rendering quantum size.  This is how many frames are processed at a time for each node in the
+// audio graph.
+static const unsigned kRenderQuantumFrames = 128;
+
 // Standard functions for converting to and from decibel values from linear.
 PLATFORM_EXPORT float linearToDecibels(float);
 PLATFORM_EXPORT float decibelsToLinear(float);
diff --git a/third_party/WebKit/Source/platform/audio/Biquad.cpp b/third_party/WebKit/Source/platform/audio/Biquad.cpp
index ae19ebc..0931d56 100644
--- a/third_party/WebKit/Source/platform/audio/Biquad.cpp
+++ b/third_party/WebKit/Source/platform/audio/Biquad.cpp
@@ -32,11 +32,13 @@
 
 #include "platform/audio/Biquad.h"
 
-#include <stdio.h>
-#include <algorithm>
+#include "platform/audio/AudioUtilities.h"
 #include "platform/audio/DenormalDisabler.h"
 #include "wtf/MathExtras.h"
 
+#include <algorithm>
+#include <stdio.h>
+
 #if OS(MACOSX)
 #include <Accelerate/Accelerate.h>
 #endif
@@ -48,6 +50,7 @@
 #endif
 
 Biquad::Biquad()
+    : m_hasSampleAccurateValues(false)
 {
 #if OS(MACOSX)
     // Allocate two samples more for filter history
@@ -61,8 +64,16 @@
     m_ippInternalBuffer = ippsMalloc_8u(bufferSize);
 #endif // USE(WEBAUDIO_IPP)
 
+    // Allocate enough space for the a-rate filter coefficients to handle a rendering quantum of 128
+    // frames.
+    m_b0.allocate(AudioUtilities::kRenderQuantumFrames);
+    m_b1.allocate(AudioUtilities::kRenderQuantumFrames);
+    m_b2.allocate(AudioUtilities::kRenderQuantumFrames);
+    m_a1.allocate(AudioUtilities::kRenderQuantumFrames);
+    m_a2.allocate(AudioUtilities::kRenderQuantumFrames);
+
     // Initialize as pass-thru (straight-wire, no filter effect)
-    setNormalizedCoefficients(1, 0, 0, 1, 0, 0);
+    setNormalizedCoefficients(0, 1, 0, 0, 1, 0, 0);
 
     reset(); // clear filter memory
 }
@@ -76,55 +87,111 @@
 
 void Biquad::process(const float* sourceP, float* destP, size_t framesToProcess)
 {
+    if (hasSampleAccurateValues()) {
+        int n = framesToProcess;
+
+        // Create local copies of member variables
+        double x1 = m_x1;
+        double x2 = m_x2;
+        double y1 = m_y1;
+        double y2 = m_y2;
+
+        const double* b0 = m_b0.data();
+        const double* b1 = m_b1.data();
+        const double* b2 = m_b2.data();
+        const double* a1 = m_a1.data();
+        const double* a2 = m_a2.data();
+
+        for (int k = 0; k < n; ++k) {
+            // FIXME: this can be optimized by pipelining the multiply adds...
+            float x = *sourceP++;
+            float y = b0[k]*x + b1[k]*x1 + b2[k]*x2 - a1[k]*y1 - a2[k]*y2;
+
+            *destP++ = y;
+
+            // Update state variables
+            x2 = x1;
+            x1 = x;
+            y2 = y1;
+            y1 = y;
+        }
+
+        // Local variables back to member. Flush denormals here so we
+        // don't slow down the inner loop above.
+        m_x1 = DenormalDisabler::flushDenormalFloatToZero(x1);
+        m_x2 = DenormalDisabler::flushDenormalFloatToZero(x2);
+        m_y1 = DenormalDisabler::flushDenormalFloatToZero(y1);
+        m_y2 = DenormalDisabler::flushDenormalFloatToZero(y2);
+
+        // There is an assumption here that once we have sample accurate values we can never go back
+        // to not having sample accurate values.  This is currently true in the way
+        // AudioParamTimline is implemented: once an event is inserted, sample accurate processing
+        // is always enabled.
+        //
+        // If so, then we never have to update the state variables for the MACOSX or WEBAUDIO_IPP
+        // path.  The structure of the state variable in these cases aren't well documented so it's
+        // not clear how to update them anyway.
+    } else {
 #if OS(MACOSX)
-    // Use vecLib if available
-    processFast(sourceP, destP, framesToProcess);
+        // Use vecLib if available
+        processFast(sourceP, destP, framesToProcess);
+
+        // Copy the last inputs and outputs to the filter memory variables.  This is needed because
+        // the next rendering quantum might be an automation which needs the history to continue
+        // correctly.
+        m_x1 = sourceP[framesToProcess - 1];
+        m_x2 = sourceP[framesToProcess - 2];
+        m_y1 = destP[framesToProcess - 1];
+        m_y2 = destP[framesToProcess - 2];
 
 #elif USE(WEBAUDIO_IPP)
-    ippsIIR64f_32f(sourceP, destP, static_cast<int>(framesToProcess), m_biquadState);
+        ippsIIR64f_32f(sourceP, destP, static_cast<int>(framesToProcess), m_biquadState);
+
+        // Copy the last inputs and outputs to the filter memory variables.  This is needed because
+        // the next rendering quantum might be an automation which needs the history to continue
+        // correctly.
+        m_x1 = sourceP[framesToProcess - 1];
+        m_x2 = sourceP[framesToProcess - 2];
+        m_y1 = destP[framesToProcess - 1];
+        m_y2 = destP[framesToProcess - 2];
 #else // USE(WEBAUDIO_IPP)
 
-    int n = framesToProcess;
+        int n = framesToProcess;
 
-    // Create local copies of member variables
-    double x1 = m_x1;
-    double x2 = m_x2;
-    double y1 = m_y1;
-    double y2 = m_y2;
+        // Create local copies of member variables
+        double x1 = m_x1;
+        double x2 = m_x2;
+        double y1 = m_y1;
+        double y2 = m_y2;
 
-    double b0 = m_b0;
-    double b1 = m_b1;
-    double b2 = m_b2;
-    double a1 = m_a1;
-    double a2 = m_a2;
+        double b0 = m_b0[0];
+        double b1 = m_b1[0];
+        double b2 = m_b2[0];
+        double a1 = m_a1[0];
+        double a2 = m_a2[0];
 
-    while (n--) {
-        // FIXME: this can be optimized by pipelining the multiply adds...
-        float x = *sourceP++;
-        float y = b0*x + b1*x1 + b2*x2 - a1*y1 - a2*y2;
+        while (n--) {
+            // FIXME: this can be optimized by pipelining the multiply adds...
+            float x = *sourceP++;
+            float y = b0*x + b1*x1 + b2*x2 - a1*y1 - a2*y2;
 
-        *destP++ = y;
+            *destP++ = y;
 
-        // Update state variables
-        x2 = x1;
-        x1 = x;
-        y2 = y1;
-        y1 = y;
-    }
+            // Update state variables
+            x2 = x1;
+            x1 = x;
+            y2 = y1;
+            y1 = y;
+        }
 
-    // Local variables back to member. Flush denormals here so we
-    // don't slow down the inner loop above.
-    m_x1 = DenormalDisabler::flushDenormalFloatToZero(x1);
-    m_x2 = DenormalDisabler::flushDenormalFloatToZero(x2);
-    m_y1 = DenormalDisabler::flushDenormalFloatToZero(y1);
-    m_y2 = DenormalDisabler::flushDenormalFloatToZero(y2);
-
-    m_b0 = b0;
-    m_b1 = b1;
-    m_b2 = b2;
-    m_a1 = a1;
-    m_a2 = a2;
+        // Local variables back to member. Flush denormals here so we
+        // don't slow down the inner loop above.
+        m_x1 = DenormalDisabler::flushDenormalFloatToZero(x1);
+        m_x2 = DenormalDisabler::flushDenormalFloatToZero(x2);
+        m_y1 = DenormalDisabler::flushDenormalFloatToZero(y1);
+        m_y2 = DenormalDisabler::flushDenormalFloatToZero(y2);
 #endif
+    }
 }
 
 #if OS(MACOSX)
@@ -134,11 +201,11 @@
 void Biquad::processFast(const float* sourceP, float* destP, size_t framesToProcess)
 {
     double filterCoefficients[5];
-    filterCoefficients[0] = m_b0;
-    filterCoefficients[1] = m_b1;
-    filterCoefficients[2] = m_b2;
-    filterCoefficients[3] = m_a1;
-    filterCoefficients[4] = m_a2;
+    filterCoefficients[0] = m_b0[0];
+    filterCoefficients[1] = m_b1[0];
+    filterCoefficients[2] = m_b2[0];
+    filterCoefficients[3] = m_a1[0];
+    filterCoefficients[4] = m_a2[0];
 
     double* inputP = m_inputBuffer.data();
     double* outputP = m_outputBuffer.data();
@@ -201,20 +268,20 @@
     ippsIIRGetStateSize64f_BiQuad_32f(1, &bufferSize);
     ippsZero_8u(m_ippInternalBuffer, bufferSize);
 
-#else
-    m_x1 = m_x2 = m_y1 = m_y2 = 0;
 #endif
+    m_x1 = m_x2 = m_y1 = m_y2 = 0;
 }
 
-void Biquad::setLowpassParams(double cutoff, double resonance)
+void Biquad::setLowpassParams(int index, double cutoff, double resonance)
 {
     // Limit cutoff to 0 to 1.
     cutoff = std::max(0.0, std::min(cutoff, 1.0));
 
     if (cutoff == 1) {
         // When cutoff is 1, the z-transform is 1.
-        setNormalizedCoefficients(1, 0, 0,
-                                  1, 0, 0);
+        setNormalizedCoefficients(index,
+            1, 0, 0,
+            1, 0, 0);
     } else if (cutoff > 0) {
         // Compute biquad coefficients for lowpass filter
         resonance = std::max(0.0, resonance); // can't go negative
@@ -233,24 +300,26 @@
         double a1 = 2 * -gamma;
         double a2 = 2 * beta;
 
-        setNormalizedCoefficients(b0, b1, b2, 1, a1, a2);
+        setNormalizedCoefficients(index, b0, b1, b2, 1, a1, a2);
     } else {
         // When cutoff is zero, nothing gets through the filter, so set
         // coefficients up correctly.
-        setNormalizedCoefficients(0, 0, 0,
-                                  1, 0, 0);
+        setNormalizedCoefficients(index,
+            0, 0, 0,
+            1, 0, 0);
     }
 }
 
-void Biquad::setHighpassParams(double cutoff, double resonance)
+void Biquad::setHighpassParams(int index, double cutoff, double resonance)
 {
     // Limit cutoff to 0 to 1.
     cutoff = std::max(0.0, std::min(cutoff, 1.0));
 
     if (cutoff == 1) {
         // The z-transform is 0.
-        setNormalizedCoefficients(0, 0, 0,
-                                  1, 0, 0);
+        setNormalizedCoefficients(index,
+            0, 0, 0,
+            1, 0, 0);
     } else if (cutoff > 0) {
         // Compute biquad coefficients for highpass filter
         resonance = std::max(0.0, resonance); // can't go negative
@@ -269,42 +338,43 @@
         double a1 = 2 * -gamma;
         double a2 = 2 * beta;
 
-        setNormalizedCoefficients(b0, b1, b2, 1, a1, a2);
+        setNormalizedCoefficients(index, b0, b1, b2, 1, a1, a2);
     } else {
-      // When cutoff is zero, we need to be careful because the above
-      // gives a quadratic divided by the same quadratic, with poles
-      // and zeros on the unit circle in the same place. When cutoff
-      // is zero, the z-transform is 1.
-        setNormalizedCoefficients(1, 0, 0,
-                                  1, 0, 0);
+        // When cutoff is zero, we need to be careful because the above
+        // gives a quadratic divided by the same quadratic, with poles
+        // and zeros on the unit circle in the same place. When cutoff
+        // is zero, the z-transform is 1.
+        setNormalizedCoefficients(index,
+            1, 0, 0,
+            1, 0, 0);
     }
 }
 
-void Biquad::setNormalizedCoefficients(double b0, double b1, double b2, double a0, double a1, double a2)
+void Biquad::setNormalizedCoefficients(int index, double b0, double b1, double b2, double a0, double a1, double a2)
 {
     double a0Inverse = 1 / a0;
 
-    m_b0 = b0 * a0Inverse;
-    m_b1 = b1 * a0Inverse;
-    m_b2 = b2 * a0Inverse;
-    m_a1 = a1 * a0Inverse;
-    m_a2 = a2 * a0Inverse;
+    m_b0[index] = b0 * a0Inverse;
+    m_b1[index] = b1 * a0Inverse;
+    m_b2[index] = b2 * a0Inverse;
+    m_a1[index] = a1 * a0Inverse;
+    m_a2[index] = a2 * a0Inverse;
 
 #if USE(WEBAUDIO_IPP)
     Ipp64f taps[6];
-    taps[0] = m_b0;
-    taps[1] = m_b1;
-    taps[2] = m_b2;
+    taps[0] = m_b0[0];
+    taps[1] = m_b1[0];
+    taps[2] = m_b2[0];
     taps[3] = 1;
-    taps[4] = m_a1;
-    taps[5] = m_a2;
+    taps[4] = m_a1[0];
+    taps[5] = m_a2[0];
     m_biquadState = 0;
 
     ippsIIRInit64f_BiQuad_32f(&m_biquadState, taps, 1, 0, m_ippInternalBuffer);
 #endif // USE(WEBAUDIO_IPP)
 }
 
-void Biquad::setLowShelfParams(double frequency, double dbGain)
+void Biquad::setLowShelfParams(int index, double frequency, double dbGain)
 {
     // Clip frequencies to between 0 and 1, inclusive.
     frequency = std::max(0.0, std::min(frequency, 1.0));
@@ -313,8 +383,9 @@
 
     if (frequency == 1) {
         // The z-transform is a constant gain.
-        setNormalizedCoefficients(A * A, 0, 0,
-                                  1, 0, 0);
+        setNormalizedCoefficients(index,
+            A * A, 0, 0,
+            1, 0, 0);
     } else if (frequency > 0) {
         double w0 = piDouble * frequency;
         double S = 1; // filter slope (1 is max value)
@@ -331,15 +402,16 @@
         double a1 = -2 * (aMinusOne + aPlusOne * k);
         double a2 = aPlusOne + aMinusOne * k - k2;
 
-        setNormalizedCoefficients(b0, b1, b2, a0, a1, a2);
+        setNormalizedCoefficients(index, b0, b1, b2, a0, a1, a2);
     } else {
         // When frequency is 0, the z-transform is 1.
-        setNormalizedCoefficients(1, 0, 0,
-                                  1, 0, 0);
+        setNormalizedCoefficients(index,
+            1, 0, 0,
+            1, 0, 0);
     }
 }
 
-void Biquad::setHighShelfParams(double frequency, double dbGain)
+void Biquad::setHighShelfParams(int index, double frequency, double dbGain)
 {
     // Clip frequencies to between 0 and 1, inclusive.
     frequency = std::max(0.0, std::min(frequency, 1.0));
@@ -348,8 +420,9 @@
 
     if (frequency == 1) {
         // The z-transform is 1.
-        setNormalizedCoefficients(1, 0, 0,
-                                  1, 0, 0);
+        setNormalizedCoefficients(index,
+            1, 0, 0,
+            1, 0, 0);
     } else if (frequency > 0) {
         double w0 = piDouble * frequency;
         double S = 1; // filter slope (1 is max value)
@@ -366,15 +439,18 @@
         double a1 = 2 * (aMinusOne - aPlusOne * k);
         double a2 = aPlusOne - aMinusOne * k - k2;
 
-        setNormalizedCoefficients(b0, b1, b2, a0, a1, a2);
+        setNormalizedCoefficients(index,
+            b0, b1, b2,
+            a0, a1, a2);
     } else {
         // When frequency = 0, the filter is just a gain, A^2.
-        setNormalizedCoefficients(A * A, 0, 0,
-                                  1, 0, 0);
+        setNormalizedCoefficients(index,
+            A * A, 0, 0,
+            1, 0, 0);
     }
 }
 
-void Biquad::setPeakingParams(double frequency, double Q, double dbGain)
+void Biquad::setPeakingParams(int index, double frequency, double Q, double dbGain)
 {
     // Clip frequencies to between 0 and 1, inclusive.
     frequency = std::max(0.0, std::min(frequency, 1.0));
@@ -397,22 +473,26 @@
             double a1 = -2 * k;
             double a2 = 1 - alpha / A;
 
-            setNormalizedCoefficients(b0, b1, b2, a0, a1, a2);
+            setNormalizedCoefficients(index,
+                b0, b1, b2,
+                a0, a1, a2);
         } else {
             // When Q = 0, the above formulas have problems. If we look at
             // the z-transform, we can see that the limit as Q->0 is A^2, so
             // set the filter that way.
-            setNormalizedCoefficients(A * A, 0, 0,
-                                      1, 0, 0);
+            setNormalizedCoefficients(index,
+                A * A, 0, 0,
+                1, 0, 0);
         }
     } else {
         // When frequency is 0 or 1, the z-transform is 1.
-        setNormalizedCoefficients(1, 0, 0,
-                                  1, 0, 0);
+        setNormalizedCoefficients(index,
+            1, 0, 0,
+            1, 0, 0);
     }
 }
 
-void Biquad::setAllpassParams(double frequency, double Q)
+void Biquad::setAllpassParams(int index, double frequency, double Q)
 {
     // Clip frequencies to between 0 and 1, inclusive.
     frequency = std::max(0.0, std::min(frequency, 1.0));
@@ -433,22 +513,26 @@
             double a1 = -2 * k;
             double a2 = 1 - alpha;
 
-            setNormalizedCoefficients(b0, b1, b2, a0, a1, a2);
+            setNormalizedCoefficients(index,
+                b0, b1, b2,
+                a0, a1, a2);
         } else {
             // When Q = 0, the above formulas have problems. If we look at
             // the z-transform, we can see that the limit as Q->0 is -1, so
             // set the filter that way.
-            setNormalizedCoefficients(-1, 0, 0,
-                                      1, 0, 0);
+            setNormalizedCoefficients(index,
+                -1, 0, 0,
+                1, 0, 0);
         }
     } else {
         // When frequency is 0 or 1, the z-transform is 1.
-        setNormalizedCoefficients(1, 0, 0,
-                                  1, 0, 0);
+        setNormalizedCoefficients(index,
+            1, 0, 0,
+            1, 0, 0);
     }
 }
 
-void Biquad::setNotchParams(double frequency, double Q)
+void Biquad::setNotchParams(int index, double frequency, double Q)
 {
     // Clip frequencies to between 0 and 1, inclusive.
     frequency = std::max(0.0, std::min(frequency, 1.0));
@@ -469,22 +553,26 @@
             double a1 = -2 * k;
             double a2 = 1 - alpha;
 
-            setNormalizedCoefficients(b0, b1, b2, a0, a1, a2);
+            setNormalizedCoefficients(index,
+                b0, b1, b2,
+                a0, a1, a2);
         } else {
             // When Q = 0, the above formulas have problems. If we look at
             // the z-transform, we can see that the limit as Q->0 is 0, so
             // set the filter that way.
-            setNormalizedCoefficients(0, 0, 0,
-                                      1, 0, 0);
+            setNormalizedCoefficients(index,
+                0, 0, 0,
+                1, 0, 0);
         }
     } else {
         // When frequency is 0 or 1, the z-transform is 1.
-        setNormalizedCoefficients(1, 0, 0,
-                                  1, 0, 0);
+        setNormalizedCoefficients(index,
+            1, 0, 0,
+            1, 0, 0);
     }
 }
 
-void Biquad::setBandpassParams(double frequency, double Q)
+void Biquad::setBandpassParams(int index, double frequency, double Q)
 {
     // No negative frequencies allowed.
     frequency = std::max(0.0, frequency);
@@ -505,13 +593,16 @@
             double a1 = -2 * k;
             double a2 = 1 - alpha;
 
-            setNormalizedCoefficients(b0, b1, b2, a0, a1, a2);
+            setNormalizedCoefficients(index,
+                b0, b1, b2,
+                a0, a1, a2);
         } else {
             // When Q = 0, the above formulas have problems. If we look at
             // the z-transform, we can see that the limit as Q->0 is 1, so
             // set the filter that way.
-            setNormalizedCoefficients(1, 0, 0,
-                                      1, 0, 0);
+            setNormalizedCoefficients(index,
+                1, 0, 0,
+                1, 0, 0);
         }
     } else {
         // When the cutoff is zero, the z-transform approaches 0, if Q
@@ -519,8 +610,9 @@
         // pretty much undefined. What should we do in this case?
         // For now, just make the filter 0. When the cutoff is 1, the
         // z-transform also approaches 0.
-        setNormalizedCoefficients(0, 0, 0,
-                                  1, 0, 0);
+        setNormalizedCoefficients(index,
+            0, 0, 0,
+            1, 0, 0);
     }
 }
 
@@ -546,11 +638,11 @@
     // with z1 = 1/z and z = exp(j*pi*frequency). Hence z1 = exp(-j*pi*frequency)
 
     // Make local copies of the coefficients as a micro-optimization.
-    double b0 = m_b0;
-    double b1 = m_b1;
-    double b2 = m_b2;
-    double a1 = m_a1;
-    double a2 = m_a2;
+    double b0 = m_b0[0];
+    double b1 = m_b1[0];
+    double b2 = m_b2[0];
+    double a1 = m_a1[0];
+    double a2 = m_a2[0];
 
     for (int k = 0; k < nFrequencies; ++k) {
         double omega = -piDouble * frequency[k];
diff --git a/third_party/WebKit/Source/platform/audio/Biquad.h b/third_party/WebKit/Source/platform/audio/Biquad.h
index dab9821..49720d3 100644
--- a/third_party/WebKit/Source/platform/audio/Biquad.h
+++ b/third_party/WebKit/Source/platform/audio/Biquad.h
@@ -54,16 +54,19 @@
 
     void process(const float* sourceP, float* destP, size_t framesToProcess);
 
+    bool hasSampleAccurateValues() const { return m_hasSampleAccurateValues; }
+    void setHasSampleAccurateValues(bool isSampleAccurate) { m_hasSampleAccurateValues = isSampleAccurate; }
+
     // frequency is 0 - 1 normalized, resonance and dbGain are in decibels.
     // Q is a unitless quality factor.
-    void setLowpassParams(double frequency, double resonance);
-    void setHighpassParams(double frequency, double resonance);
-    void setBandpassParams(double frequency, double Q);
-    void setLowShelfParams(double frequency, double dbGain);
-    void setHighShelfParams(double frequency, double dbGain);
-    void setPeakingParams(double frequency, double Q, double dbGain);
-    void setAllpassParams(double frequency, double Q);
-    void setNotchParams(double frequency, double Q);
+    void setLowpassParams(int, double frequency, double resonance);
+    void setHighpassParams(int, double frequency, double resonance);
+    void setBandpassParams(int, double frequency, double Q);
+    void setLowShelfParams(int, double frequency, double dbGain);
+    void setHighShelfParams(int, double frequency, double dbGain);
+    void setPeakingParams(int, double frequency, double Q, double dbGain);
+    void setAllpassParams(int, double frequency, double Q);
+    void setNotchParams(int, double frequency, double Q);
 
     // Resets filter state
     void reset();
@@ -76,16 +79,20 @@
                               float* magResponse,
                               float* phaseResponse);
 private:
-    void setNormalizedCoefficients(double b0, double b1, double b2, double a0, double a1, double a2);
+    void setNormalizedCoefficients(int, double b0, double b1, double b2, double a0, double a1, double a2);
+
+    // If true, the filter coefficients are (possibly) time-varying due to a timeline automation on
+    // at least one filter parameter.
+    bool m_hasSampleAccurateValues;
 
     // Filter coefficients. The filter is defined as
     //
     // y[n] + m_a1*y[n-1] + m_a2*y[n-2] = m_b0*x[n] + m_b1*x[n-1] + m_b2*x[n-2].
-    double m_b0;
-    double m_b1;
-    double m_b2;
-    double m_a1;
-    double m_a2;
+    AudioDoubleArray m_b0;
+    AudioDoubleArray m_b1;
+    AudioDoubleArray m_b2;
+    AudioDoubleArray m_a1;
+    AudioDoubleArray m_a2;
 
 #if OS(MACOSX)
     void processFast(const float* sourceP, float* destP, size_t framesToProcess);
@@ -98,13 +105,12 @@
     IppsIIRState64f_32f* m_biquadState;
     Ipp8u* m_ippInternalBuffer;
 
-#else
+#endif
     // Filter memory
     double m_x1; // input delayed by 1 sample
     double m_x2; // input delayed by 2 samples
     double m_y1; // output delayed by 1 sample
     double m_y2; // output delayed by 2 samples
-#endif
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/blink_platform.gypi b/third_party/WebKit/Source/platform/blink_platform.gypi
index 2f30ce1..c8d6b876 100644
--- a/third_party/WebKit/Source/platform/blink_platform.gypi
+++ b/third_party/WebKit/Source/platform/blink_platform.gypi
@@ -600,6 +600,8 @@
       'graphics/ThreadSafeDataTransport.h',
       'graphics/UnacceleratedImageBufferSurface.cpp',
       'graphics/UnacceleratedImageBufferSurface.h',
+      'graphics/compositing/PaintArtifactCompositor.cpp',
+      'graphics/compositing/PaintArtifactCompositor.h',
       'graphics/cpu/arm/WebGLImageConversionNEON.h',
       'graphics/cpu/x86/WebGLImageConversionSSE.h',
       'graphics/filters/DistantLightSource.cpp',
diff --git a/third_party/WebKit/Source/platform/exported/WebScrollbarThemeClientImpl.cpp b/third_party/WebKit/Source/platform/exported/WebScrollbarThemeClientImpl.cpp
index 83ab99d..6c7513b1 100644
--- a/third_party/WebKit/Source/platform/exported/WebScrollbarThemeClientImpl.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebScrollbarThemeClientImpl.cpp
@@ -31,15 +31,15 @@
 
 namespace blink {
 
-WebScrollbarThemeClientImpl::WebScrollbarThemeClientImpl(WebScrollbar* scrollbar)
+WebScrollbarThemeClientImpl::WebScrollbarThemeClientImpl(WebScrollbar& scrollbar)
     : m_scrollbar(scrollbar)
 {
-    ScrollbarTheme::theme()->registerScrollbar(this);
+    ScrollbarTheme::theme().registerScrollbar(*this);
 }
 
 WebScrollbarThemeClientImpl::~WebScrollbarThemeClientImpl()
 {
-    ScrollbarTheme::theme()->unregisterScrollbar(this);
+    ScrollbarTheme::theme().unregisterScrollbar(*this);
 }
 
 int WebScrollbarThemeClientImpl::x() const
@@ -64,12 +64,12 @@
 
 IntSize WebScrollbarThemeClientImpl::size() const
 {
-    return m_scrollbar->size();
+    return m_scrollbar.size();
 }
 
 IntPoint WebScrollbarThemeClientImpl::location() const
 {
-    return m_scrollbar->location();
+    return m_scrollbar.location();
 }
 
 Widget* WebScrollbarThemeClientImpl::parent() const
@@ -111,13 +111,13 @@
 
 ScrollbarOverlayStyle WebScrollbarThemeClientImpl::scrollbarOverlayStyle() const
 {
-    return static_cast<ScrollbarOverlayStyle>(m_scrollbar->scrollbarOverlayStyle());
+    return static_cast<ScrollbarOverlayStyle>(m_scrollbar.scrollbarOverlayStyle());
 }
 
 void WebScrollbarThemeClientImpl::getTickmarks(Vector<IntRect>& tickmarks) const
 {
     WebVector<WebRect> webTickmarks;
-    m_scrollbar->getTickmarks(webTickmarks);
+    m_scrollbar.getTickmarks(webTickmarks);
     tickmarks.resize(webTickmarks.size());
     for (size_t i = 0; i < webTickmarks.size(); ++i)
         tickmarks[i] = webTickmarks[i];
@@ -125,7 +125,7 @@
 
 bool WebScrollbarThemeClientImpl::isScrollableAreaActive() const
 {
-    return m_scrollbar->isScrollableAreaActive();
+    return m_scrollbar.isScrollableAreaActive();
 }
 
 IntPoint WebScrollbarThemeClientImpl::convertFromRootFrame(const IntPoint& pointInRootFrame) const
@@ -137,22 +137,22 @@
 
 bool WebScrollbarThemeClientImpl::isCustomScrollbar() const
 {
-    return m_scrollbar->isCustomScrollbar();
+    return m_scrollbar.isCustomScrollbar();
 }
 
 ScrollbarOrientation WebScrollbarThemeClientImpl::orientation() const
 {
-    return static_cast<ScrollbarOrientation>(m_scrollbar->orientation());
+    return static_cast<ScrollbarOrientation>(m_scrollbar.orientation());
 }
 
 bool WebScrollbarThemeClientImpl::isLeftSideVerticalScrollbar() const
 {
-    return m_scrollbar->isLeftSideVerticalScrollbar();
+    return m_scrollbar.isLeftSideVerticalScrollbar();
 }
 
 int WebScrollbarThemeClientImpl::value() const
 {
-    return m_scrollbar->value();
+    return m_scrollbar.value();
 }
 
 float WebScrollbarThemeClientImpl::currentPos() const
@@ -167,27 +167,27 @@
 
 int WebScrollbarThemeClientImpl::totalSize() const
 {
-    return m_scrollbar->totalSize();
+    return m_scrollbar.totalSize();
 }
 
 int WebScrollbarThemeClientImpl::maximum() const
 {
-    return m_scrollbar->maximum();
+    return m_scrollbar.maximum();
 }
 
 ScrollbarControlSize WebScrollbarThemeClientImpl::controlSize() const
 {
-    return static_cast<ScrollbarControlSize>(m_scrollbar->controlSize());
+    return static_cast<ScrollbarControlSize>(m_scrollbar.controlSize());
 }
 
 ScrollbarPart WebScrollbarThemeClientImpl::pressedPart() const
 {
-    return static_cast<ScrollbarPart>(m_scrollbar->pressedPart());
+    return static_cast<ScrollbarPart>(m_scrollbar.pressedPart());
 }
 
 ScrollbarPart WebScrollbarThemeClientImpl::hoveredPart() const
 {
-    return static_cast<ScrollbarPart>(m_scrollbar->hoveredPart());
+    return static_cast<ScrollbarPart>(m_scrollbar.hoveredPart());
 }
 
 void WebScrollbarThemeClientImpl::styleChanged()
@@ -201,7 +201,7 @@
 
 bool WebScrollbarThemeClientImpl::enabled() const
 {
-    return m_scrollbar->enabled();
+    return m_scrollbar.enabled();
 }
 
 void WebScrollbarThemeClientImpl::setEnabled(bool)
@@ -211,27 +211,27 @@
 
 bool WebScrollbarThemeClientImpl::isOverlayScrollbar() const
 {
-    return m_scrollbar->isOverlay();
+    return m_scrollbar.isOverlay();
 }
 
 bool WebScrollbarThemeClientImpl::isAlphaLocked() const
 {
-    return m_scrollbar->isAlphaLocked();
+    return m_scrollbar.isAlphaLocked();
 }
 
 void WebScrollbarThemeClientImpl::setIsAlphaLocked(bool flag)
 {
-    m_scrollbar->setIsAlphaLocked(flag);
+    m_scrollbar.setIsAlphaLocked(flag);
 }
 
 float WebScrollbarThemeClientImpl::elasticOverscroll() const
 {
-    return m_scrollbar->elasticOverscroll();
+    return m_scrollbar.elasticOverscroll();
 }
 
 void WebScrollbarThemeClientImpl::setElasticOverscroll(float elasticOverscroll)
 {
-    return m_scrollbar->setElasticOverscroll(elasticOverscroll);
+    return m_scrollbar.setElasticOverscroll(elasticOverscroll);
 }
 
 bool WebScrollbarThemeClientImpl::trackNeedsRepaint() const
@@ -254,12 +254,6 @@
     ASSERT_NOT_REACHED();
 }
 
-DisplayItemClient WebScrollbarThemeClientImpl::displayItemClient() const
-{
-    ASSERT_NOT_REACHED();
-    return toDisplayItemClient(this);
-}
-
 String WebScrollbarThemeClientImpl::debugName() const
 {
     return "WebScrollbarThemeClientImpl";
diff --git a/third_party/WebKit/Source/platform/exported/WebScrollbarThemeClientImpl.h b/third_party/WebKit/Source/platform/exported/WebScrollbarThemeClientImpl.h
index 679b2e7..5121b40 100644
--- a/third_party/WebKit/Source/platform/exported/WebScrollbarThemeClientImpl.h
+++ b/third_party/WebKit/Source/platform/exported/WebScrollbarThemeClientImpl.h
@@ -39,7 +39,7 @@
 public:
     // Caller must retain ownership of this pointer and ensure that its lifetime
     // exceeds this instance.
-    WebScrollbarThemeClientImpl(WebScrollbar*);
+    WebScrollbarThemeClientImpl(WebScrollbar&);
     ~WebScrollbarThemeClientImpl() override;
 
     // Implement ScrollbarThemeClient interface
@@ -83,11 +83,10 @@
     void setTrackNeedsRepaint(bool) override;
     bool thumbNeedsRepaint() const override;
     void setThumbNeedsRepaint(bool) override;
-    DisplayItemClient displayItemClient() const override;
-    String debugName() const override;
+    String debugName() const final;
 
 private:
-    WebScrollbar* m_scrollbar;
+    WebScrollbar& m_scrollbar;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebScrollbarThemeGeometryNative.cpp b/third_party/WebKit/Source/platform/exported/WebScrollbarThemeGeometryNative.cpp
index d9df7d2..dd1615e 100644
--- a/third_party/WebKit/Source/platform/exported/WebScrollbarThemeGeometryNative.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebScrollbarThemeGeometryNative.cpp
@@ -33,12 +33,12 @@
 
 namespace blink {
 
-PassOwnPtr<WebScrollbarThemeGeometryNative> WebScrollbarThemeGeometryNative::create(ScrollbarTheme* theme)
+PassOwnPtr<WebScrollbarThemeGeometryNative> WebScrollbarThemeGeometryNative::create(ScrollbarTheme& theme)
 {
     return adoptPtr(new WebScrollbarThemeGeometryNative(theme));
 }
 
-WebScrollbarThemeGeometryNative::WebScrollbarThemeGeometryNative(ScrollbarTheme* theme)
+WebScrollbarThemeGeometryNative::WebScrollbarThemeGeometryNative(ScrollbarTheme& theme)
     : m_theme(theme)
 {
 }
@@ -50,102 +50,86 @@
 
 int WebScrollbarThemeGeometryNative::thumbPosition(WebScrollbar* scrollbar)
 {
-    WebScrollbarThemeClientImpl client(scrollbar);
-    return m_theme->thumbPosition(&client);
+    return m_theme.thumbPosition(WebScrollbarThemeClientImpl(*scrollbar));
 }
 
 int WebScrollbarThemeGeometryNative::thumbLength(WebScrollbar* scrollbar)
 {
-    WebScrollbarThemeClientImpl client(scrollbar);
-    return m_theme->thumbLength(&client);
+    return m_theme.thumbLength(WebScrollbarThemeClientImpl(*scrollbar));
 }
 
 int WebScrollbarThemeGeometryNative::trackPosition(WebScrollbar* scrollbar)
 {
-    WebScrollbarThemeClientImpl client(scrollbar);
-    return m_theme->trackPosition(&client);
+    return m_theme.trackPosition(WebScrollbarThemeClientImpl(*scrollbar));
 }
 
 int WebScrollbarThemeGeometryNative::trackLength(WebScrollbar* scrollbar)
 {
-    WebScrollbarThemeClientImpl client(scrollbar);
-    return m_theme->trackLength(&client);
+    return m_theme.trackLength(WebScrollbarThemeClientImpl(*scrollbar));
 }
 
 bool WebScrollbarThemeGeometryNative::hasButtons(WebScrollbar* scrollbar)
 {
-    WebScrollbarThemeClientImpl client(scrollbar);
-    return m_theme->hasButtons(&client);
+    return m_theme.hasButtons(WebScrollbarThemeClientImpl(*scrollbar));
 }
 
 bool WebScrollbarThemeGeometryNative::hasThumb(WebScrollbar* scrollbar)
 {
-    WebScrollbarThemeClientImpl client(scrollbar);
-    return m_theme->hasThumb(&client);
+    return m_theme.hasThumb(WebScrollbarThemeClientImpl(*scrollbar));
 }
 
 WebRect WebScrollbarThemeGeometryNative::trackRect(WebScrollbar* scrollbar)
 {
-    WebScrollbarThemeClientImpl client(scrollbar);
-    return m_theme->trackRect(&client);
+    return m_theme.trackRect(WebScrollbarThemeClientImpl(*scrollbar));
 }
 
 WebRect WebScrollbarThemeGeometryNative::thumbRect(WebScrollbar* scrollbar)
 {
-    WebScrollbarThemeClientImpl client(scrollbar);
-    return m_theme->thumbRect(&client);
+    return m_theme.thumbRect(WebScrollbarThemeClientImpl(*scrollbar));
 }
 
 int WebScrollbarThemeGeometryNative::minimumThumbLength(WebScrollbar* scrollbar)
 {
-    WebScrollbarThemeClientImpl client(scrollbar);
-    return m_theme->minimumThumbLength(&client);
+    return m_theme.minimumThumbLength(WebScrollbarThemeClientImpl(*scrollbar));
 }
 
 int WebScrollbarThemeGeometryNative::scrollbarThickness(WebScrollbar* scrollbar)
 {
-    WebScrollbarThemeClientImpl client(scrollbar);
-    return m_theme->scrollbarThickness(client.controlSize());
+    return m_theme.scrollbarThickness(WebScrollbarThemeClientImpl(*scrollbar).controlSize());
 }
 
 WebRect WebScrollbarThemeGeometryNative::backButtonStartRect(WebScrollbar* scrollbar)
 {
-    WebScrollbarThemeClientImpl client(scrollbar);
-    return m_theme->backButtonRect(&client, BackButtonStartPart, false);
+    return m_theme.backButtonRect(WebScrollbarThemeClientImpl(*scrollbar), BackButtonStartPart, false);
 }
 
 WebRect WebScrollbarThemeGeometryNative::backButtonEndRect(WebScrollbar* scrollbar)
 {
-    WebScrollbarThemeClientImpl client(scrollbar);
-    return m_theme->backButtonRect(&client, BackButtonEndPart, false);
+    return m_theme.backButtonRect(WebScrollbarThemeClientImpl(*scrollbar), BackButtonEndPart, false);
 }
 
 WebRect WebScrollbarThemeGeometryNative::forwardButtonStartRect(WebScrollbar* scrollbar)
 {
-    WebScrollbarThemeClientImpl client(scrollbar);
-    return m_theme->forwardButtonRect(&client, ForwardButtonStartPart, false);
+    return m_theme.forwardButtonRect(WebScrollbarThemeClientImpl(*scrollbar), ForwardButtonStartPart, false);
 }
 
 WebRect WebScrollbarThemeGeometryNative::forwardButtonEndRect(WebScrollbar* scrollbar)
 {
-    WebScrollbarThemeClientImpl client(scrollbar);
-    return m_theme->forwardButtonRect(&client, ForwardButtonEndPart, false);
+    return m_theme.forwardButtonRect(WebScrollbarThemeClientImpl(*scrollbar), ForwardButtonEndPart, false);
 }
 
 WebRect WebScrollbarThemeGeometryNative::constrainTrackRectToTrackPieces(WebScrollbar* scrollbar, const WebRect& rect)
 {
-    WebScrollbarThemeClientImpl client(scrollbar);
-    return m_theme->constrainTrackRectToTrackPieces(&client, IntRect(rect));
+    return m_theme.constrainTrackRectToTrackPieces(WebScrollbarThemeClientImpl(*scrollbar), IntRect(rect));
 }
 
 void WebScrollbarThemeGeometryNative::splitTrack(WebScrollbar* scrollbar, const WebRect& webTrack, WebRect& webStartTrack, WebRect& webThumb, WebRect& webEndTrack)
 {
-    WebScrollbarThemeClientImpl client(scrollbar);
     IntRect track(webTrack);
     IntRect startTrack;
     IntRect thumb;
     IntRect endTrack;
-    m_theme->splitTrack(&client, track, startTrack, thumb, endTrack);
+    m_theme.splitTrack(WebScrollbarThemeClientImpl(*scrollbar), track, startTrack, thumb, endTrack);
 
     webStartTrack = startTrack;
     webThumb = thumb;
diff --git a/third_party/WebKit/Source/platform/exported/WebScrollbarThemeGeometryNative.h b/third_party/WebKit/Source/platform/exported/WebScrollbarThemeGeometryNative.h
index 0030f8c9..29f80f9 100644
--- a/third_party/WebKit/Source/platform/exported/WebScrollbarThemeGeometryNative.h
+++ b/third_party/WebKit/Source/platform/exported/WebScrollbarThemeGeometryNative.h
@@ -38,7 +38,7 @@
 
 class PLATFORM_EXPORT WebScrollbarThemeGeometryNative : public WebScrollbarThemeGeometry {
 public:
-    static PassOwnPtr<WebScrollbarThemeGeometryNative> create(ScrollbarTheme*);
+    static PassOwnPtr<WebScrollbarThemeGeometryNative> create(ScrollbarTheme&);
 
     // WebScrollbarThemeGeometry overrides
     WebScrollbarThemeGeometryNative* clone() const override;
@@ -60,12 +60,12 @@
     void splitTrack(WebScrollbar*, const WebRect& track, WebRect& startTrack, WebRect& thumb, WebRect& endTrack) override;
 
 private:
-    explicit WebScrollbarThemeGeometryNative(ScrollbarTheme*);
+    explicit WebScrollbarThemeGeometryNative(ScrollbarTheme&);
 
     // The theme is not owned by this class. It is assumed that the theme is a
     // static pointer and its lifetime is essentially infinite. Only thread-safe
     // functions on the theme can be called by this theme.
-    ScrollbarTheme* m_theme;
+    ScrollbarTheme& m_theme;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebScrollbarThemePainter.cpp b/third_party/WebKit/Source/platform/exported/WebScrollbarThemePainter.cpp
index d4e9828..1327ca1 100644
--- a/third_party/WebKit/Source/platform/exported/WebScrollbarThemePainter.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebScrollbarThemePainter.cpp
@@ -57,7 +57,7 @@
     IntRect intRect(rect);
     SkPictureBuilder pictureBuilder(intRect);
     pictureBuilder.context().setDeviceScaleFactor(m_deviceScaleFactor);
-    m_theme->paintScrollbarBackground(&pictureBuilder.context(), m_scrollbar.get());
+    m_theme->paintScrollbarBackground(pictureBuilder.context(), *m_scrollbar);
     pictureBuilder.endRecording()->playback(canvas);
 }
 
@@ -66,7 +66,7 @@
     IntRect intRect(rect);
     SkPictureBuilder pictureBuilder(intRect);
     pictureBuilder.context().setDeviceScaleFactor(m_deviceScaleFactor);
-    m_theme->paintTrackBackground(&pictureBuilder.context(), m_scrollbar.get(), intRect);
+    m_theme->paintTrackBackground(pictureBuilder.context(), *m_scrollbar, intRect);
     pictureBuilder.endRecording()->playback(canvas);
     if (!m_theme->shouldRepaintAllPartsOnInvalidation())
         m_scrollbar->setTrackNeedsRepaint(false);
@@ -77,7 +77,7 @@
     IntRect intRect(rect);
     SkPictureBuilder pictureBuilder(intRect);
     pictureBuilder.context().setDeviceScaleFactor(m_deviceScaleFactor);
-    m_theme->paintTrackPiece(&pictureBuilder.context(), m_scrollbar.get(), intRect, BackTrackPart);
+    m_theme->paintTrackPiece(pictureBuilder.context(), *m_scrollbar, intRect, BackTrackPart);
     pictureBuilder.endRecording()->playback(canvas);
 }
 
@@ -86,7 +86,7 @@
     IntRect intRect(rect);
     SkPictureBuilder pictureBuilder(intRect);
     pictureBuilder.context().setDeviceScaleFactor(m_deviceScaleFactor);
-    m_theme->paintTrackPiece(&pictureBuilder.context(), m_scrollbar.get(), intRect, ForwardTrackPart);
+    m_theme->paintTrackPiece(pictureBuilder.context(), *m_scrollbar, intRect, ForwardTrackPart);
     pictureBuilder.endRecording()->playback(canvas);
 }
 
@@ -95,7 +95,7 @@
     IntRect intRect(rect);
     SkPictureBuilder pictureBuilder(intRect);
     pictureBuilder.context().setDeviceScaleFactor(m_deviceScaleFactor);
-    m_theme->paintButton(&pictureBuilder.context(), m_scrollbar.get(), intRect, BackButtonStartPart);
+    m_theme->paintButton(pictureBuilder.context(), *m_scrollbar, intRect, BackButtonStartPart);
     pictureBuilder.endRecording()->playback(canvas);
 }
 
@@ -104,7 +104,7 @@
     IntRect intRect(rect);
     SkPictureBuilder pictureBuilder(intRect);
     pictureBuilder.context().setDeviceScaleFactor(m_deviceScaleFactor);
-    m_theme->paintButton(&pictureBuilder.context(), m_scrollbar.get(), intRect, BackButtonEndPart);
+    m_theme->paintButton(pictureBuilder.context(), *m_scrollbar, intRect, BackButtonEndPart);
     pictureBuilder.endRecording()->playback(canvas);
 }
 
@@ -113,7 +113,7 @@
     IntRect intRect(rect);
     SkPictureBuilder pictureBuilder(intRect);
     pictureBuilder.context().setDeviceScaleFactor(m_deviceScaleFactor);
-    m_theme->paintButton(&pictureBuilder.context(), m_scrollbar.get(), intRect, ForwardButtonStartPart);
+    m_theme->paintButton(pictureBuilder.context(), *m_scrollbar, intRect, ForwardButtonStartPart);
     pictureBuilder.endRecording()->playback(canvas);
 }
 
@@ -122,7 +122,7 @@
     IntRect intRect(rect);
     SkPictureBuilder pictureBuilder(intRect);
     pictureBuilder.context().setDeviceScaleFactor(m_deviceScaleFactor);
-    m_theme->paintButton(&pictureBuilder.context(), m_scrollbar.get(), intRect, ForwardButtonEndPart);
+    m_theme->paintButton(pictureBuilder.context(), *m_scrollbar, intRect, ForwardButtonEndPart);
     pictureBuilder.endRecording()->playback(canvas);
 }
 
@@ -131,7 +131,7 @@
     IntRect intRect(rect);
     SkPictureBuilder pictureBuilder(intRect);
     pictureBuilder.context().setDeviceScaleFactor(m_deviceScaleFactor);
-    m_theme->paintTickmarks(&pictureBuilder.context(), m_scrollbar.get(), intRect);
+    m_theme->paintTickmarks(pictureBuilder.context(), *m_scrollbar, intRect);
     pictureBuilder.endRecording()->playback(canvas);
 }
 
@@ -140,22 +140,22 @@
     IntRect intRect(rect);
     SkPictureBuilder pictureBuilder(intRect);
     pictureBuilder.context().setDeviceScaleFactor(m_deviceScaleFactor);
-    m_theme->paintThumb(&pictureBuilder.context(), m_scrollbar.get(), intRect);
+    m_theme->paintThumb(pictureBuilder.context(), *m_scrollbar, intRect);
     pictureBuilder.endRecording()->playback(canvas);
     if (!m_theme->shouldRepaintAllPartsOnInvalidation())
         m_scrollbar->setThumbNeedsRepaint(false);
 }
 
-WebScrollbarThemePainter::WebScrollbarThemePainter(ScrollbarTheme* theme, Scrollbar* scrollbar, float deviceScaleFactor)
-    : m_theme(theme)
-    , m_scrollbar(scrollbar)
+WebScrollbarThemePainter::WebScrollbarThemePainter(ScrollbarTheme& theme, Scrollbar& scrollbar, float deviceScaleFactor)
+    : m_theme(&theme)
+    , m_scrollbar(&scrollbar)
     , m_deviceScaleFactor(deviceScaleFactor)
 {
 }
 
 float WebScrollbarThemePainter::thumbOpacity() const
 {
-    return m_theme->thumbOpacity(m_scrollbar.get());
+    return m_theme->thumbOpacity(*m_scrollbar);
 }
 
 bool WebScrollbarThemePainter::trackNeedsRepaint() const
diff --git a/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp b/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp
index 46f5dbf..6998d9a 100644
--- a/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp
@@ -305,6 +305,11 @@
     m_private->m_resourceResponse->setSecurityInfo(securityInfo);
 }
 
+void WebURLResponse::setHasMajorCertificateErrors(bool value)
+{
+    m_private->m_resourceResponse->setHasMajorCertificateErrors(value);
+}
+
 WebURLResponse::SecurityStyle WebURLResponse::securityStyle() const
 {
     return static_cast<SecurityStyle>(m_private->m_resourceResponse->securityStyle());
diff --git a/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp b/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp
index db4fb78..77984387 100644
--- a/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp
+++ b/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp
@@ -236,11 +236,6 @@
         m_avgCharWidth = xHeight;
         const Glyph xGlyph = glyphForCharacter('x');
         if (xGlyph) {
-            // In widthForGlyph(), xGlyph will be compared with
-            // m_zeroWidthSpaceGlyph, which isn't initialized yet here.
-            // Initialize it with zero to make sure widthForGlyph() returns
-            // the right width.
-            m_zeroWidthSpaceGlyph = 0;
             m_avgCharWidth = widthForGlyph(xGlyph);
         }
 #if !OS(MACOSX)
@@ -258,16 +253,11 @@
         m_spaceGlyph = 0;
         m_spaceWidth = 0;
         m_zeroGlyph = 0;
-        m_zeroWidthSpaceGlyph = 0;
         m_missingGlyphData.fontData = this;
         m_missingGlyphData.glyph = 0;
         return;
     }
 
-    // Ask for the glyph for 0 to avoid paging in ZERO WIDTH SPACE. Control characters, including 0,
-    // are mapped to the ZERO WIDTH SPACE glyph.
-    m_zeroWidthSpaceGlyph = glyphForCharacter(0);
-
     // Nasty hack to determine if we should round or ceil space widths.
     // If the font is monospace or fake monospace we ceil to ensure that
     // every character and the space are the same width.  Otherwise we round.
@@ -277,14 +267,6 @@
     m_zeroGlyph = glyphForCharacter('0');
     m_fontMetrics.setZeroWidth(widthForGlyph(m_zeroGlyph));
 
-    // Force the glyph for ZERO WIDTH SPACE to have zero width, unless it is shared with SPACE.
-    // Helvetica is an example of a non-zero width ZERO WIDTH SPACE glyph.
-    // See <http://bugs.webkit.org/show_bug.cgi?id=13178>
-    if (m_zeroWidthSpaceGlyph == m_spaceGlyph) {
-        m_zeroWidthSpaceGlyph = 0;
-        WTF_LOG_ERROR("Font maps SPACE and ZERO WIDTH SPACE to the same glyph. Glyph width will not be overridden.");
-    }
-
     m_missingGlyphData.fontData = this;
     m_missingGlyphData.glyph = 0;
 }
diff --git a/third_party/WebKit/Source/platform/fonts/SimpleFontData.h b/third_party/WebKit/Source/platform/fonts/SimpleFontData.h
index 1cc3f08e..9ff6e5d0c 100644
--- a/third_party/WebKit/Source/platform/fonts/SimpleFontData.h
+++ b/third_party/WebKit/Source/platform/fonts/SimpleFontData.h
@@ -103,9 +103,6 @@
 
     Glyph spaceGlyph() const { return m_spaceGlyph; }
     void setSpaceGlyph(Glyph spaceGlyph) { m_spaceGlyph = spaceGlyph; }
-    Glyph zeroWidthSpaceGlyph() const { return m_zeroWidthSpaceGlyph; }
-    void setZeroWidthSpaceGlyph(Glyph spaceGlyph) { m_zeroWidthSpaceGlyph = spaceGlyph; }
-    bool isZeroWidthSpaceGlyph(Glyph glyph) const { return glyph == m_zeroWidthSpaceGlyph && glyph; }
     Glyph zeroGlyph() const { return m_zeroGlyph; }
     void setZeroGlyph(Glyph zeroGlyph) { m_zeroGlyph = zeroGlyph; }
 
@@ -158,8 +155,6 @@
     float m_spaceWidth;
     Glyph m_zeroGlyph;
 
-    Glyph m_zeroWidthSpaceGlyph;
-
     GlyphData m_missingGlyphData;
 
     struct DerivedFontData {
@@ -192,9 +187,6 @@
 
 ALWAYS_INLINE FloatRect SimpleFontData::boundsForGlyph(Glyph glyph) const
 {
-    if (isZeroWidthSpaceGlyph(glyph))
-        return FloatRect();
-
     FloatRect bounds;
     if (m_glyphToBoundsMap) {
         bounds = m_glyphToBoundsMap->metricsForGlyph(glyph);
@@ -211,9 +203,6 @@
 
 ALWAYS_INLINE float SimpleFontData::widthForGlyph(Glyph glyph) const
 {
-    if (isZeroWidthSpaceGlyph(glyph))
-        return 0;
-
     float width = m_glyphToWidthMap.metricsForGlyph(glyph);
     if (width != cGlyphSizeUnknown)
         return width;
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
index 700f3f9..c8a5a00 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
@@ -673,11 +673,6 @@
         if (isClusterEnd)
             spacing += adjustSpacing(run.get(), i, currentCharacterIndex, *directionOffset, totalAdvance);
 
-        if (currentFontData->isZeroWidthSpaceGlyph(glyph)) {
-            run->setGlyphAndPositions(i, glyph, 0, 0, 0);
-            continue;
-        }
-
         advance += spacing;
         if (m_textRun.rtl()) {
             // In RTL, spacing should be added to left side of glyphs.
diff --git a/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.cpp b/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.cpp
index c38264f..af5600f6 100644
--- a/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.cpp
@@ -34,11 +34,8 @@
 #include "platform/graphics/GraphicsContext.h"
 #include "platform/graphics/paint/PaintArtifactToSkCanvas.h"
 #include "platform/graphics/paint/PaintController.h"
-#include "platform/transforms/AffineTransform.h"
-#include "platform/transforms/TransformationMatrix.h"
 #include "public/platform/WebDisplayItemList.h"
-#include "public/platform/WebFloatRect.h"
-#include "third_party/skia/include/core/SkCanvas.h"
+#include "public/platform/WebRect.h"
 #include "third_party/skia/include/core/SkPicture.h"
 #include "ui/gfx/geometry/rect.h"
 
@@ -62,8 +59,7 @@
         // one big flat SkPicture.
         SkRect skBounds = SkRect::MakeXYWH(bounds.x(), bounds.y(), bounds.width(), bounds.height());
         RefPtr<SkPicture> picture = paintArtifactToSkPicture(artifact, skBounds);
-        // TODO(wkorman): Pass actual visual rect with the drawing item.
-        list->appendDrawingItem(IntRect(), picture.get());
+        list->appendDrawingItem(WebRect(bounds.x(), bounds.y(), bounds.width(), bounds.height()), picture.get());
         return;
     }
     artifact.appendToWebDisplayItemList(list);
diff --git a/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp b/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp
index 1470a16..afc8818 100644
--- a/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp
+++ b/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp
@@ -52,15 +52,7 @@
 {
     TRACE_EVENT0("blink", "DecodingImageGenerator::refEncodedData");
 
-    // FIXME: If the image has been clipped or scaled, do not return the original
-    // encoded data, since on playback it will not be known how the clipping/scaling
-    // was done.
-    RefPtr<SharedBuffer> buffer = nullptr;
-    bool allDataReceived = false;
-    m_frameGenerator->copyData(&buffer, &allDataReceived);
-    if (buffer && allDataReceived)
-        return SkData::NewWithCopy(buffer->data(), buffer->size());
-    return 0;
+    return m_frameGenerator->refEncodedData();
 }
 
 bool DecodingImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor table[], int* tableCount)
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
index 2ea8f29e..2cd05cf 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
@@ -1191,6 +1191,16 @@
     SkAnnotateLinkToDestination(m_canvas, rect, skDestName.get());
 }
 
+void GraphicsContext::setURLDestinationLocation(const String& name, const IntPoint& location)
+{
+    if (contextDisabled())
+        return;
+    ASSERT(m_canvas);
+
+    SkAutoDataUnref skName(SkData::NewWithCString(name.utf8().data()));
+    SkAnnotateNamedDestination(m_canvas, SkPoint::Make(location.x(), location.y()), skName);
+}
+
 void GraphicsContext::concatCTM(const AffineTransform& affine)
 {
     concat(affineTransformToSkMatrix(affine));
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsContext.h b/third_party/WebKit/Source/platform/graphics/GraphicsContext.h
index a93a129c..2ff1418e 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsContext.h
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsContext.h
@@ -249,10 +249,17 @@
 
     SkFilterQuality computeFilterQuality(Image*, const FloatRect& dest, const FloatRect& src) const;
 
-    // URL drawing
+    // Sets target URL of a clickable area.
     void setURLForRect(const KURL&, const IntRect&);
+
+    // Sets destination of a URL fragment (in a URL pointing to the same web page) of a clickable area.
+    // When the area is clicked, the page should be scrolled to the location set by setURLDestinationLocation()
+    // for the destination whose name equals the fragment.
     void setURLFragmentForRect(const String& name, const IntRect&);
 
+    // Sets location of a URL destination (a.k.a. anchor) in the page.
+    void setURLDestinationLocation(const String& name, const IntPoint&);
+
     static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle);
 
     static int focusRingOutsetExtent(int offset, int width)
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
index 5a0f8d4..cea4553 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
@@ -844,7 +844,7 @@
 #ifndef NDEBUG
     // The red debug fill needs to be invalidated if the layer resizes.
     if (m_paintController)
-        m_paintController->invalidateUntracked(displayItemClient());
+        m_paintController->invalidateUntracked(*this);
 #endif
 }
 
@@ -1045,7 +1045,7 @@
         m_linkHighlights[i]->invalidate();
 }
 
-void GraphicsLayer::invalidateDisplayItemClient(const DisplayItemClientWrapper& displayItemClient, PaintInvalidationReason paintInvalidationReason, const IntRect* visualRect)
+void GraphicsLayer::invalidateDisplayItemClient(const DisplayItemClient& displayItemClient, PaintInvalidationReason paintInvalidationReason, const IntRect* visualRect)
 {
     paintController()->invalidate(displayItemClient, paintInvalidationReason, visualRect);
     if (isTrackingPaintInvalidations())
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
index be7dd01..ee9f73e 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
@@ -75,7 +75,7 @@
 // GraphicsLayer is an abstraction for a rendering surface with backing store,
 // which may have associated transformation and animations.
 
-class PLATFORM_EXPORT GraphicsLayer : public GraphicsContextPainter, public WebCompositorAnimationDelegate, public WebLayerScrollClient, public cc::LayerClient {
+class PLATFORM_EXPORT GraphicsLayer : public GraphicsContextPainter, public WebCompositorAnimationDelegate, public WebLayerScrollClient, public cc::LayerClient, public DisplayItemClient {
     WTF_MAKE_NONCOPYABLE(GraphicsLayer); USING_FAST_MALLOC(GraphicsLayer);
 public:
     static PassOwnPtr<GraphicsLayer> create(GraphicsLayerFactory*, GraphicsLayerClient*);
@@ -193,7 +193,7 @@
     // If |visualRect| is not nullptr, it contains all pixels within the GraphicsLayer which might be painted into by
     // the display item client, in coordinate space of the GraphicsLayer.
     // |visualRect| can be nullptr if we know it's unchanged and PaintController has cached the previous value.
-    void invalidateDisplayItemClient(const DisplayItemClientWrapper&, PaintInvalidationReason, const IntRect* visualRect);
+    void invalidateDisplayItemClient(const DisplayItemClient&, PaintInvalidationReason, const IntRect* visualRect);
 
     // Set that the position/size of the contents (image or video).
     void setContentsRect(const IntRect&);
@@ -267,11 +267,11 @@
     static void setDrawDebugRedFillForTesting(bool);
     ContentLayerDelegate* contentLayerDelegateForTesting() const { return m_contentLayerDelegate.get(); }
 
-    DisplayItemClient displayItemClient() const { return toDisplayItemClient(this); }
-    String debugName() const { return m_client->debugName(this); }
+    String debugName() const final { return m_client->debugName(this); }
 
 protected:
     String debugName(cc::Layer*) const;
+    bool shouldFlattenTransform() const { return m_shouldFlattenTransform; }
 
     explicit GraphicsLayer(GraphicsLayerClient*);
     // GraphicsLayerFactoryChromium that wants to create a GraphicsLayer need to be friends.
@@ -279,6 +279,7 @@
     // for testing
     friend class CompositedLayerMappingTest;
     friend class FakeGraphicsLayerFactory;
+    friend class CompositedLayerMappingTest;
 
 private:
     // Adds a child without calling updateChildList(), so that adding children
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.h b/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
index 1fd37ba..41a0a95 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
+++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
@@ -35,7 +35,6 @@
 #include "platform/graphics/GraphicsTypes.h"
 #include "platform/graphics/GraphicsTypes3D.h"
 #include "platform/graphics/ImageBufferSurface.h"
-#include "platform/graphics/paint/DisplayItemClient.h"
 #include "platform/transforms/AffineTransform.h"
 #include "third_party/skia/include/core/SkPaint.h"
 #include "wtf/Forward.h"
@@ -130,9 +129,6 @@
     PassRefPtr<SkImage> newSkImageSnapshot(AccelerationHint) const;
     PassRefPtr<Image> newImageSnapshot(AccelerationHint = PreferNoAcceleration) const;
 
-    DisplayItemClient displayItemClient() const { return toDisplayItemClient(this); }
-    String debugName() const { return "ImageBuffer"; }
-
     void draw(GraphicsContext*, const FloatRect&, const FloatRect*, SkXfermode::Mode);
 
 private:
diff --git a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
index 0230e47..39a11f9 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
@@ -27,6 +27,7 @@
 
 #include "platform/graphics/ImageFrameGenerator.h"
 
+#include "SkData.h"
 #include "platform/SharedBuffer.h"
 #include "platform/TraceEvent.h"
 #include "platform/graphics/ImageDecodingStore.h"
@@ -101,30 +102,77 @@
 
 ImageFrameGenerator::ImageFrameGenerator(const SkISize& fullSize, PassRefPtr<SharedBuffer> data, bool allDataReceived, bool isMultiFrame)
     : m_fullSize(fullSize)
+    , m_data(adoptRef(new ThreadSafeDataTransport()))
     , m_isMultiFrame(isMultiFrame)
     , m_decodeFailedAndEmpty(false)
     , m_decodeCount(0)
     , m_frameCount(0)
+    , m_encodedData(nullptr)
 {
     setData(data.get(), allDataReceived);
 }
 
 ImageFrameGenerator::~ImageFrameGenerator()
 {
+    if (m_encodedData)
+        m_encodedData->unref();
     ImageDecodingStore::instance().removeCacheIndexedByGenerator(this);
 }
 
 void ImageFrameGenerator::setData(PassRefPtr<SharedBuffer> data, bool allDataReceived)
 {
-    m_data.setData(data.get(), allDataReceived);
+    m_data->setData(data.get(), allDataReceived);
 }
 
-void ImageFrameGenerator::copyData(RefPtr<SharedBuffer>* data, bool* allDataReceived)
+static void sharedSkDataReleaseCallback(const void* address, void* context)
 {
+    // This gets called when m_encodedData reference count becomes 0 - and it could happen in
+    // ImageFrameGenerator destructor or later when m_encodedData gets dereferenced.
+    // In this method, we deref ThreadSafeDataTransport, as ThreadSafeDataTransport is the owner
+    // of data returned via refEncodedData.
+
+    ThreadSafeDataTransport* dataTransport = static_cast<ThreadSafeDataTransport*>(context);
+#if ENABLE(ASSERT)
+    ASSERT(dataTransport);
     SharedBuffer* buffer = 0;
-    m_data.data(&buffer, allDataReceived);
-    if (buffer)
-        *data = buffer->copy();
+    bool allDataReceived = false;
+    dataTransport->data(&buffer, &allDataReceived);
+    ASSERT(allDataReceived && buffer && buffer->data() == address);
+#endif
+    // Dereference m_data now.
+    dataTransport->deref();
+}
+
+SkData* ImageFrameGenerator::refEncodedData()
+{
+    // SkData is returned only when full image (encoded) data is received. This is important
+    // since DeferredImageDecoder::setData is called only once with allDataReceived set to true,
+    // and after that m_data->m_readBuffer.data() is not changed. See also RELEASE_ASSERT used in
+    // ThreadSafeDataTransport::data().
+    SharedBuffer* buffer = 0;
+    bool allDataReceived = false;
+    m_data->data(&buffer, &allDataReceived);
+    if (!allDataReceived)
+        return nullptr;
+
+    {
+        // Prevents concurrent access to m_encodedData creation.
+        MutexLocker lock(m_decodeMutex);
+        if (m_encodedData) {
+            m_encodedData->ref();
+            return m_encodedData;
+        }
+        // m_encodedData is created with initial reference count == 1. ImageFrameGenerator always holds one
+        // reference to m_encodedData, as it prevents write access in SkData::writable_data.
+        m_encodedData = SkData::NewWithProc(buffer->data(), buffer->size(), sharedSkDataReleaseCallback, m_data.get());
+        // While m_encodedData is referenced, prevent disposing m_data and its content.
+        // it is dereferenced in sharedSkDataReleaseCallback, called when m_encodedData gets dereferenced.
+        m_data->ref();
+    }
+    // Increase the reference, caller must decrease it. One reference is always kept by ImageFrameGenerator and released
+    // in destructor.
+    m_encodedData->ref();
+    return m_encodedData;
 }
 
 bool ImageFrameGenerator::decodeAndScale(const SkImageInfo& info, size_t index, void* pixels, size_t rowBytes)
@@ -184,7 +232,7 @@
 
     SharedBuffer* data = 0;
     bool allDataReceived = false;
-    m_data.data(&data, &allDataReceived);
+    m_data->data(&data, &allDataReceived);
 
     // FIXME: YUV decoding does not currently support progressive decoding.
     ASSERT(allDataReceived);
@@ -290,7 +338,7 @@
     SharedBuffer* data = 0;
     bool allDataReceived = false;
     bool newDecoder = false;
-    m_data.data(&data, &allDataReceived);
+    m_data->data(&data, &allDataReceived);
 
     // Try to create an ImageDecoder if we are not given one.
     if (!*decoder) {
@@ -358,7 +406,7 @@
 
     SharedBuffer* data = 0;
     bool allDataReceived = false;
-    m_data.data(&data, &allDataReceived);
+    m_data->data(&data, &allDataReceived);
 
     // FIXME: YUV decoding does not currently support progressive decoding.
     if (!allDataReceived)
diff --git a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h
index 113ea88f..acf7b75 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h
+++ b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h
@@ -41,6 +41,8 @@
 #include "wtf/ThreadingPrimitives.h"
 #include "wtf/Vector.h"
 
+class SkData;
+
 namespace blink {
 
 class ImageDecoder;
@@ -75,8 +77,11 @@
 
     void setData(PassRefPtr<SharedBuffer>, bool allDataReceived);
 
-    // Creates a new SharedBuffer containing the data received so far.
-    void copyData(RefPtr<SharedBuffer>*, bool* allDataReceived);
+    // Return our encoded image data. Caller takes ownership and must unref the data
+    // according to the contract SkImageGenerator::refEncodedData.
+    //
+    // Returns null if image is not fully received.
+    SkData* refEncodedData();
 
     const SkISize& getFullSize() const { return m_fullSize; }
 
@@ -104,7 +109,11 @@
     bool decode(size_t index, ImageDecoder**, SkBitmap*);
 
     SkISize m_fullSize;
-    ThreadSafeDataTransport m_data;
+
+    // ThreadSafeDataTransport is referenced by this class and m_encodedData.
+    // In case that ImageFrameGenerator get's deleted before m_encodedData,
+    // m_encodedData would hold the reference to it (and underlying data).
+    RefPtr<ThreadSafeDataTransport> m_data;
     bool m_isMultiFrame;
     bool m_decodeFailedAndEmpty;
     Vector<bool> m_hasAlpha;
@@ -123,6 +132,9 @@
     // Protect concurrent access to m_hasAlpha.
     Mutex m_alphaMutex;
 
+    // Our encoded image data returned in refEncodedData.
+    SkData* m_encodedData;
+
 #if COMPILER(MSVC)
     friend struct ::WTF::OwnedPtrDeleter<ExternalMemoryAllocator>;
 #endif
diff --git a/third_party/WebKit/Source/platform/graphics/ImageFrameGeneratorTest.cpp b/third_party/WebKit/Source/platform/graphics/ImageFrameGeneratorTest.cpp
index e03e803..94c88b42 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageFrameGeneratorTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ImageFrameGeneratorTest.cpp
@@ -96,10 +96,10 @@
         m_generator->setImageDecoderFactory(MockImageDecoderFactory::create(this, fullSize()));
     }
 
-    void addNewData()
+    void addNewData(bool allDataReceived = false)
     {
         m_data->append("g", 1);
-        m_generator->setData(m_data, false);
+        m_generator->setData(m_data, allDataReceived);
     }
 
     void setFrameStatus(ImageFrame::Status status)  { m_status = m_nextFrameStatus = status; }
@@ -164,6 +164,15 @@
     generator->decodeAndScale(imageInfo(), 0, buffer, 100 * 4);
 }
 
+static void decodeThreadWithRefEncodedMain(ImageFrameGenerator* generator)
+{
+    // Image must be complete - refEncodedData otherwise returns null.
+    char buffer[100 * 100 * 4];
+    SkData* data = generator->refEncodedData();
+    generator->decodeAndScale(imageInfo(), 0, buffer, 100 * 4);
+    data->unref();
+}
+
 TEST_F(ImageFrameGeneratorTest, incompleteDecodeBecomesCompleteMultiThreaded)
 {
     setFrameStatus(ImageFrame::FramePartial);
@@ -172,10 +181,16 @@
     m_generator->decodeAndScale(imageInfo(), 0, buffer, 100 * 4);
     EXPECT_EQ(1, m_decodeRequestCount);
     EXPECT_EQ(0, m_decodersDestroyed);
+    SkData* data = m_generator->refEncodedData();
+    EXPECT_EQ(nullptr, data);
 
     // LocalFrame can now be decoded completely.
     setFrameStatus(ImageFrame::FrameComplete);
     addNewData();
+    // addNewData is calling m_generator->setData with allDataReceived == false, which means that
+    // refEncodedData should return null.
+    data = m_generator->refEncodedData();
+    EXPECT_EQ(nullptr, data);
     OwnPtr<WebThread> thread = adoptPtr(Platform::current()->createThread("DecodeThread"));
     thread->taskRunner()->postTask(BLINK_FROM_HERE, new Task(threadSafeBind(&decodeThreadMain, AllowCrossThreadAccess(m_generator.get()))));
     thread.clear();
@@ -185,6 +200,30 @@
     // Decoder created again.
     m_generator->decodeAndScale(imageInfo(), 0, buffer, 100 * 4);
     EXPECT_EQ(3, m_decodeRequestCount);
+
+    addNewData(true);
+    data = m_generator->refEncodedData();
+    ASSERT_TRUE(data);
+    // To prevent data writting, SkData::unique() should be false.
+    ASSERT_TRUE(!data->unique());
+
+    // Thread will also ref and unref the data.
+    thread = adoptPtr(Platform::current()->createThread("RefEncodedDataThread"));
+    thread->taskRunner()->postTask(BLINK_FROM_HERE, new Task(threadSafeBind(&decodeThreadWithRefEncodedMain, AllowCrossThreadAccess(m_generator.get()))));
+    thread.clear();
+    EXPECT_EQ(4, m_decodeRequestCount);
+
+    data->unref();
+    // m_generator is holding the only reference to SkData now.
+    ASSERT_TRUE(data->unique());
+
+    data = m_generator->refEncodedData();
+    ASSERT_TRUE(data && !data->unique());
+
+    // Delete generator, and SkData should have the only reference.
+    m_generator = nullptr;
+    ASSERT_TRUE(data->unique());
+    data->unref();
 }
 
 TEST_F(ImageFrameGeneratorTest, frameHasAlpha)
diff --git a/third_party/WebKit/Source/platform/graphics/ThreadSafeDataTransport.cpp b/third_party/WebKit/Source/platform/graphics/ThreadSafeDataTransport.cpp
index e047a0c..36bdece4 100644
--- a/third_party/WebKit/Source/platform/graphics/ThreadSafeDataTransport.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ThreadSafeDataTransport.cpp
@@ -54,6 +54,10 @@
     }
 
     MutexLocker locker(m_mutex);
+
+    // If all data was previously received, don't append more to it.
+    RELEASE_ASSERT(!(m_allDataReceived && newBufferQueue.size()));
+
     m_newBufferQueue.appendVector(newBufferQueue);
     newBufferQueue.clear();
     m_allDataReceived = allDataReceived;
diff --git a/third_party/WebKit/Source/platform/graphics/ThreadSafeDataTransport.h b/third_party/WebKit/Source/platform/graphics/ThreadSafeDataTransport.h
index 7c3ab37..3aae947 100644
--- a/third_party/WebKit/Source/platform/graphics/ThreadSafeDataTransport.h
+++ b/third_party/WebKit/Source/platform/graphics/ThreadSafeDataTransport.h
@@ -32,6 +32,7 @@
 #include "wtf/OwnPtr.h"
 #include "wtf/PassOwnPtr.h"
 #include "wtf/RefPtr.h"
+#include "wtf/ThreadSafeRefCounted.h"
 #include "wtf/ThreadingPrimitives.h"
 #include "wtf/Vector.h"
 
@@ -45,8 +46,8 @@
 //
 // This class is designed such that there is only one producer and
 // one consumer.
-class PLATFORM_EXPORT ThreadSafeDataTransport final {
-    DISALLOW_NEW();
+
+class PLATFORM_EXPORT ThreadSafeDataTransport final : public ThreadSafeRefCounted<ThreadSafeDataTransport> {
     WTF_MAKE_NONCOPYABLE(ThreadSafeDataTransport);
 public:
     ThreadSafeDataTransport();
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
new file mode 100644
index 0000000..dde06b2
--- /dev/null
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
@@ -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 "config.h"
+#include "platform/graphics/compositing/PaintArtifactCompositor.h"
+
+#include "cc/layers/layer.h"
+#include "cc/layers/layer_settings.h"
+#include "platform/RuntimeEnabledFeatures.h"
+#include "public/platform/Platform.h"
+#include "public/platform/WebCompositorSupport.h"
+#include "public/platform/WebLayer.h"
+#include "wtf/PassOwnPtr.h"
+
+namespace blink {
+
+PaintArtifactCompositor::PaintArtifactCompositor()
+{
+}
+
+PaintArtifactCompositor::~PaintArtifactCompositor()
+{
+}
+
+void PaintArtifactCompositor::initializeIfNeeded()
+{
+    ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
+    if (m_rootLayer)
+        return;
+
+    m_rootLayer = cc::Layer::Create(cc::LayerSettings());
+    m_webLayer = adoptPtr(Platform::current()->compositorSupport()->createLayerFromCCLayer(m_rootLayer.get()));
+}
+
+void PaintArtifactCompositor::update(const PaintArtifact& paintArtifact)
+{
+    initializeIfNeeded();
+    ASSERT(m_rootLayer);
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.h b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.h
new file mode 100644
index 0000000..6f6f0018
--- /dev/null
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.h
@@ -0,0 +1,58 @@
+// 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 PaintArtifactCompositor_h
+#define PaintArtifactCompositor_h
+
+#include "base/memory/ref_counted.h"
+#include "platform/PlatformExport.h"
+#include "wtf/Noncopyable.h"
+#include "wtf/OwnPtr.h"
+
+namespace cc {
+class Layer;
+}
+
+namespace blink {
+
+class PaintArtifact;
+class WebLayer;
+
+// Responsible for managing compositing in terms of a PaintArtifact.
+//
+// Owns a subtree of the compositor layer tree, and updates it in response to
+// changes in the paint artifact.
+//
+// PaintArtifactCompositor is the successor to PaintLayerCompositor, reflecting
+// the new home of compositing decisions after paint in Slimming Paint v2.
+class PLATFORM_EXPORT PaintArtifactCompositor {
+    WTF_MAKE_NONCOPYABLE(PaintArtifactCompositor);
+public:
+    PaintArtifactCompositor();
+    ~PaintArtifactCompositor();
+
+    // Creates at least a root layer to be managed by this controller. Can't be
+    // done in the constructor, since RuntimeEnabledFeatures may not be
+    // initialized yet.
+    void initializeIfNeeded();
+
+    // Updates the layer tree to match the provided paint artifact.
+    // Creates the root layer if not already done.
+    void update(const PaintArtifact&);
+
+    // The root layer of the tree managed by this object.
+    cc::Layer* rootLayer() const { return m_rootLayer.get(); }
+
+    // Wraps rootLayer(), so that it can be attached as a child of another
+    // WebLayer.
+    WebLayer* webLayer() const { return m_webLayer.get(); }
+
+private:
+    scoped_refptr<cc::Layer> m_rootLayer;
+    OwnPtr<WebLayer> m_webLayer;
+};
+
+} // namespace blink
+
+#endif // PaintArtifactCompositor_h
diff --git a/third_party/WebKit/Source/platform/graphics/paint/CachedDisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/CachedDisplayItem.h
index 34c4d1e..24b2888 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/CachedDisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/CachedDisplayItem.h
@@ -15,7 +15,7 @@
 // the cached DrawingDisplayItem/subtree when merging new paint list to cached paint list.
 class CachedDisplayItem final : public DisplayItem {
 public:
-    CachedDisplayItem(const DisplayItemClientWrapper& client, Type type)
+    CachedDisplayItem(const DisplayItemClient& client, Type type)
         : DisplayItem(client, type, sizeof(*this))
     {
         ASSERT(isCachedType(type));
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ClipDisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/ClipDisplayItem.h
index df1fef7..eede2c21 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ClipDisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/ClipDisplayItem.h
@@ -17,14 +17,14 @@
 
 class PLATFORM_EXPORT ClipDisplayItem final : public PairedBeginDisplayItem {
 public:
-    ClipDisplayItem(const DisplayItemClientWrapper& client, Type type, const IntRect& clipRect)
+    ClipDisplayItem(const DisplayItemClient& client, Type type, const IntRect& clipRect)
         : PairedBeginDisplayItem(client, type, sizeof(*this))
         , m_clipRect(clipRect)
     {
         ASSERT(isClipType(type));
     }
 
-    ClipDisplayItem(const DisplayItemClientWrapper& client, Type type, const IntRect& clipRect, Vector<FloatRoundedRect>& roundedRectClips)
+    ClipDisplayItem(const DisplayItemClient& client, Type type, const IntRect& clipRect, Vector<FloatRoundedRect>& roundedRectClips)
         : ClipDisplayItem(client, type, clipRect)
     {
         m_roundedRectClips.swap(roundedRectClips);
@@ -52,7 +52,7 @@
 
 class PLATFORM_EXPORT EndClipDisplayItem final : public PairedEndDisplayItem {
 public:
-    EndClipDisplayItem(const DisplayItemClientWrapper& client, Type type)
+    EndClipDisplayItem(const DisplayItemClient& client, Type type)
         : PairedEndDisplayItem(client, type, sizeof(*this))
     {
         ASSERT(isEndClipType(type));
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.h b/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.h
index 5c7d84d975..943de30 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.h
@@ -22,24 +22,24 @@
 class PLATFORM_EXPORT ClipPaintPropertyNode : public RefCounted<ClipPaintPropertyNode> {
 public:
     static PassRefPtr<ClipPaintPropertyNode> create(
-        PassRefPtr<TransformPaintPropertyNode> base,
+        PassRefPtr<TransformPaintPropertyNode> localTransformSpace,
         const FloatRoundedRect& clipRect,
         PassRefPtr<ClipPaintPropertyNode> parent = nullptr)
     {
-        return adoptRef(new ClipPaintPropertyNode(base, clipRect, parent));
+        return adoptRef(new ClipPaintPropertyNode(localTransformSpace, clipRect, parent));
     }
 
-    const TransformPaintPropertyNode* base() const { return m_base.get(); }
+    const TransformPaintPropertyNode* localTransformSpace() const { return m_localTransformSpace.get(); }
     const FloatRoundedRect& clipRect() const { return m_clipRect; }
 
     // Reference to inherited clips, or nullptr if this is the only clip.
     const ClipPaintPropertyNode* parent() const { return m_parent.get(); }
 
 private:
-    ClipPaintPropertyNode(PassRefPtr<TransformPaintPropertyNode> base, const FloatRoundedRect& clipRect, PassRefPtr<ClipPaintPropertyNode> parent)
-        : m_base(base), m_clipRect(clipRect), m_parent(parent) { }
+    ClipPaintPropertyNode(PassRefPtr<TransformPaintPropertyNode> localTransformSpace, const FloatRoundedRect& clipRect, PassRefPtr<ClipPaintPropertyNode> parent)
+        : m_localTransformSpace(localTransformSpace), m_clipRect(clipRect), m_parent(parent) { }
 
-    RefPtr<TransformPaintPropertyNode> m_base;
+    RefPtr<TransformPaintPropertyNode> m_localTransformSpace;
     const FloatRoundedRect m_clipRect;
     RefPtr<ClipPaintPropertyNode> m_parent;
 };
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ClipPathDisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/ClipPathDisplayItem.h
index 79df5b3..3455898 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ClipPathDisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/ClipPathDisplayItem.h
@@ -15,7 +15,7 @@
 
 class PLATFORM_EXPORT BeginClipPathDisplayItem final : public PairedBeginDisplayItem {
 public:
-    BeginClipPathDisplayItem(const DisplayItemClientWrapper& client, const Path& clipPath)
+    BeginClipPathDisplayItem(const DisplayItemClient& client, const Path& clipPath)
         : PairedBeginDisplayItem(client, BeginClipPath, sizeof(*this))
         , m_clipPath(clipPath.skPath()) { }
 
@@ -38,7 +38,7 @@
 
 class PLATFORM_EXPORT EndClipPathDisplayItem final : public PairedEndDisplayItem {
 public:
-    EndClipPathDisplayItem(const DisplayItemClientWrapper& client)
+    EndClipPathDisplayItem(const DisplayItemClient& client)
         : PairedEndDisplayItem(client, EndClipPath, sizeof(*this)) { }
 
     void replay(GraphicsContext&) const override;
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ClipPathRecorder.cpp b/third_party/WebKit/Source/platform/graphics/paint/ClipPathRecorder.cpp
index 419ee81..71f35b5 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ClipPathRecorder.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/ClipPathRecorder.cpp
@@ -11,7 +11,7 @@
 
 namespace blink {
 
-ClipPathRecorder::ClipPathRecorder(GraphicsContext& context, const DisplayItemClientWrapper& client, const Path& clipPath)
+ClipPathRecorder::ClipPathRecorder(GraphicsContext& context, const DisplayItemClient& client, const Path& clipPath)
     : m_context(context)
     , m_client(client)
 {
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ClipPathRecorder.h b/third_party/WebKit/Source/platform/graphics/paint/ClipPathRecorder.h
index 98e6a24..d9929c8 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ClipPathRecorder.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/ClipPathRecorder.h
@@ -18,12 +18,12 @@
     USING_FAST_MALLOC(ClipPathRecorder);
     WTF_MAKE_NONCOPYABLE(ClipPathRecorder);
 public:
-    ClipPathRecorder(GraphicsContext&, const DisplayItemClientWrapper&, const Path&);
+    ClipPathRecorder(GraphicsContext&, const DisplayItemClient&, const Path&);
     ~ClipPathRecorder();
 
 private:
     GraphicsContext& m_context;
-    DisplayItemClientWrapper m_client;
+    const DisplayItemClient& m_client;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ClipRecorder.cpp b/third_party/WebKit/Source/platform/graphics/paint/ClipRecorder.cpp
index 1aee77d..0aad9f2 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ClipRecorder.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/ClipRecorder.cpp
@@ -11,7 +11,7 @@
 
 namespace blink {
 
-ClipRecorder::ClipRecorder(GraphicsContext& context, const DisplayItemClientWrapper& client, DisplayItem::Type type, const LayoutRect& clipRect)
+ClipRecorder::ClipRecorder(GraphicsContext& context, const DisplayItemClient& client, DisplayItem::Type type, const LayoutRect& clipRect)
     : m_client(client)
     , m_context(context)
     , m_type(type)
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ClipRecorder.h b/third_party/WebKit/Source/platform/graphics/paint/ClipRecorder.h
index 2f2c8d5..4056783 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ClipRecorder.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/ClipRecorder.h
@@ -19,10 +19,10 @@
     DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
     WTF_MAKE_NONCOPYABLE(ClipRecorder);
 public:
-    ClipRecorder(GraphicsContext&, const DisplayItemClientWrapper&, DisplayItem::Type, const LayoutRect& clipRect);
+    ClipRecorder(GraphicsContext&, const DisplayItemClient&, DisplayItem::Type, const LayoutRect& clipRect);
     ~ClipRecorder();
 private:
-    DisplayItemClientWrapper m_client;
+    const DisplayItemClient& m_client;
     GraphicsContext& m_context;
     DisplayItem::Type m_type;
 };
diff --git a/third_party/WebKit/Source/platform/graphics/paint/CompositingDisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/CompositingDisplayItem.h
index 2763f8fe..1e444fc 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/CompositingDisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/CompositingDisplayItem.h
@@ -18,7 +18,7 @@
 
 class PLATFORM_EXPORT BeginCompositingDisplayItem final : public PairedBeginDisplayItem {
 public:
-    BeginCompositingDisplayItem(const DisplayItemClientWrapper& client, const SkXfermode::Mode xferMode, const float opacity, const FloatRect* bounds, ColorFilter colorFilter = ColorFilterNone)
+    BeginCompositingDisplayItem(const DisplayItemClient& client, const SkXfermode::Mode xferMode, const float opacity, const FloatRect* bounds, ColorFilter colorFilter = ColorFilterNone)
         : PairedBeginDisplayItem(client, BeginCompositing, sizeof(*this))
         , m_xferMode(xferMode)
         , m_opacity(opacity)
@@ -57,7 +57,7 @@
 
 class PLATFORM_EXPORT EndCompositingDisplayItem final : public PairedEndDisplayItem {
 public:
-    EndCompositingDisplayItem(const DisplayItemClientWrapper& client)
+    EndCompositingDisplayItem(const DisplayItemClient& client)
         : PairedEndDisplayItem(client, EndCompositing, sizeof(*this)) { }
 
     void replay(GraphicsContext&) const override;
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp
index d1574150..36883228 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp
@@ -83,6 +83,7 @@
         DEBUG_STRING_CASE(PopupListBoxBackground);
         DEBUG_STRING_CASE(PopupListBoxRow);
         DEBUG_STRING_CASE(PrintedContentBackground);
+        DEBUG_STRING_CASE(PrintedContentDestinationLocations);
         DEBUG_STRING_CASE(PrintedContentLineBoundary);
         DEBUG_STRING_CASE(PrintedContentPDFURLRect);
         DEBUG_STRING_CASE(Resizer);
@@ -223,7 +224,7 @@
         return;
     }
 
-    stringBuilder.append(String::format("client: \"%p", client()));
+    stringBuilder.append(String::format("client: \"%p", &client()));
     if (!clientDebugString().isEmpty()) {
         stringBuilder.append(' ');
         stringBuilder.append(clientDebugString());
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
index 632fa11..b1a913e 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
@@ -73,6 +73,7 @@
         PopupListBoxBackground,
         PopupListBoxRow,
         PrintedContentBackground,
+        PrintedContentDestinationLocations,
         PrintedContentLineBoundary,
         PrintedContentPDFURLRect,
         Resizer,
@@ -192,8 +193,8 @@
         TableCollapsedBorderLeft = 1 << 3,
     };
 
-    DisplayItem(const DisplayItemClientWrapper& client, Type type, size_t derivedSize)
-        : m_client(client.displayItemClient())
+    DisplayItem(const DisplayItemClient& client, Type type, size_t derivedSize)
+        : m_client(&client)
         , m_scope(0)
         , m_type(type)
         , m_derivedSize(derivedSize)
@@ -213,7 +214,7 @@
     // Ids are for matching new DisplayItems with existing DisplayItems.
     struct Id {
         STACK_ALLOCATED();
-        Id(const DisplayItemClient client, const Type type, const unsigned scope)
+        Id(const DisplayItemClient& client, const Type type, const unsigned scope)
             : client(client)
             , type(type)
             , scope(scope) { }
@@ -223,12 +224,12 @@
             // We should always convert to non-cached types before matching.
             ASSERT(!isCachedType(item.m_type));
             ASSERT(!isCachedType(type));
-            return client == item.m_client
+            return &client == item.m_client
                 && type == item.m_type
                 && scope == item.m_scope;
         }
 
-        const DisplayItemClient client;
+        const DisplayItemClient& client;
         const Type type;
         const unsigned scope;
     };
@@ -246,12 +247,12 @@
     // Return the Id with cached type converted to non-cached type.
     Id nonCachedId() const
     {
-        return Id(m_client, nonCachedType(m_type), m_scope);
+        return Id(*m_client, nonCachedType(m_type), m_scope);
     }
 
     virtual void replay(GraphicsContext&) const { }
 
-    DisplayItemClient client() const { return m_client; }
+    const DisplayItemClient& client() const { ASSERT(m_client); return *m_client; }
     Type type() const { return m_type; }
 
     void setScope(unsigned scope) { m_scope = scope; }
@@ -345,7 +346,7 @@
 
 #ifndef NDEBUG
     static WTF::String typeAsDebugString(DisplayItem::Type);
-    const WTF::String& clientDebugString() const { return m_clientDebugString; }
+    const WTF::String clientDebugString() const { return m_clientDebugString; }
     void setClientDebugString(const WTF::String& s) { m_clientDebugString = s; }
     WTF::String asDebugString() const;
     virtual void dumpPropertiesAsDebugString(WTF::StringBuilder&) const;
@@ -365,7 +366,7 @@
         , m_skippedCache(false)
     { }
 
-    const DisplayItemClient m_client;
+    const DisplayItemClient* m_client;
     unsigned m_scope;
     static_assert(TypeLast < (1 << 16), "DisplayItem::Type should fit in 16 bits");
     const Type m_type : 16;
@@ -379,7 +380,7 @@
 
 class PLATFORM_EXPORT PairedBeginDisplayItem : public DisplayItem {
 protected:
-    PairedBeginDisplayItem(const DisplayItemClientWrapper& client, Type type, size_t derivedSize) : DisplayItem(client, type, derivedSize) { }
+    PairedBeginDisplayItem(const DisplayItemClient& client, Type type, size_t derivedSize) : DisplayItem(client, type, derivedSize) { }
 
 private:
     bool isBegin() const final { return true; }
@@ -387,7 +388,7 @@
 
 class PLATFORM_EXPORT PairedEndDisplayItem : public DisplayItem {
 protected:
-    PairedEndDisplayItem(const DisplayItemClientWrapper& client, Type type, size_t derivedSize) : DisplayItem(client, type, derivedSize) { }
+    PairedEndDisplayItem(const DisplayItemClient& client, Type type, size_t derivedSize) : DisplayItem(client, type, derivedSize) { }
 
 #if ENABLE(ASSERT)
     bool isEndAndPairedWith(DisplayItem::Type otherType) const override = 0;
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemClient.h b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemClient.h
index 32f312e8..eb2bc41 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemClient.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemClient.h
@@ -6,52 +6,21 @@
 #define DisplayItemClient_h
 
 #include "platform/PlatformExport.h"
-#include "platform/heap/Heap.h"
 #include "wtf/text/WTFString.h"
 
 namespace blink {
 
-class DisplayItemClientInternalVoid;
-using DisplayItemClient = const DisplayItemClientInternalVoid*;
-
-inline DisplayItemClient toDisplayItemClient(const void* object) { return static_cast<DisplayItemClient>(object); }
-
-// Used to pass DisplayItemClient and debugName() (called only when needed) from
-// core/layout module etc. to platform/paint module.
-// The instance must not out-live the object. Long-time reference to a client must
-// use DisplayItemClient.
-class PLATFORM_EXPORT DisplayItemClientWrapper final {
-    DISALLOW_NEW(); // Allow allocated in stack or in another object only.
+// The interface for objects that can be associated with display items.
+class PLATFORM_EXPORT DisplayItemClient {
 public:
-    template <typename T>
-    DisplayItemClientWrapper(const T& object)
-        : m_displayItemClient(object.displayItemClient())
-        , m_object(reinterpret_cast<const GenericClass&>(object))
-        , m_debugNameInvoker(&invokeDebugName<T>)
-    { }
+    virtual ~DisplayItemClient() { }
 
-    DisplayItemClientWrapper(const DisplayItemClientWrapper& other)
-        : m_displayItemClient(other.m_displayItemClient)
-        , m_object(other.m_object)
-        , m_debugNameInvoker(other.m_debugNameInvoker)
-    { }
-
-    DisplayItemClient displayItemClient() const { return m_displayItemClient; }
-    String debugName() const { return m_debugNameInvoker(m_object); }
-
-private:
-    DisplayItemClientWrapper& operator=(const DisplayItemClientWrapper&) = delete;
-
-    class GenericClass;
-    template <typename T>
-    static String invokeDebugName(const GenericClass& object) { return reinterpret_cast<const T&>(object).debugName(); }
-
-    DisplayItemClient m_displayItemClient;
-    const GenericClass& m_object;
-    using DebugNameInvoker = String(*)(const GenericClass&);
-    DebugNameInvoker m_debugNameInvoker;
+    virtual String debugName() const = 0;
 };
 
+inline bool operator==(const DisplayItemClient& client1, const DisplayItemClient& client2) { return &client1 == &client2; }
+inline bool operator!=(const DisplayItemClient& client1, const DisplayItemClient& client2) { return &client1 != &client2; }
+
 }
 
 #endif // DisplayItemClient_h
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DrawingDisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/DrawingDisplayItem.h
index d5e535de..a2a9c1d 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DrawingDisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/DrawingDisplayItem.h
@@ -22,7 +22,7 @@
     };
 #endif
 
-    DrawingDisplayItem(const DisplayItemClientWrapper& client
+    DrawingDisplayItem(const DisplayItemClient& client
         , Type type
         , PassRefPtr<const SkPicture> picture
 #if ENABLE(ASSERT)
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.cpp b/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.cpp
index 0228a66..f74205e 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.cpp
@@ -14,11 +14,11 @@
 
 namespace blink {
 
-bool DrawingRecorder::useCachedDrawingIfPossible(GraphicsContext& context, const DisplayItemClientWrapper& client, DisplayItem::Type type)
+bool DrawingRecorder::useCachedDrawingIfPossible(GraphicsContext& context, const DisplayItemClient& client, DisplayItem::Type type)
 {
     ASSERT(DisplayItem::isDrawingType(type));
 
-    if (!context.paintController().clientCacheIsValid(client.displayItemClient()))
+    if (!context.paintController().clientCacheIsValid(client))
         return false;
 
     context.paintController().createAndAppend<CachedDisplayItem>(client, DisplayItem::drawingTypeToCachedDrawingType(type));
@@ -33,7 +33,7 @@
     return true;
 }
 
-DrawingRecorder::DrawingRecorder(GraphicsContext& context, const DisplayItemClientWrapper& displayItemClient, DisplayItem::Type displayItemType, const FloatRect& cullRect)
+DrawingRecorder::DrawingRecorder(GraphicsContext& context, const DisplayItemClient& displayItemClient, DisplayItem::Type displayItemType, const FloatRect& cullRect)
     : m_context(context)
     , m_displayItemClient(displayItemClient)
     , m_displayItemType(displayItemType)
@@ -46,7 +46,7 @@
         return;
 
     // Must check DrawingRecorder::useCachedDrawingIfPossible before creating the DrawingRecorder.
-    ASSERT((RuntimeEnabledFeatures::slimmingPaintOffsetCachingEnabled() && context.paintController().paintOffsetWasInvalidated(displayItemClient.displayItemClient()))
+    ASSERT((RuntimeEnabledFeatures::slimmingPaintOffsetCachingEnabled() && context.paintController().paintOffsetWasInvalidated(displayItemClient))
         || RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled()
         || !useCachedDrawingIfPossible(m_context, m_displayItemClient, m_displayItemType));
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.h b/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.h
index ae4b93e..c8e45e6 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.h
@@ -24,9 +24,9 @@
     DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
     WTF_MAKE_NONCOPYABLE(DrawingRecorder);
 public:
-    static bool useCachedDrawingIfPossible(GraphicsContext&, const DisplayItemClientWrapper&, DisplayItem::Type);
+    static bool useCachedDrawingIfPossible(GraphicsContext&, const DisplayItemClient&, DisplayItem::Type);
 
-    DrawingRecorder(GraphicsContext&, const DisplayItemClientWrapper&, DisplayItem::Type, const FloatRect& cullRect);
+    DrawingRecorder(GraphicsContext&, const DisplayItemClient&, DisplayItem::Type, const FloatRect& cullRect);
     ~DrawingRecorder();
 
 #if ENABLE(ASSERT)
@@ -35,7 +35,7 @@
 
 private:
     GraphicsContext& m_context;
-    DisplayItemClientWrapper m_displayItemClient;
+    const DisplayItemClient& m_displayItemClient;
     const DisplayItem::Type m_displayItemType;
 #if ENABLE(ASSERT)
     size_t m_displayItemPosition;
diff --git a/third_party/WebKit/Source/platform/graphics/paint/FilterDisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/FilterDisplayItem.h
index dd95a2d..9d4ce95 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/FilterDisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/FilterDisplayItem.h
@@ -18,7 +18,7 @@
 
 class PLATFORM_EXPORT BeginFilterDisplayItem final : public PairedBeginDisplayItem {
 public:
-    BeginFilterDisplayItem(const DisplayItemClientWrapper& client, PassRefPtr<SkImageFilter> imageFilter, const FloatRect& bounds, PassOwnPtr<WebFilterOperations> filterOperations = nullptr)
+    BeginFilterDisplayItem(const DisplayItemClient& client, PassRefPtr<SkImageFilter> imageFilter, const FloatRect& bounds, PassOwnPtr<WebFilterOperations> filterOperations = nullptr)
         : PairedBeginDisplayItem(client, BeginFilter, sizeof(*this))
         , m_imageFilter(imageFilter)
         , m_webFilterOperations(filterOperations)
@@ -49,7 +49,7 @@
 
 class PLATFORM_EXPORT EndFilterDisplayItem final : public PairedEndDisplayItem {
 public:
-    EndFilterDisplayItem(const DisplayItemClientWrapper& client)
+    EndFilterDisplayItem(const DisplayItemClient& client)
         : PairedEndDisplayItem(client, EndFilter, sizeof(*this)) { }
 
     void replay(GraphicsContext&) const override;
diff --git a/third_party/WebKit/Source/platform/graphics/paint/FixedPositionContainerDisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/FixedPositionContainerDisplayItem.h
index 73e2b10..92248eb 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/FixedPositionContainerDisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/FixedPositionContainerDisplayItem.h
@@ -13,7 +13,7 @@
 
 class PLATFORM_EXPORT BeginFixedPositionContainerDisplayItem final : public PairedBeginDisplayItem {
 public:
-    BeginFixedPositionContainerDisplayItem(const DisplayItemClientWrapper& client)
+    BeginFixedPositionContainerDisplayItem(const DisplayItemClient& client)
         : PairedBeginDisplayItem(client, BeginFixedPositionContainer, sizeof(*this)) { }
 
     void replay(GraphicsContext&) const final { }
@@ -22,7 +22,7 @@
 
 class PLATFORM_EXPORT EndFixedPositionContainerDisplayItem final : public PairedEndDisplayItem {
 public:
-    EndFixedPositionContainerDisplayItem(const DisplayItemClientWrapper& client)
+    EndFixedPositionContainerDisplayItem(const DisplayItemClient& client)
         : PairedEndDisplayItem(client, EndFixedPositionContainer, sizeof(*this)) { }
 
     void replay(GraphicsContext&) const final { }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/FixedPositionDisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/FixedPositionDisplayItem.h
index cf5197c..c4f0d0a 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/FixedPositionDisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/FixedPositionDisplayItem.h
@@ -13,7 +13,7 @@
 
 class PLATFORM_EXPORT BeginFixedPositionDisplayItem final : public PairedBeginDisplayItem {
 public:
-    BeginFixedPositionDisplayItem(const DisplayItemClientWrapper& client)
+    BeginFixedPositionDisplayItem(const DisplayItemClient& client)
         : PairedBeginDisplayItem(client, BeginFixedPosition, sizeof(*this)) { }
 
     void replay(GraphicsContext&) const final { }
@@ -22,7 +22,7 @@
 
 class PLATFORM_EXPORT EndFixedPositionDisplayItem final : public PairedEndDisplayItem {
 public:
-    EndFixedPositionDisplayItem(const DisplayItemClientWrapper& client)
+    EndFixedPositionDisplayItem(const DisplayItemClient& client)
         : PairedEndDisplayItem(client, EndFixedPosition, sizeof(*this)) { }
 
     void replay(GraphicsContext&) const final { }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/FloatClipDisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/FloatClipDisplayItem.h
index 536f30c0..e9cac36 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/FloatClipDisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/FloatClipDisplayItem.h
@@ -16,7 +16,7 @@
 
 class PLATFORM_EXPORT FloatClipDisplayItem final : public PairedBeginDisplayItem {
 public:
-    FloatClipDisplayItem(const DisplayItemClientWrapper& client, Type type, const FloatRect& clipRect)
+    FloatClipDisplayItem(const DisplayItemClient& client, Type type, const FloatRect& clipRect)
         : PairedBeginDisplayItem(client, type, sizeof(*this))
         , m_clipRect(clipRect)
     {
@@ -43,7 +43,7 @@
 
 class PLATFORM_EXPORT EndFloatClipDisplayItem final : public PairedEndDisplayItem {
 public:
-    EndFloatClipDisplayItem(const DisplayItemClientWrapper& client, Type type)
+    EndFloatClipDisplayItem(const DisplayItemClient& client, Type type)
         : PairedEndDisplayItem(client, type, sizeof(*this))
     {
         ASSERT(isEndFloatClipType(type));
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifactToSkCanvas.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifactToSkCanvas.cpp
index adcdb3d..292cc66 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifactToSkCanvas.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifactToSkCanvas.cpp
@@ -115,7 +115,7 @@
         // Setup the canvas clip state first because it clobbers matrix state.
         for (const ClipPaintPropertyNode* currentClipNode = chunk.properties.clip.get();
             currentClipNode; currentClipNode = currentClipNode->parent()) {
-            canvas->setMatrix(TransformationMatrix::toSkMatrix44(totalTransform(currentClipNode->base())));
+            canvas->setMatrix(TransformationMatrix::toSkMatrix44(totalTransform(currentClipNode->localTransformSpace())));
             canvas->clipRRect(currentClipNode->clipRect());
         }
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifactToSkCanvasTest.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifactToSkCanvasTest.cpp
index a1c29e1..e4753e1 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifactToSkCanvasTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifactToSkCanvasTest.cpp
@@ -61,14 +61,13 @@
     }
 };
 
-class DummyRectClient {
+class DummyRectClient : public DisplayItemClient {
 public:
     DummyRectClient(const SkRect& rect, SkColor color) : m_rect(rect), m_color(color) {}
     const SkRect& rect() const { return m_rect; }
     SkColor color() const { return m_color; }
     PassRefPtr<SkPicture> makePicture() const { return pictureWithRect(m_rect, m_color); }
-    DisplayItemClient displayItemClient() const { return toDisplayItemClient(this); }
-    String debugName() const { return "<dummy>"; }
+    String debugName() const final { return "<dummy>"; }
 
 private:
     SkRect m_rect;
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
index 6f06a7f0..7ff41d8 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
@@ -41,7 +41,7 @@
 
 #if ENABLE(ASSERT)
     // Also remove the index pointing to the removed display item.
-    DisplayItemIndicesByClientMap::iterator it = m_newDisplayItemIndicesByClient.find(m_newDisplayItemList.last().client());
+    DisplayItemIndicesByClientMap::iterator it = m_newDisplayItemIndicesByClient.find(&m_newDisplayItemList.last().client());
     if (it != m_newDisplayItemIndicesByClient.end()) {
         Vector<size_t>& indices = it->value;
         if (!indices.isEmpty() && indices.last() == (m_newDisplayItemList.size() - 1))
@@ -117,7 +117,7 @@
     endSkippingCache();
 }
 
-void PaintController::invalidate(const DisplayItemClientWrapper& client, PaintInvalidationReason paintInvalidationReason, const IntRect* visualRect)
+void PaintController::invalidate(const DisplayItemClient& client, PaintInvalidationReason paintInvalidationReason, const IntRect* visualRect)
 {
     invalidateClient(client);
 
@@ -126,25 +126,25 @@
     }
 }
 
-void PaintController::invalidateClient(const DisplayItemClientWrapper& client)
+void PaintController::invalidateClient(const DisplayItemClient& client)
 {
 #if ENABLE(ASSERT)
     // Slimming paint v1 CompositedLayerMapping may invalidate client on extra layers.
-    if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() || clientCacheIsValid(client.displayItemClient()))
+    if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() || clientCacheIsValid(client))
         m_invalidations.append(client.debugName());
 #endif
 
-    invalidateUntracked(client.displayItemClient());
+    invalidateUntracked(client);
     if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() && m_trackedPaintInvalidationObjects)
         m_trackedPaintInvalidationObjects->append(client.debugName());
 }
 
-void PaintController::invalidateUntracked(DisplayItemClient client)
+void PaintController::invalidateUntracked(const DisplayItemClient& client)
 {
     // This can be called during painting, but we can't invalidate already painted clients.
-    ASSERT(!m_newDisplayItemIndicesByClient.contains(client));
+    ASSERT(!m_newDisplayItemIndicesByClient.contains(&client));
     updateValidlyCachedClientsIfNeeded();
-    m_validlyCachedClients.remove(client);
+    m_validlyCachedClients.remove(&client);
 }
 
 void PaintController::invalidateAll()
@@ -159,36 +159,36 @@
         m_trackedPaintInvalidationObjects->append("##ALL##");
 }
 
-bool PaintController::clientCacheIsValid(DisplayItemClient client) const
+bool PaintController::clientCacheIsValid(const DisplayItemClient& client) const
 {
     if (skippingCache())
         return false;
     updateValidlyCachedClientsIfNeeded();
-    return m_validlyCachedClients.contains(client);
+    return m_validlyCachedClients.contains(&client);
 }
 
-void PaintController::invalidatePaintOffset(const DisplayItemClientWrapper& client)
+void PaintController::invalidatePaintOffset(const DisplayItemClient& client)
 {
     ASSERT(RuntimeEnabledFeatures::slimmingPaintOffsetCachingEnabled());
     invalidateClient(client);
 
 #if ENABLE(ASSERT)
-    ASSERT(!paintOffsetWasInvalidated(client.displayItemClient()));
-    m_clientsWithPaintOffsetInvalidations.add(client.displayItemClient());
+    ASSERT(!paintOffsetWasInvalidated(client));
+    m_clientsWithPaintOffsetInvalidations.add(&client);
 #endif
 }
 
 #if ENABLE(ASSERT)
-bool PaintController::paintOffsetWasInvalidated(DisplayItemClient client) const
+bool PaintController::paintOffsetWasInvalidated(const DisplayItemClient& client) const
 {
     ASSERT(RuntimeEnabledFeatures::slimmingPaintOffsetCachingEnabled());
-    return m_clientsWithPaintOffsetInvalidations.contains(client);
+    return m_clientsWithPaintOffsetInvalidations.contains(&client);
 }
 #endif
 
 size_t PaintController::findMatchingItemFromIndex(const DisplayItem::Id& id, const DisplayItemIndicesByClientMap& displayItemIndicesByClient, const DisplayItemList& list)
 {
-    DisplayItemIndicesByClientMap::const_iterator it = displayItemIndicesByClient.find(id.client);
+    DisplayItemIndicesByClientMap::const_iterator it = displayItemIndicesByClient.find(&id.client);
     if (it == displayItemIndicesByClient.end())
         return kNotFound;
 
@@ -208,9 +208,9 @@
     if (!displayItem.isCacheable())
         return;
 
-    DisplayItemIndicesByClientMap::iterator it = displayItemIndicesByClient.find(displayItem.client());
+    DisplayItemIndicesByClientMap::iterator it = displayItemIndicesByClient.find(&displayItem.client());
     Vector<size_t>& indices = it == displayItemIndicesByClient.end() ?
-        displayItemIndicesByClient.add(displayItem.client(), Vector<size_t>()).storedValue->value : it->value;
+        displayItemIndicesByClient.add(&displayItem.client(), Vector<size_t>()).storedValue->value : it->value;
     indices.append(index);
 }
 
@@ -435,12 +435,12 @@
     m_validlyCachedClients.clear();
     m_validlyCachedClientsDirty = false;
 
-    DisplayItemClient lastAddedClient = nullptr;
+    const DisplayItemClient* lastAddedClient = nullptr;
     for (const DisplayItem& displayItem : m_currentPaintArtifact.displayItemList()) {
-        if (displayItem.client() == lastAddedClient)
+        if (&displayItem.client() == lastAddedClient)
             continue;
         if (displayItem.isCacheable()) {
-            lastAddedClient = displayItem.client();
+            lastAddedClient = &displayItem.client();
             m_validlyCachedClients.add(lastAddedClient);
         }
     }
@@ -509,7 +509,7 @@
         ASSERT_NOT_REACHED();
     }
 
-    if (newItem.isCacheable() && !m_validlyCachedClients.contains(newItem.client())) {
+    if (newItem.isCacheable() && !m_validlyCachedClients.contains(&newItem.client())) {
         showUnderInvalidationError(messagePrefix, "ERROR: under-invalidation: invalidated in cached subsequence", &newItem, &oldItem);
         ASSERT_NOT_REACHED();
     }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.h b/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
index b62d539..ad3fb8d 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
@@ -19,6 +19,7 @@
 #include "platform/graphics/paint/Transform3DDisplayItem.h"
 #include "wtf/Alignment.h"
 #include "wtf/HashMap.h"
+#include "wtf/HashSet.h"
 #include "wtf/PassOwnPtr.h"
 #include "wtf/Utility.h"
 #include "wtf/Vector.h"
@@ -47,14 +48,14 @@
     // which might be painted into by the display item client, in coordinate space of the GraphicsLayer.
     // TODO(pdr): define it for spv2.
     // |visualRect| can be nullptr if we know it's unchanged and PaintController has cached the previous value.
-    void invalidate(const DisplayItemClientWrapper&, PaintInvalidationReason, const IntRect* visualRect);
-    void invalidateUntracked(DisplayItemClient);
+    void invalidate(const DisplayItemClient&, PaintInvalidationReason, const IntRect* visualRect);
+    void invalidateUntracked(const DisplayItemClient&);
     void invalidateAll();
 
     // Record when paint offsets change during paint.
-    void invalidatePaintOffset(const DisplayItemClientWrapper&);
+    void invalidatePaintOffset(const DisplayItemClient&);
 #if ENABLE(ASSERT)
-    bool paintOffsetWasInvalidated(DisplayItemClient) const;
+    bool paintOffsetWasInvalidated(const DisplayItemClient&) const;
 #endif
 
     // These methods are called during painting.
@@ -123,7 +124,7 @@
     const DisplayItemList& displayItemList() const { return paintArtifact().displayItemList(); }
     const Vector<PaintChunk>& paintChunks() const { return paintArtifact().paintChunks(); }
 
-    bool clientCacheIsValid(DisplayItemClient) const;
+    bool clientCacheIsValid(const DisplayItemClient&) const;
     bool cacheIsEmpty() const { return m_currentPaintArtifact.isEmpty(); }
 
     bool displayItemConstructionIsDisabled() const { return m_constructionDisabled; }
@@ -158,15 +159,15 @@
         return m_trackedPaintInvalidationObjects ? *m_trackedPaintInvalidationObjects : Vector<String>();
     }
 
-    bool clientHasCheckedPaintInvalidation(DisplayItemClient client) const
+    bool clientHasCheckedPaintInvalidation(const DisplayItemClient& client) const
     {
         ASSERT(RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled());
-        return m_clientsCheckedPaintInvalidation.contains(client);
+        return m_clientsCheckedPaintInvalidation.contains(&client);
     }
-    void setClientHasCheckedPaintInvalidation(DisplayItemClient client)
+    void setClientHasCheckedPaintInvalidation(const DisplayItemClient& client)
     {
         ASSERT(RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled());
-        m_clientsCheckedPaintInvalidation.add(client);
+        m_clientsCheckedPaintInvalidation.add(&client);
     }
 
 protected:
@@ -186,7 +187,7 @@
 
     void updateValidlyCachedClientsIfNeeded() const;
 
-    void invalidateClient(const DisplayItemClientWrapper&);
+    void invalidateClient(const DisplayItemClient&);
 
 #ifndef NDEBUG
     WTF::String displayItemListAsDebugString(const DisplayItemList&) const;
@@ -194,7 +195,7 @@
 
     // Indices into PaintList of all DrawingDisplayItems and BeginSubsequenceDisplayItems of each client.
     // Temporarily used during merge to find out-of-order display items.
-    using DisplayItemIndicesByClientMap = HashMap<DisplayItemClient, Vector<size_t>>;
+    using DisplayItemIndicesByClientMap = HashMap<const DisplayItemClient*, Vector<size_t>>;
 
     static size_t findMatchingItemFromIndex(const DisplayItem::Id&, const DisplayItemIndicesByClientMap&, const DisplayItemList&);
     static void addItemToIndexIfNeeded(const DisplayItem&, size_t index, DisplayItemIndicesByClientMap&);
@@ -224,18 +225,18 @@
     // It's lazily updated in updateValidlyCachedClientsIfNeeded().
     // TODO(wangxianzhu): In the future we can replace this with client-side repaint flags
     // to avoid the cost of building and querying the hash table.
-    mutable HashSet<DisplayItemClient> m_validlyCachedClients;
+    mutable HashSet<const DisplayItemClient*> m_validlyCachedClients;
     mutable bool m_validlyCachedClientsDirty;
 
     // Used during painting. Contains clients that have checked paint invalidation and
     // are known to be valid.
     // TODO(wangxianzhu): Use client side flag to avoid const of hash table.
-    HashSet<DisplayItemClient> m_clientsCheckedPaintInvalidation;
+    HashSet<const DisplayItemClient*> m_clientsCheckedPaintInvalidation;
 
 #if ENABLE(ASSERT)
     // Set of clients which had paint offset changes since the last commit. This is used for
     // ensuring paint offsets are only updated once and are the same in all phases.
-    HashSet<DisplayItemClient> m_clientsWithPaintOffsetInvalidations;
+    HashSet<const DisplayItemClient*> m_clientsWithPaintOffsetInvalidations;
 #endif
 
     // Allow display item construction to be disabled to isolate the costs of construction
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp
index ecd9e62d..c375021 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp
@@ -43,14 +43,13 @@
 const DisplayItem::Type backgroundDrawingType = DisplayItem::DrawingPaintPhaseFirst;
 const DisplayItem::Type clipType = DisplayItem::ClipFirst;
 
-class TestDisplayItemClient {
+class TestDisplayItemClient : public DisplayItemClient {
 public:
     TestDisplayItemClient(const String& name)
         : m_name(name)
     { }
 
-    DisplayItemClient displayItemClient() const { return toDisplayItemClient(this); }
-    String debugName() const { return m_name; }
+    String debugName() const final { return m_name; }
 
 private:
     String m_name;
@@ -370,14 +369,14 @@
     EXPECT_DISPLAY_LIST(paintController().displayItemList(), 2,
         TestDisplayItem(first, backgroundDrawingType),
         TestDisplayItem(second, backgroundDrawingType));
-    EXPECT_TRUE(paintController().clientCacheIsValid(first.displayItemClient()));
-    EXPECT_TRUE(paintController().clientCacheIsValid(second.displayItemClient()));
+    EXPECT_TRUE(paintController().clientCacheIsValid(first));
+    EXPECT_TRUE(paintController().clientCacheIsValid(second));
     const SkPicture* firstPicture = static_cast<const DrawingDisplayItem&>(paintController().displayItemList()[0]).picture();
     const SkPicture* secondPicture = static_cast<const DrawingDisplayItem&>(paintController().displayItemList()[1]).picture();
 
     paintController().invalidate(first, PaintInvalidationFull, nullptr);
-    EXPECT_FALSE(paintController().clientCacheIsValid(first.displayItemClient()));
-    EXPECT_TRUE(paintController().clientCacheIsValid(second.displayItemClient()));
+    EXPECT_FALSE(paintController().clientCacheIsValid(first));
+    EXPECT_TRUE(paintController().clientCacheIsValid(second));
 
     drawRect(context, first, backgroundDrawingType, FloatRect(100, 100, 150, 150));
     drawRect(context, second, backgroundDrawingType, FloatRect(100, 100, 150, 150));
@@ -390,12 +389,12 @@
     EXPECT_NE(firstPicture, static_cast<const DrawingDisplayItem&>(paintController().displayItemList()[0]).picture());
     // The second display item should be cached.
     EXPECT_EQ(secondPicture, static_cast<const DrawingDisplayItem&>(paintController().displayItemList()[1]).picture());
-    EXPECT_TRUE(paintController().clientCacheIsValid(first.displayItemClient()));
-    EXPECT_TRUE(paintController().clientCacheIsValid(second.displayItemClient()));
+    EXPECT_TRUE(paintController().clientCacheIsValid(first));
+    EXPECT_TRUE(paintController().clientCacheIsValid(second));
 
     paintController().invalidateAll();
-    EXPECT_FALSE(paintController().clientCacheIsValid(first.displayItemClient()));
-    EXPECT_FALSE(paintController().clientCacheIsValid(second.displayItemClient()));
+    EXPECT_FALSE(paintController().clientCacheIsValid(first));
+    EXPECT_FALSE(paintController().clientCacheIsValid(second));
 }
 
 TEST_F(PaintControllerTest, ComplexUpdateSwapOrder)
@@ -666,7 +665,7 @@
     EXPECT_NE(picture1, picture2);
 
     // Draw again with nothing invalidated.
-    EXPECT_TRUE(paintController().clientCacheIsValid(multicol.displayItemClient()));
+    EXPECT_TRUE(paintController().clientCacheIsValid(multicol));
     drawRect(context, multicol, backgroundDrawingType, FloatRect(100, 200, 100, 100));
     paintController().beginScope();
     drawRect(context, content, foregroundDrawingType, rect1);
diff --git a/third_party/WebKit/Source/platform/graphics/paint/README.md b/third_party/WebKit/Source/platform/graphics/paint/README.md
index f637743f..b36d412 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/README.md
+++ b/third_party/WebKit/Source/platform/graphics/paint/README.md
@@ -70,6 +70,21 @@
 TODO(jbroman): Explain flattening, etc., once it exists in the paint properties.
 ***
 
+### Clips
+
+Each paint chunk is associated with a [clip node](ClipPaintPropertyNode.h),
+which defines the raster region that will be applied on the canvas when
+the chunk is rastered.
+
+Each clip node has:
+
+* A float rect with (optionally) rounded corner radius.
+* An associated transform node, which the clip rect is based on.
+
+The raster region defined by a node is the rounded rect transformed to the
+root space, intersects with the raster region defined by its parent clip node
+(if not root).
+
 ### Effects
 
 Each paint chunk is associated with an [effect node](EffectPaintPropertyNode.h),
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ScrollDisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/ScrollDisplayItem.cpp
index 54de302..8bbd095 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ScrollDisplayItem.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/ScrollDisplayItem.cpp
@@ -19,7 +19,7 @@
 
 void BeginScrollDisplayItem::appendToWebDisplayItemList(const IntRect& visualRect, WebDisplayItemList* list) const
 {
-    WebDisplayItemList::ScrollContainerId scrollContainerId = client();
+    WebDisplayItemList::ScrollContainerId scrollContainerId = &client();
     list->appendScrollItem(visualRect, m_currentOffset, scrollContainerId);
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ScrollDisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/ScrollDisplayItem.h
index d3b2b081..73ca8c1 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ScrollDisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/ScrollDisplayItem.h
@@ -14,7 +14,7 @@
 
 class PLATFORM_EXPORT BeginScrollDisplayItem final : public PairedBeginDisplayItem {
 public:
-    BeginScrollDisplayItem(const DisplayItemClientWrapper& client, Type type, const IntSize& currentOffset)
+    BeginScrollDisplayItem(const DisplayItemClient& client, Type type, const IntSize& currentOffset)
         : PairedBeginDisplayItem(client, type, sizeof(*this))
         , m_currentOffset(currentOffset)
     {
@@ -43,7 +43,7 @@
 
 class PLATFORM_EXPORT EndScrollDisplayItem final : public PairedEndDisplayItem {
 public:
-    EndScrollDisplayItem(const DisplayItemClientWrapper& client, Type type)
+    EndScrollDisplayItem(const DisplayItemClient& client, Type type)
         : PairedEndDisplayItem(client, type, sizeof(*this))
     {
         ASSERT(isEndScrollType(type));
diff --git a/third_party/WebKit/Source/platform/graphics/paint/SkPictureBuilder.h b/third_party/WebKit/Source/platform/graphics/paint/SkPictureBuilder.h
index f519cc57..15f588d5 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/SkPictureBuilder.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/SkPictureBuilder.h
@@ -28,6 +28,7 @@
             disabledMode = GraphicsContext::FullyDisabled;
 
         m_paintController = PaintController::create();
+        m_paintController->beginSkippingCache();
         m_context = adoptPtr(new GraphicsContext(*m_paintController, disabledMode, metaData));
 
         if (containingContext) {
@@ -41,6 +42,7 @@
     PassRefPtr<const SkPicture> endRecording()
     {
         m_context->beginRecording(m_bounds);
+        m_paintController->endSkippingCache();
         m_paintController->commitNewDisplayItems();
         m_paintController->paintArtifact().replay(*m_context);
         return m_context->endRecording();
diff --git a/third_party/WebKit/Source/platform/graphics/paint/SubsequenceDisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/SubsequenceDisplayItem.h
index 140ff4d0..1d56b3c 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/SubsequenceDisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/SubsequenceDisplayItem.h
@@ -13,14 +13,14 @@
 
 class BeginSubsequenceDisplayItem final : public PairedBeginDisplayItem {
 public:
-    BeginSubsequenceDisplayItem(const DisplayItemClientWrapper& client)
+    BeginSubsequenceDisplayItem(const DisplayItemClient& client)
         : PairedBeginDisplayItem(client, Subsequence, sizeof(*this))
     { }
 };
 
 class EndSubsequenceDisplayItem final : public PairedEndDisplayItem {
 public:
-    EndSubsequenceDisplayItem(const DisplayItemClientWrapper& client)
+    EndSubsequenceDisplayItem(const DisplayItemClient& client)
         : PairedEndDisplayItem(client, EndSubsequence, sizeof(*this))
     { }
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/SubsequenceRecorder.cpp b/third_party/WebKit/Source/platform/graphics/paint/SubsequenceRecorder.cpp
index 45067bc..50ac33ff 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/SubsequenceRecorder.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/SubsequenceRecorder.cpp
@@ -13,7 +13,7 @@
 
 namespace blink {
 
-bool SubsequenceRecorder::useCachedSubsequenceIfPossible(GraphicsContext& context, const DisplayItemClientWrapper& client)
+bool SubsequenceRecorder::useCachedSubsequenceIfPossible(GraphicsContext& context, const DisplayItemClient& client)
 {
     if (!RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled())
         return false;
@@ -21,7 +21,7 @@
     if (context.paintController().displayItemConstructionIsDisabled())
         return false;
 
-    if (!context.paintController().clientCacheIsValid(client.displayItemClient()))
+    if (!context.paintController().clientCacheIsValid(client))
         return false;
 
     context.paintController().createAndAppend<CachedDisplayItem>(client, DisplayItem::CachedSubsequence);
@@ -36,7 +36,7 @@
     return true;
 }
 
-SubsequenceRecorder::SubsequenceRecorder(GraphicsContext& context, const DisplayItemClientWrapper& client)
+SubsequenceRecorder::SubsequenceRecorder(GraphicsContext& context, const DisplayItemClient& client)
     : m_paintController(context.paintController())
     , m_client(client)
     , m_beginSubsequenceIndex(0)
diff --git a/third_party/WebKit/Source/platform/graphics/paint/SubsequenceRecorder.h b/third_party/WebKit/Source/platform/graphics/paint/SubsequenceRecorder.h
index 483a868..a24e8a31 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/SubsequenceRecorder.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/SubsequenceRecorder.h
@@ -26,16 +26,16 @@
     DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
     WTF_MAKE_NONCOPYABLE(SubsequenceRecorder);
 public:
-    static bool useCachedSubsequenceIfPossible(GraphicsContext&, const DisplayItemClientWrapper&);
+    static bool useCachedSubsequenceIfPossible(GraphicsContext&, const DisplayItemClient&);
 
-    SubsequenceRecorder(GraphicsContext&, const DisplayItemClientWrapper&);
+    SubsequenceRecorder(GraphicsContext&, const DisplayItemClient&);
     ~SubsequenceRecorder();
 
     void setUncacheable();
 
 private:
     PaintController& m_paintController;
-    DisplayItemClientWrapper m_client;
+    const DisplayItemClient& m_client;
     size_t m_beginSubsequenceIndex;
 };
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/Transform3DDisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/Transform3DDisplayItem.h
index e0257c9..d480b5c 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/Transform3DDisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/Transform3DDisplayItem.h
@@ -16,7 +16,7 @@
 class PLATFORM_EXPORT BeginTransform3DDisplayItem final : public PairedBeginDisplayItem {
 public:
     BeginTransform3DDisplayItem(
-        const DisplayItemClientWrapper& client,
+        const DisplayItemClient& client,
         Type type,
         const TransformationMatrix& transform,
         const FloatPoint3D& transformOrigin)
@@ -52,7 +52,7 @@
 
 class PLATFORM_EXPORT EndTransform3DDisplayItem final : public PairedEndDisplayItem {
 public:
-    EndTransform3DDisplayItem(const DisplayItemClientWrapper& client, Type type)
+    EndTransform3DDisplayItem(const DisplayItemClient& client, Type type)
         : PairedEndDisplayItem(client, type, sizeof(*this))
     {
         ASSERT(DisplayItem::isEndTransform3DType(type));
diff --git a/third_party/WebKit/Source/platform/graphics/paint/TransformDisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/TransformDisplayItem.h
index b4a3869..e05a1b8 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/TransformDisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/TransformDisplayItem.h
@@ -13,7 +13,7 @@
 
 class PLATFORM_EXPORT BeginTransformDisplayItem final : public PairedBeginDisplayItem {
 public:
-    BeginTransformDisplayItem(const DisplayItemClientWrapper& client, const AffineTransform& transform)
+    BeginTransformDisplayItem(const DisplayItemClient& client, const AffineTransform& transform)
         : PairedBeginDisplayItem(client, BeginTransform, sizeof(*this))
         , m_transform(transform) { }
 
@@ -39,7 +39,7 @@
 
 class PLATFORM_EXPORT EndTransformDisplayItem final : public PairedEndDisplayItem {
 public:
-    EndTransformDisplayItem(const DisplayItemClientWrapper& client)
+    EndTransformDisplayItem(const DisplayItemClient& client)
         : PairedEndDisplayItem(client, EndTransform, sizeof(*this)) { }
 
     void replay(GraphicsContext&) const override;
diff --git a/third_party/WebKit/Source/platform/graphics/skia/SkiaUtils.h b/third_party/WebKit/Source/platform/graphics/skia/SkiaUtils.h
index d8d4936..44b16b3 100644
--- a/third_party/WebKit/Source/platform/graphics/skia/SkiaUtils.h
+++ b/third_party/WebKit/Source/platform/graphics/skia/SkiaUtils.h
@@ -116,7 +116,7 @@
 inline SkScalar skBlurRadiusToSigma(SkScalar radius)
 {
     SkASSERT(radius >= 0);
-    return 0.288675f * radius + 0.5f;
+    return 0.288675f * radius;
 }
 
 template<typename PrimitiveType>
diff --git a/third_party/WebKit/Source/platform/heap/HeapTest.cpp b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
index d75c36d..02fa6ee 100644
--- a/third_party/WebKit/Source/platform/heap/HeapTest.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
@@ -4568,11 +4568,17 @@
     MixinA() : m_obj(IntWrapper::create(100)) { }
     DEFINE_INLINE_VIRTUAL_TRACE()
     {
+        s_traceCount++;
         visitor->trace(m_obj);
     }
+
+    static int s_traceCount;
+
     Member<IntWrapper> m_obj;
 };
 
+int MixinA::s_traceCount = 0;
+
 class MixinB : public GarbageCollectedMixin {
 public:
     MixinB() : m_obj(IntWrapper::create(101)) { }
@@ -4663,6 +4669,35 @@
     EXPECT_EQ(4, IntWrapper::s_destructorCalls);
 }
 
+class MixinInstanceWithoutTrace : public GarbageCollected<MixinInstanceWithoutTrace>, public MixinA {
+    USING_GARBAGE_COLLECTED_MIXIN(MixinInstanceWithoutTrace);
+public:
+    MixinInstanceWithoutTrace()
+    {
+    }
+};
+
+TEST(HeapTest, MixinInstanceWithoutTrace)
+{
+    // Verify that a mixin instance without any traceable
+    // references inherits the mixin's trace implementation.
+    clearOutOldGarbage();
+    MixinA::s_traceCount = 0;
+    MixinInstanceWithoutTrace* obj = new MixinInstanceWithoutTrace();
+    {
+        Persistent<MixinA> a = obj;
+        preciselyCollectGarbage();
+        EXPECT_EQ(1, MixinA::s_traceCount);
+    }
+    {
+        Persistent<MixinInstanceWithoutTrace> b = obj;
+        preciselyCollectGarbage();
+        EXPECT_EQ(2, MixinA::s_traceCount);
+    }
+    preciselyCollectGarbage();
+    EXPECT_EQ(2, MixinA::s_traceCount);
+}
+
 class GCParkingThreadTester {
 public:
     static void test()
diff --git a/third_party/WebKit/Source/platform/heap/MarkingVisitorImpl.h b/third_party/WebKit/Source/platform/heap/MarkingVisitorImpl.h
index 3381509..99ac12e 100644
--- a/third_party/WebKit/Source/platform/heap/MarkingVisitorImpl.h
+++ b/third_party/WebKit/Source/platform/heap/MarkingVisitorImpl.h
@@ -38,11 +38,12 @@
         if (header->isMarked())
             return;
 
-#if ENABLE(ASSERT)
         ASSERT(ThreadState::current()->isInGC());
+#if !defined(NDEBUG)
         ASSERT(Heap::findPageFromAddress(header));
-        ASSERT(toDerived()->markingMode() != Visitor::WeakProcessing);
 #endif
+        ASSERT(toDerived()->markingMode() != Visitor::WeakProcessing);
+
         header->mark();
 
         if (callback)
diff --git a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.h b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.h
index b8665e48..b5805bc6 100644
--- a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.h
+++ b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.h
@@ -100,8 +100,8 @@
     void mouseEnteredContentArea() const override;
     void mouseExitedContentArea() const override;
     void mouseMovedInContentArea() const override;
-    void mouseEnteredScrollbar(Scrollbar*) const override;
-    void mouseExitedScrollbar(Scrollbar*) const override;
+    void mouseEnteredScrollbar(Scrollbar&) const override;
+    void mouseExitedScrollbar(Scrollbar&) const override;
     void willStartLiveResize() override;
     void contentsResized() const override;
     void willEndLiveResize() override;
@@ -113,12 +113,12 @@
 
     void finishCurrentScrollAnimations() override;
 
-    void didAddVerticalScrollbar(Scrollbar*) override;
-    void willRemoveVerticalScrollbar(Scrollbar*) override;
-    void didAddHorizontalScrollbar(Scrollbar*) override;
-    void willRemoveHorizontalScrollbar(Scrollbar*) override;
+    void didAddVerticalScrollbar(Scrollbar&) override;
+    void willRemoveVerticalScrollbar(Scrollbar&) override;
+    void didAddHorizontalScrollbar(Scrollbar&) override;
+    void willRemoveHorizontalScrollbar(Scrollbar&) override;
 
-    bool shouldScrollbarParticipateInHitTesting(Scrollbar*) override;
+    bool shouldScrollbarParticipateInHitTesting(Scrollbar&) override;
 
     void notifyContentAreaScrolled(const FloatSize& delta) override;
 
diff --git a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm
index fb411cf..8c3cb76 100644
--- a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm
+++ b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm
@@ -66,11 +66,11 @@
 static ScrollbarThemeMacOverlayAPI* macOverlayScrollbarTheme()
 {
     RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(ScrollbarThemeMacCommon::isOverlayAPIAvailable());
-    ScrollbarTheme* scrollbarTheme = ScrollbarTheme::theme();
-    return !scrollbarTheme->isMockTheme() ? static_cast<ScrollbarThemeMacOverlayAPI*>(scrollbarTheme) : 0;
+    ScrollbarTheme& scrollbarTheme = ScrollbarTheme::theme();
+    return !scrollbarTheme.isMockTheme() ? static_cast<ScrollbarThemeMacOverlayAPI*>(&scrollbarTheme) : nil;
 }
 
-static ScrollbarPainter scrollbarPainterForScrollbar(Scrollbar* scrollbar)
+static ScrollbarPainter scrollbarPainterForScrollbar(Scrollbar& scrollbar)
 {
     if (ScrollbarThemeMacOverlayAPI* scrollbarTheme = macOverlayScrollbarTheme())
         return scrollbarTheme->painterForScrollbar(scrollbar);
@@ -237,7 +237,7 @@
     if (!_scrollableArea || !scrollerImp)
         return NSZeroPoint;
 
-    blink::Scrollbar* scrollbar = 0;
+    blink::Scrollbar* scrollbar = nil;
     if ([scrollerImp isHorizontal])
         scrollbar = _scrollableArea->horizontalScrollbar();
     else
@@ -251,7 +251,7 @@
     if (!scrollbar)
         return NSZeroPoint;
 
-    ASSERT(scrollerImp == scrollbarPainterForScrollbar(scrollbar));
+    ASSERT(scrollerImp == scrollbarPainterForScrollbar(*scrollbar));
 
     return scrollbar->convertFromContainingWidget(blink::IntPoint(pointInContentArea));
 }
@@ -264,7 +264,7 @@
     if (!_scrollableArea->scrollbarsCanBeActive())
         return;
 
-    _scrollableArea->scrollAnimator()->contentAreaWillPaint();
+    _scrollableArea->scrollAnimator().contentAreaWillPaint();
 }
 
 - (void)scrollerImpPair:(id)scrollerImpPair updateScrollerStyleForNewRecommendedScrollerStyle:(NSScrollerStyle)newRecommendedScrollerStyle
@@ -281,7 +281,7 @@
 
     [scrollerImpPair setScrollerStyle:newRecommendedScrollerStyle];
 
-    static_cast<ScrollAnimatorMac*>(_scrollableArea->scrollAnimator())->updateScrollerStyle();
+    static_cast<ScrollAnimatorMac&>(_scrollableArea->scrollAnimator()).updateScrollerStyle();
 }
 
 @end
@@ -390,7 +390,7 @@
 {
     ASSERT(_scrollbar);
 
-    _scrollbarPainter = scrollbarPainterForScrollbar(_scrollbar);
+    _scrollbarPainter = scrollbarPainterForScrollbar(*_scrollbar);
     _timer->start();
 }
 
@@ -486,7 +486,7 @@
 - (void)updateVisibilityImmediately:(bool)show
 {
     [self cancelAnimations];
-    [scrollbarPainterForScrollbar(_scrollbar) setKnobAlpha:(show ? 1.0 : 0.0)];
+    [scrollbarPainterForScrollbar(*_scrollbar) setKnobAlpha:(show ? 1.0 : 0.0)];
 }
 
 - (void)cancelAnimations
@@ -499,9 +499,9 @@
     END_BLOCK_OBJC_EXCEPTIONS;
 }
 
-- (ScrollAnimatorMac*)scrollAnimator
+- (ScrollAnimatorMac&)scrollAnimator
 {
-    return static_cast<ScrollAnimatorMac*>(_scrollbar->scrollableArea()->scrollAnimator());
+    return static_cast<ScrollAnimatorMac&>(_scrollbar->scrollableArea()->scrollAnimator());
 }
 
 - (NSRect)convertRectToBacking:(NSRect)aRect
@@ -519,7 +519,7 @@
     if (!_scrollbar)
         return NSZeroPoint;
 
-    ASSERT_UNUSED(scrollerImp, scrollerImp == scrollbarPainterForScrollbar(_scrollbar));
+    ASSERT_UNUSED(scrollerImp, scrollerImp == scrollbarPainterForScrollbar(*_scrollbar));
 
     return _scrollbar->convertFromContainingWidget(_scrollbar->scrollableArea()->lastKnownMousePosition());
 }
@@ -528,18 +528,18 @@
 {
     // If the user has scrolled the page, then the scrollbars must be animated here.
     // This overrides the early returns.
-    bool mustAnimate = [self scrollAnimator]->haveScrolledSincePageLoad();
+    bool mustAnimate = [self scrollAnimator].haveScrolledSincePageLoad();
 
-    if ([self scrollAnimator]->scrollbarPaintTimerIsActive() && !mustAnimate)
+    if ([self scrollAnimator].scrollbarPaintTimerIsActive() && !mustAnimate)
         return;
 
     if (_scrollbar->scrollableArea()->shouldSuspendScrollAnimations() && !mustAnimate) {
-        [self scrollAnimator]->startScrollbarPaintTimer();
+        [self scrollAnimator].startScrollbarPaintTimer();
         return;
     }
 
     // At this point, we are definitely going to animate now, so stop the timer.
-    [self scrollAnimator]->stopScrollbarPaintTimer();
+    [self scrollAnimator].stopScrollbarPaintTimer();
 
     // If we are currently animating, stop
     if (scrollbarPartAnimation) {
@@ -550,9 +550,9 @@
     if (part == blink::ThumbPart && _scrollbar->orientation() == VerticalScrollbar) {
         if (newAlpha == 1) {
             IntRect thumbRect = IntRect([scrollerPainter rectForPart:NSScrollerKnob]);
-            [self scrollAnimator]->setVisibleScrollerThumbRect(thumbRect);
+            [self scrollAnimator].setVisibleScrollerThumbRect(thumbRect);
         } else
-            [self scrollAnimator]->setVisibleScrollerThumbRect(IntRect());
+            [self scrollAnimator].setVisibleScrollerThumbRect(IntRect());
     }
 
     scrollbarPartAnimation.adoptNS([[WebScrollbarPartAnimation alloc] initWithScrollbar:_scrollbar
@@ -568,7 +568,7 @@
     if (!_scrollbar)
         return;
 
-    ASSERT(scrollerImp == scrollbarPainterForScrollbar(_scrollbar));
+    ASSERT(scrollerImp == scrollbarPainterForScrollbar(*_scrollbar));
 
     ScrollbarPainter scrollerPainter = (ScrollbarPainter)scrollerImp;
     [self setUpAlphaAnimation:_knobAlphaAnimation scrollerPainter:scrollerPainter part:blink::ThumbPart animateAlphaTo:newKnobAlpha duration:duration];
@@ -579,7 +579,7 @@
     if (!_scrollbar)
         return;
 
-    ASSERT(scrollerImp == scrollbarPainterForScrollbar(_scrollbar));
+    ASSERT(scrollerImp == scrollbarPainterForScrollbar(*_scrollbar));
 
     ScrollbarPainter scrollerPainter = (ScrollbarPainter)scrollerImp;
     [self setUpAlphaAnimation:_trackAlphaAnimation scrollerPainter:scrollerPainter part:blink::BackTrackPart animateAlphaTo:newTrackAlpha duration:duration];
@@ -593,7 +593,7 @@
     if (!supportsUIStateTransitionProgress())
         return;
 
-    ASSERT(scrollerImp == scrollbarPainterForScrollbar(_scrollbar));
+    ASSERT(scrollerImp == scrollbarPainterForScrollbar(*_scrollbar));
 
     ScrollbarPainter scrollbarPainter = (ScrollbarPainter)scrollerImp;
 
@@ -623,7 +623,7 @@
     if (!supportsExpansionTransitionProgress())
         return;
 
-    ASSERT(scrollerImp == scrollbarPainterForScrollbar(_scrollbar));
+    ASSERT(scrollerImp == scrollbarPainterForScrollbar(*_scrollbar));
 
     ScrollbarPainter scrollbarPainter = (ScrollbarPainter)scrollerImp;
 
@@ -730,9 +730,9 @@
 
 ScrollResultOneDimensional ScrollAnimatorMac::userScroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float delta)
 {
-    bool scrollAnimationEnabledForSystem = static_cast<ScrollbarThemeMacCommon*>(
+    bool scrollAnimationEnabledForSystem = static_cast<ScrollbarThemeMacCommon&>(
                                                ScrollbarTheme::theme())
-                                               ->scrollAnimationEnabledForSystem();
+                                               .scrollAnimationEnabledForSystem();
     m_haveScrolledSincePageLoad = true;
 
     if (!scrollAnimationEnabledForSystem || !m_scrollableArea->scrollAnimatorEnabled())
@@ -830,7 +830,7 @@
         [m_scrollbarPainterController.get() mouseMovedInContentArea];
 }
 
-void ScrollAnimatorMac::mouseEnteredScrollbar(Scrollbar* scrollbar) const
+void ScrollAnimatorMac::mouseEnteredScrollbar(Scrollbar& scrollbar) const
 {
     if (!scrollableArea()->scrollbarsCanBeActive())
         return;
@@ -843,7 +843,7 @@
     }
 }
 
-void ScrollAnimatorMac::mouseExitedScrollbar(Scrollbar* scrollbar) const
+void ScrollAnimatorMac::mouseExitedScrollbar(Scrollbar& scrollbar) const
 {
     if (!scrollableArea()->scrollbarsCanBeActive())
         return;
@@ -930,7 +930,7 @@
     }
 }
 
-void ScrollAnimatorMac::didAddVerticalScrollbar(Scrollbar* scrollbar)
+void ScrollAnimatorMac::didAddVerticalScrollbar(Scrollbar& scrollbar)
 {
     if (!ScrollbarThemeMacCommon::isOverlayAPIAvailable())
         return;
@@ -940,7 +940,7 @@
         return;
 
     ASSERT(!m_verticalScrollbarPainterDelegate);
-    m_verticalScrollbarPainterDelegate.adoptNS([[WebScrollbarPainterDelegate alloc] initWithScrollbar:scrollbar]);
+    m_verticalScrollbarPainterDelegate.adoptNS([[WebScrollbarPainterDelegate alloc] initWithScrollbar:&scrollbar]);
 
     [painter setDelegate:m_verticalScrollbarPainterDelegate.get()];
     [m_scrollbarPainterController.get() setVerticalScrollerImp:painter];
@@ -948,7 +948,7 @@
         [painter setKnobAlpha:1];
 }
 
-void ScrollAnimatorMac::willRemoveVerticalScrollbar(Scrollbar* scrollbar)
+void ScrollAnimatorMac::willRemoveVerticalScrollbar(Scrollbar& scrollbar)
 {
     if (!ScrollbarThemeMacCommon::isOverlayAPIAvailable())
         return;
@@ -965,7 +965,7 @@
     [m_scrollbarPainterController.get() setVerticalScrollerImp:nil];
 }
 
-void ScrollAnimatorMac::didAddHorizontalScrollbar(Scrollbar* scrollbar)
+void ScrollAnimatorMac::didAddHorizontalScrollbar(Scrollbar& scrollbar)
 {
     if (!ScrollbarThemeMacCommon::isOverlayAPIAvailable())
         return;
@@ -975,7 +975,7 @@
         return;
 
     ASSERT(!m_horizontalScrollbarPainterDelegate);
-    m_horizontalScrollbarPainterDelegate.adoptNS([[WebScrollbarPainterDelegate alloc] initWithScrollbar:scrollbar]);
+    m_horizontalScrollbarPainterDelegate.adoptNS([[WebScrollbarPainterDelegate alloc] initWithScrollbar:&scrollbar]);
 
     [painter setDelegate:m_horizontalScrollbarPainterDelegate.get()];
     [m_scrollbarPainterController.get() setHorizontalScrollerImp:painter];
@@ -983,7 +983,7 @@
         [painter setKnobAlpha:1];
 }
 
-void ScrollAnimatorMac::willRemoveHorizontalScrollbar(Scrollbar* scrollbar)
+void ScrollAnimatorMac::willRemoveHorizontalScrollbar(Scrollbar& scrollbar)
 {
     if (!ScrollbarThemeMacCommon::isOverlayAPIAvailable())
         return;
@@ -1000,7 +1000,7 @@
     [m_scrollbarPainterController.get() setHorizontalScrollerImp:nil];
 }
 
-bool ScrollAnimatorMac::shouldScrollbarParticipateInHitTesting(Scrollbar* scrollbar)
+bool ScrollAnimatorMac::shouldScrollbarParticipateInHitTesting(Scrollbar& scrollbar)
 {
     // Non-overlay scrollbars should always participate in hit testing.
     if (ScrollbarThemeMacCommon::recommendedScrollerStyle() != NSScrollerStyleOverlay)
@@ -1009,7 +1009,7 @@
     if (!ScrollbarThemeMacCommon::isOverlayAPIAvailable())
         return true;
 
-    if (scrollbar->isAlphaLocked())
+    if (scrollbar.isAlphaLocked())
         return true;
 
     // Overlay scrollbars should participate in hit testing whenever they are at all visible.
@@ -1112,7 +1112,7 @@
                                                                                     horizontal:NO
                                                                                     replacingScrollerImp:oldVerticalPainter];
         [m_scrollbarPainterController.get() setVerticalScrollerImp:newVerticalPainter];
-        macTheme->setNewPainterForScrollbar(verticalScrollbar, newVerticalPainter);
+        macTheme->setNewPainterForScrollbar(*verticalScrollbar, newVerticalPainter);
 
         // The different scrollbar styles have different thicknesses, so we must re-set the
         // frameRect to the new thickness, and the re-layout below will ensure the position
@@ -1132,7 +1132,7 @@
                                                                                     horizontal:YES
                                                                                     replacingScrollerImp:oldHorizontalPainter];
         [m_scrollbarPainterController.get() setHorizontalScrollerImp:newHorizontalPainter];
-        macTheme->setNewPainterForScrollbar(horizontalScrollbar, newHorizontalPainter);
+        macTheme->setNewPainterForScrollbar(*horizontalScrollbar, newHorizontalPainter);
 
         // The different scrollbar styles have different thicknesses, so we must re-set the
         // frameRect to the new thickness, and the re-layout below will ensure the position
diff --git a/third_party/WebKit/Source/platform/network/ResourceResponse.cpp b/third_party/WebKit/Source/platform/network/ResourceResponse.cpp
index 37de0b6..1ba750e5 100644
--- a/third_party/WebKit/Source/platform/network/ResourceResponse.cpp
+++ b/third_party/WebKit/Source/platform/network/ResourceResponse.cpp
@@ -48,6 +48,7 @@
     , m_date(0.0)
     , m_expires(0.0)
     , m_lastModified(0.0)
+    , m_hasMajorCertificateErrors(false)
     , m_securityStyle(SecurityStyleUnknown)
     , m_httpVersion(HTTPVersionUnknown)
     , m_appCacheID(0)
@@ -84,6 +85,7 @@
     , m_date(0.0)
     , m_expires(0.0)
     , m_lastModified(0.0)
+    , m_hasMajorCertificateErrors(false)
     , m_securityStyle(SecurityStyleUnknown)
     , m_httpVersion(HTTPVersionUnknown)
     , m_appCacheID(0)
@@ -116,6 +118,7 @@
     response->setLastModifiedDate(data->m_lastModifiedDate);
     response->setResourceLoadTiming(data->m_resourceLoadTiming.release());
     response->m_securityInfo = data->m_securityInfo;
+    response->m_hasMajorCertificateErrors = data->m_hasMajorCertificateErrors;
     response->m_securityStyle = data->m_securityStyle;
     response->m_securityDetails.protocol = data->m_securityDetails.protocol;
     response->m_securityDetails.cipher = data->m_securityDetails.cipher;
@@ -161,6 +164,7 @@
     if (m_resourceLoadTiming)
         data->m_resourceLoadTiming = m_resourceLoadTiming->deepCopy();
     data->m_securityInfo = CString(m_securityInfo.data(), m_securityInfo.length());
+    data->m_hasMajorCertificateErrors = m_hasMajorCertificateErrors;
     data->m_securityStyle = m_securityStyle;
     data->m_securityDetails.protocol = m_securityDetails.protocol.isolatedCopy();
     data->m_securityDetails.cipher = m_securityDetails.cipher.isolatedCopy();
diff --git a/third_party/WebKit/Source/platform/network/ResourceResponse.h b/third_party/WebKit/Source/platform/network/ResourceResponse.h
index 58080de3..9c19606 100644
--- a/third_party/WebKit/Source/platform/network/ResourceResponse.h
+++ b/third_party/WebKit/Source/platform/network/ResourceResponse.h
@@ -160,6 +160,9 @@
     const CString& getSecurityInfo() const { return m_securityInfo; }
     void setSecurityInfo(const CString& securityInfo) { m_securityInfo = securityInfo; }
 
+    bool hasMajorCertificateErrors() const { return m_hasMajorCertificateErrors; }
+    void setHasMajorCertificateErrors(bool hasMajorCertificateErrors) { m_hasMajorCertificateErrors = hasMajorCertificateErrors; }
+
     SecurityStyle securityStyle() const { return m_securityStyle; }
     void setSecurityStyle(SecurityStyle securityStyle) { m_securityStyle = securityStyle; }
 
@@ -268,6 +271,10 @@
     // string if not over HTTPS).
     CString m_securityInfo;
 
+    // True if the resource was retrieved by the embedder in spite of
+    // certificate errors.
+    bool m_hasMajorCertificateErrors;
+
     // The security style of the resource.
     // This only contains a valid value when the DevTools Network domain is
     // enabled. (Otherwise, it contains a default value of Unknown.)
@@ -357,6 +364,7 @@
     time_t m_lastModifiedDate;
     RefPtr<ResourceLoadTiming> m_resourceLoadTiming;
     CString m_securityInfo;
+    bool m_hasMajorCertificateErrors;
     ResourceResponse::SecurityStyle m_securityStyle;
     ResourceResponse::SecurityDetails m_securityDetails;
     ResourceResponse::HTTPVersion m_httpVersion;
diff --git a/third_party/WebKit/Source/platform/scheduler/CancellableTaskFactory.h b/third_party/WebKit/Source/platform/scheduler/CancellableTaskFactory.h
index 36a56bfc..e379fed 100644
--- a/third_party/WebKit/Source/platform/scheduler/CancellableTaskFactory.h
+++ b/third_party/WebKit/Source/platform/scheduler/CancellableTaskFactory.h
@@ -13,8 +13,8 @@
 #include "wtf/OwnPtr.h"
 #include "wtf/PassOwnPtr.h"
 #include "wtf/RefCounted.h"
-#include "wtf/TypeTraits.h"
 #include "wtf/WeakPtr.h"
+#include <type_traits>
 
 namespace blink {
 
@@ -37,13 +37,13 @@
     // variety, which will refer back to the owner heap object safely (but weakly.)
     //
     template<typename T>
-    static PassOwnPtr<CancellableTaskFactory> create(T* thisObject, void (T::*method)(), typename WTF::EnableIf<IsGarbageCollectedType<T>::value>::Type* = nullptr)
+    static PassOwnPtr<CancellableTaskFactory> create(T* thisObject, void (T::*method)(), typename std::enable_if<IsGarbageCollectedType<T>::value>::type* = nullptr)
     {
         return adoptPtr(new CancellableTaskFactory(WTF::bind(method, AllowCrossThreadWeakPersistent<T>(thisObject))));
     }
 
     template<typename T>
-    static PassOwnPtr<CancellableTaskFactory> create(T* thisObject, void (T::*method)(), typename WTF::EnableIf<!IsGarbageCollectedType<T>::value>::Type* = nullptr)
+    static PassOwnPtr<CancellableTaskFactory> create(T* thisObject, void (T::*method)(), typename std::enable_if<!IsGarbageCollectedType<T>::value>::type* = nullptr)
     {
         return adoptPtr(new CancellableTaskFactory(WTF::bind(method, thisObject)));
     }
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h
index 0a561831..49b51eb4 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h
@@ -80,8 +80,8 @@
     virtual void mouseEnteredContentArea() const { }
     virtual void mouseExitedContentArea() const { }
     virtual void mouseMovedInContentArea() const { }
-    virtual void mouseEnteredScrollbar(Scrollbar*) const { }
-    virtual void mouseExitedScrollbar(Scrollbar*) const { }
+    virtual void mouseEnteredScrollbar(Scrollbar&) const { }
+    virtual void mouseExitedScrollbar(Scrollbar&) const { }
     virtual void willStartLiveResize() { }
     virtual void updateAfterLayout() { }
     virtual void contentsResized() const { }
@@ -91,12 +91,12 @@
 
     virtual void finishCurrentScrollAnimations() { }
 
-    virtual void didAddVerticalScrollbar(Scrollbar*) { }
-    virtual void willRemoveVerticalScrollbar(Scrollbar*) { }
-    virtual void didAddHorizontalScrollbar(Scrollbar*) { }
-    virtual void willRemoveHorizontalScrollbar(Scrollbar*) { }
+    virtual void didAddVerticalScrollbar(Scrollbar&) { }
+    virtual void willRemoveVerticalScrollbar(Scrollbar&) { }
+    virtual void didAddHorizontalScrollbar(Scrollbar&) { }
+    virtual void willRemoveHorizontalScrollbar(Scrollbar&) { }
 
-    virtual bool shouldScrollbarParticipateInHitTesting(Scrollbar*) { return true; }
+    virtual bool shouldScrollbarParticipateInHitTesting(Scrollbar&) { return true; }
 
     virtual void notifyContentAreaScrolled(const FloatSize&) { }
 
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
index 14086dc..9768a4e6 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
@@ -73,7 +73,7 @@
 
 int ScrollableArea::maxOverlapBetweenPages()
 {
-    static int maxOverlapBetweenPages = ScrollbarTheme::theme()->maxOverlapBetweenPages();
+    static int maxOverlapBetweenPages = ScrollbarTheme::theme().maxOverlapBetweenPages();
     return maxOverlapBetweenPages;
 }
 
@@ -101,20 +101,20 @@
     m_programmaticScrollAnimator.clear();
 }
 
-ScrollAnimatorBase* ScrollableArea::scrollAnimator() const
+ScrollAnimatorBase& ScrollableArea::scrollAnimator() const
 {
     if (!m_scrollAnimator)
         m_scrollAnimator = ScrollAnimatorBase::create(const_cast<ScrollableArea*>(this));
 
-    return m_scrollAnimator.get();
+    return *m_scrollAnimator;
 }
 
-ProgrammaticScrollAnimator* ScrollableArea::programmaticScrollAnimator() const
+ProgrammaticScrollAnimator& ScrollableArea::programmaticScrollAnimator() const
 {
     if (!m_programmaticScrollAnimator)
         m_programmaticScrollAnimator = ProgrammaticScrollAnimator::create(const_cast<ScrollableArea*>(this));
 
-    return m_programmaticScrollAnimator.get();
+    return *m_programmaticScrollAnimator;
 }
 
 void ScrollableArea::setScrollOrigin(const IntPoint& origin)
@@ -163,7 +163,7 @@
     if (direction == ScrollUp || direction == ScrollLeft)
         delta = -delta;
 
-    return scrollAnimator()->userScroll(orientation, granularity, step, delta);
+    return scrollAnimator().userScroll(orientation, granularity, step, delta);
 }
 
 void ScrollableArea::setScrollPosition(const DoublePoint& position, ScrollType scrollType, ScrollBehavior behavior)
@@ -190,9 +190,9 @@
 {
     DoublePoint newPosition;
     if (orientation == HorizontalScrollbar)
-        newPosition = DoublePoint(position, scrollAnimator()->currentPosition().y());
+        newPosition = DoublePoint(position, scrollAnimator().currentPosition().y());
     else
-        newPosition = DoublePoint(scrollAnimator()->currentPosition().x(), position);
+        newPosition = DoublePoint(scrollAnimator().currentPosition().x(), position);
 
     // TODO(bokan): Note, this doesn't use the derived class versions since this method is currently used
     // exclusively by code that adjusts the position by the scroll origin and the derived class versions
@@ -205,24 +205,24 @@
     cancelScrollAnimation();
 
     if (scrollBehavior == ScrollBehaviorSmooth)
-        programmaticScrollAnimator()->animateToOffset(toFloatPoint(position));
+        programmaticScrollAnimator().animateToOffset(toFloatPoint(position));
     else
-        programmaticScrollAnimator()->scrollToOffsetWithoutAnimation(toFloatPoint(position));
+        programmaticScrollAnimator().scrollToOffsetWithoutAnimation(toFloatPoint(position));
 }
 
 void ScrollableArea::userScrollHelper(const DoublePoint& position, ScrollBehavior scrollBehavior)
 {
     cancelProgrammaticScrollAnimation();
 
-    double x = userInputScrollable(HorizontalScrollbar) ? position.x() : scrollAnimator()->currentPosition().x();
-    double y = userInputScrollable(VerticalScrollbar) ? position.y() : scrollAnimator()->currentPosition().y();
+    double x = userInputScrollable(HorizontalScrollbar) ? position.x() : scrollAnimator().currentPosition().x();
+    double y = userInputScrollable(VerticalScrollbar) ? position.y() : scrollAnimator().currentPosition().y();
 
     // Smooth user scrolls (keyboard, wheel clicks) are handled via the userScroll method.
     // TODO(bokan): The userScroll method should probably be modified to call this method
     //              and ScrollAnimatorBase to have a simpler animateToOffset method like the
     //              ProgrammaticScrollAnimator.
     ASSERT(scrollBehavior == ScrollBehaviorInstant);
-    scrollAnimator()->scrollToOffsetWithoutAnimation(FloatPoint(x, y));
+    scrollAnimator().scrollToOffsetWithoutAnimation(FloatPoint(x, y));
 }
 
 LayoutRect ScrollableArea::scrollIntoView(const LayoutRect& rectInContent, const ScrollAlignment& alignX, const ScrollAlignment& alignY, ScrollType)
@@ -248,20 +248,20 @@
     if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) {
         horizontalScrollbar->offsetDidChange();
         if (horizontalScrollbar->isOverlayScrollbar() && !hasLayerForHorizontalScrollbar())
-            setScrollbarNeedsPaintInvalidation(horizontalScrollbar);
+            setScrollbarNeedsPaintInvalidation(HorizontalScrollbar);
     }
     if (verticalScrollbar) {
         verticalScrollbar->offsetDidChange();
         if (verticalScrollbar->isOverlayScrollbar() && !hasLayerForVerticalScrollbar())
-            setScrollbarNeedsPaintInvalidation(verticalScrollbar);
+            setScrollbarNeedsPaintInvalidation(VerticalScrollbar);
     }
 
     if (scrollPositionDouble() != oldPosition) {
         // FIXME: Pass in DoubleSize. crbug.com/414283.
-        scrollAnimator()->notifyContentAreaScrolled(toFloatSize(scrollPositionDouble() - oldPosition));
+        scrollAnimator().notifyContentAreaScrolled(toFloatSize(scrollPositionDouble() - oldPosition));
     }
 
-    scrollAnimator()->setCurrentPosition(toFloatPoint(position));
+    scrollAnimator().setCurrentPosition(toFloatPoint(position));
 }
 
 bool ScrollableArea::scrollBehaviorFromString(const String& behaviorString, ScrollBehavior& behavior)
@@ -326,14 +326,14 @@
         scrollAnimator->mouseMovedInContentArea();
 }
 
-void ScrollableArea::mouseEnteredScrollbar(Scrollbar* scrollbar) const
+void ScrollableArea::mouseEnteredScrollbar(Scrollbar& scrollbar) const
 {
-    scrollAnimator()->mouseEnteredScrollbar(scrollbar);
+    scrollAnimator().mouseEnteredScrollbar(scrollbar);
 }
 
-void ScrollableArea::mouseExitedScrollbar(Scrollbar* scrollbar) const
+void ScrollableArea::mouseExitedScrollbar(Scrollbar& scrollbar) const
 {
-    scrollAnimator()->mouseExitedScrollbar(scrollbar);
+    scrollAnimator().mouseExitedScrollbar(scrollbar);
 }
 
 void ScrollableArea::contentAreaDidShow() const
@@ -354,23 +354,23 @@
         scrollAnimator->finishCurrentScrollAnimations();
 }
 
-void ScrollableArea::didAddScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
+void ScrollableArea::didAddScrollbar(Scrollbar& scrollbar, ScrollbarOrientation orientation)
 {
     if (orientation == VerticalScrollbar)
-        scrollAnimator()->didAddVerticalScrollbar(scrollbar);
+        scrollAnimator().didAddVerticalScrollbar(scrollbar);
     else
-        scrollAnimator()->didAddHorizontalScrollbar(scrollbar);
+        scrollAnimator().didAddHorizontalScrollbar(scrollbar);
 
     // <rdar://problem/9797253> AppKit resets the scrollbar's style when you attach a scrollbar
     setScrollbarOverlayStyle(scrollbarOverlayStyle());
 }
 
-void ScrollableArea::willRemoveScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
+void ScrollableArea::willRemoveScrollbar(Scrollbar& scrollbar, ScrollbarOrientation orientation)
 {
     if (orientation == VerticalScrollbar)
-        scrollAnimator()->willRemoveVerticalScrollbar(scrollbar);
+        scrollAnimator().willRemoveVerticalScrollbar(scrollbar);
     else
-        scrollAnimator()->willRemoveHorizontalScrollbar(scrollbar);
+        scrollAnimator().willRemoveHorizontalScrollbar(scrollbar);
 }
 
 void ScrollableArea::contentsResized()
@@ -393,40 +393,24 @@
     m_scrollbarOverlayStyle = overlayStyle;
 
     if (Scrollbar* scrollbar = horizontalScrollbar()) {
-        ScrollbarTheme::theme()->updateScrollbarOverlayStyle(scrollbar);
-        setScrollbarNeedsPaintInvalidation(scrollbar);
+        ScrollbarTheme::theme().updateScrollbarOverlayStyle(*scrollbar);
+        setScrollbarNeedsPaintInvalidation(HorizontalScrollbar);
     }
 
     if (Scrollbar* scrollbar = verticalScrollbar()) {
-        ScrollbarTheme::theme()->updateScrollbarOverlayStyle(scrollbar);
-        setScrollbarNeedsPaintInvalidation(scrollbar);
+        ScrollbarTheme::theme().updateScrollbarOverlayStyle(*scrollbar);
+        setScrollbarNeedsPaintInvalidation(VerticalScrollbar);
     }
 }
 
-void ScrollableArea::setScrollbarNeedsPaintInvalidation(Scrollbar* scrollbar)
+void ScrollableArea::setScrollbarNeedsPaintInvalidation(ScrollbarOrientation orientation)
 {
-    if (scrollbar == horizontalScrollbar()) {
-        if (GraphicsLayer* graphicsLayer = layerForHorizontalScrollbar()) {
-            graphicsLayer->setNeedsDisplay();
-            graphicsLayer->setContentsNeedsDisplay();
-            return;
-        }
+    if (orientation == HorizontalScrollbar)
         m_horizontalScrollbarNeedsPaintInvalidation = true;
-        scrollControlWasSetNeedsPaintInvalidation();
-        return;
-    }
-    if (scrollbar == verticalScrollbar()) {
-        if (GraphicsLayer* graphicsLayer = layerForVerticalScrollbar()) {
-            graphicsLayer->setNeedsDisplay();
-            graphicsLayer->setContentsNeedsDisplay();
-            return;
-        }
+    else
         m_verticalScrollbarNeedsPaintInvalidation = true;
-        scrollControlWasSetNeedsPaintInvalidation();
-        return;
-    }
-    // Otherwise the scrollbar is just created and has not been set as either
-    // horizontalScrollbar() or verticalScrollbar().
+
+    scrollControlWasSetNeedsPaintInvalidation();
 }
 
 void ScrollableArea::setScrollCornerNeedsPaintInvalidation()
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableArea.h b/third_party/WebKit/Source/platform/scroll/ScrollableArea.h
index d643a1a..e8b1928 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollableArea.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollableArea.h
@@ -106,15 +106,15 @@
     void mouseEnteredContentArea() const;
     void mouseExitedContentArea() const;
     void mouseMovedInContentArea() const;
-    void mouseEnteredScrollbar(Scrollbar*) const;
-    void mouseExitedScrollbar(Scrollbar*) const;
+    void mouseEnteredScrollbar(Scrollbar&) const;
+    void mouseExitedScrollbar(Scrollbar&) const;
     void contentAreaDidShow() const;
     void contentAreaDidHide() const;
 
     void finishCurrentScrollAnimations() const;
 
-    virtual void didAddScrollbar(Scrollbar*, ScrollbarOrientation);
-    virtual void willRemoveScrollbar(Scrollbar*, ScrollbarOrientation);
+    virtual void didAddScrollbar(Scrollbar&, ScrollbarOrientation);
+    virtual void willRemoveScrollbar(Scrollbar&, ScrollbarOrientation);
 
     virtual void contentsResized();
 
@@ -123,12 +123,12 @@
     ScrollbarOverlayStyle scrollbarOverlayStyle() const { return static_cast<ScrollbarOverlayStyle>(m_scrollbarOverlayStyle); }
 
     // This getter will create a ScrollAnimatorBase if it doesn't already exist.
-    ScrollAnimatorBase* scrollAnimator() const;
+    ScrollAnimatorBase& scrollAnimator() const;
 
     // This getter will return null if the ScrollAnimatorBase hasn't been created yet.
     ScrollAnimatorBase* existingScrollAnimator() const { return m_scrollAnimator.get(); }
 
-    ProgrammaticScrollAnimator* programmaticScrollAnimator() const;
+    ProgrammaticScrollAnimator& programmaticScrollAnimator() const;
     ProgrammaticScrollAnimator* existingProgrammaticScrollAnimator() const { return m_programmaticScrollAnimator.get(); }
 
     const IntPoint& scrollOrigin() const { return m_scrollOrigin; }
@@ -144,7 +144,7 @@
 
     virtual bool isActive() const = 0;
     virtual int scrollSize(ScrollbarOrientation) const = 0;
-    void setScrollbarNeedsPaintInvalidation(Scrollbar*);
+    void setScrollbarNeedsPaintInvalidation(ScrollbarOrientation);
     virtual bool isScrollCornerVisible() const = 0;
     virtual IntRect scrollCornerRect() const = 0;
     void setScrollCornerNeedsPaintInvalidation();
@@ -153,25 +153,25 @@
     // Convert points and rects between the scrollbar and its containing Widget.
     // The client needs to implement these in order to be aware of layout effects
     // like CSS transforms.
-    virtual IntRect convertFromScrollbarToContainingWidget(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
+    virtual IntRect convertFromScrollbarToContainingWidget(const Scrollbar& scrollbar, const IntRect& scrollbarRect) const
     {
-        return scrollbar->Widget::convertToContainingWidget(scrollbarRect);
+        return scrollbar.Widget::convertToContainingWidget(scrollbarRect);
     }
-    virtual IntRect convertFromContainingWidgetToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
+    virtual IntRect convertFromContainingWidgetToScrollbar(const Scrollbar& scrollbar, const IntRect& parentRect) const
     {
-        return scrollbar->Widget::convertFromContainingWidget(parentRect);
+        return scrollbar.Widget::convertFromContainingWidget(parentRect);
     }
-    virtual IntPoint convertFromScrollbarToContainingWidget(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const
+    virtual IntPoint convertFromScrollbarToContainingWidget(const Scrollbar& scrollbar, const IntPoint& scrollbarPoint) const
     {
-        return scrollbar->Widget::convertToContainingWidget(scrollbarPoint);
+        return scrollbar.Widget::convertToContainingWidget(scrollbarPoint);
     }
-    virtual IntPoint convertFromContainingWidgetToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
+    virtual IntPoint convertFromContainingWidgetToScrollbar(const Scrollbar& scrollbar, const IntPoint& parentPoint) const
     {
-        return scrollbar->Widget::convertFromContainingWidget(parentPoint);
+        return scrollbar.Widget::convertFromContainingWidget(parentPoint);
     }
 
-    virtual Scrollbar* horizontalScrollbar() const { return 0; }
-    virtual Scrollbar* verticalScrollbar() const { return 0; }
+    virtual Scrollbar* horizontalScrollbar() const { return nullptr; }
+    virtual Scrollbar* verticalScrollbar() const { return nullptr; }
 
     // scrollPosition is relative to the scrollOrigin. i.e. If the page is RTL
     // then scrollPosition will be negative. By default, scrollPositionDouble()
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableAreaTest.cpp b/third_party/WebKit/Source/platform/scroll/ScrollableAreaTest.cpp
index 14084965..bda6b24 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollableAreaTest.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollableAreaTest.cpp
@@ -126,7 +126,7 @@
 {
     OwnPtrWillBeRawPtr<MockScrollableArea> scrollableArea = MockScrollableArea::create(IntPoint(0, 100));
     scrollableArea->setScrollPosition(IntPoint(0, 10000), CompositorScroll);
-    EXPECT_EQ(100.0, scrollableArea->scrollAnimator()->currentPosition().y());
+    EXPECT_EQ(100.0, scrollableArea->scrollAnimator().currentPosition().y());
 }
 
 TEST_F(ScrollableAreaTest, ScrollbarTrackAndThumbRepaint)
diff --git a/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp b/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp
index fefe8750..463961b5e 100644
--- a/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp
+++ b/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp
@@ -50,7 +50,7 @@
     : m_scrollableArea(scrollableArea)
     , m_orientation(orientation)
     , m_controlSize(controlSize)
-    , m_theme(theme)
+    , m_theme(theme ? *theme : ScrollbarTheme::theme())
     , m_visibleSize(0)
     , m_totalSize(0)
     , m_currentPos(0)
@@ -69,15 +69,12 @@
     , m_trackNeedsRepaint(true)
     , m_thumbNeedsRepaint(true)
 {
-    if (!m_theme)
-        m_theme = ScrollbarTheme::theme();
-
-    m_theme->registerScrollbar(this);
+    m_theme.registerScrollbar(*this);
 
     // FIXME: This is ugly and would not be necessary if we fix cross-platform code to actually query for
     // scrollbar thickness and use it when sizing scrollbars (rather than leaving one dimension of the scrollbar
     // alone when sizing).
-    int thickness = m_theme->scrollbarThickness(controlSize);
+    int thickness = m_theme.scrollbarThickness(controlSize);
     Widget::setFrameRect(IntRect(0, 0, thickness, thickness));
 
     m_currentPos = scrollableAreaCurrentPos();
@@ -85,7 +82,7 @@
 
 Scrollbar::~Scrollbar()
 {
-    m_theme->unregisterScrollbar(this);
+    m_theme.unregisterScrollbar(*this);
 }
 
 DEFINE_TRACE(Scrollbar)
@@ -134,11 +131,11 @@
     if (position == m_currentPos)
         return;
 
-    int oldThumbPosition = theme()->thumbPosition(this);
+    int oldThumbPosition = theme().thumbPosition(*this);
     m_currentPos = position;
     updateThumbPosition();
     if (m_pressedPart == ThumbPart)
-        setPressedPos(m_pressedPos + theme()->thumbPosition(this) - oldThumbPosition);
+        setPressedPos(m_pressedPos + theme().thumbPosition(*this) - oldThumbPosition);
 }
 
 void Scrollbar::disconnectFromScrollableArea()
@@ -172,25 +169,25 @@
     updateThumb();
 }
 
-void Scrollbar::paint(GraphicsContext* context, const CullRect& cullRect) const
+void Scrollbar::paint(GraphicsContext& context, const CullRect& cullRect) const
 {
     if (!cullRect.intersectsCullRect(frameRect()))
         return;
 
-    if (!theme()->paint(this, context, cullRect))
+    if (!theme().paint(*this, context, cullRect))
         Widget::paint(context, cullRect);
 }
 
 void Scrollbar::autoscrollTimerFired(Timer<Scrollbar>*)
 {
-    autoscrollPressedPart(theme()->autoscrollTimerDelay());
+    autoscrollPressedPart(theme().autoscrollTimerDelay());
 }
 
-static bool thumbUnderMouse(Scrollbar* scrollbar)
+static bool thumbUnderMouse(Scrollbar& scrollbar)
 {
-    int thumbPos = scrollbar->theme()->trackPosition(scrollbar) + scrollbar->theme()->thumbPosition(scrollbar);
-    int thumbLength = scrollbar->theme()->thumbLength(scrollbar);
-    return scrollbar->pressedPos() >= thumbPos && scrollbar->pressedPos() < thumbPos + thumbLength;
+    int thumbPos = scrollbar.theme().trackPosition(scrollbar) + scrollbar.theme().thumbPosition(scrollbar);
+    int thumbLength = scrollbar.theme().thumbLength(scrollbar);
+    return scrollbar.pressedPos() >= thumbPos && scrollbar.pressedPos() < thumbPos + thumbLength;
 }
 
 void Scrollbar::autoscrollPressedPart(double delay)
@@ -200,7 +197,7 @@
         return;
 
     // Handle the track.
-    if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse(this)) {
+    if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse(*this)) {
         setNeedsPaintInvalidation();
         setHoveredPart(ThumbPart);
         return;
@@ -219,7 +216,7 @@
 
     // Handle the track.  We halt track scrolling once the thumb is level
     // with us.
-    if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse(this)) {
+    if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse(*this)) {
         setNeedsPaintInvalidation();
         setHoveredPart(ThumbPart);
         return;
@@ -275,7 +272,7 @@
         if (m_draggingDocument)
             delta = pos - m_documentDragPos;
         m_draggingDocument = true;
-        FloatPoint currentPosition = m_scrollableArea->scrollAnimator()->currentPosition();
+        FloatPoint currentPosition = m_scrollableArea->scrollAnimator().currentPosition();
         float destinationPosition = (m_orientation == HorizontalScrollbar ? currentPosition.x() : currentPosition.y()) + delta;
         destinationPosition = m_scrollableArea->clampScrollPosition(m_orientation, destinationPosition);
         m_scrollableArea->setScrollPositionSingleAxis(m_orientation, destinationPosition, UserScroll);
@@ -289,9 +286,9 @@
     }
 
     // Drag the thumb.
-    int thumbPos = theme()->thumbPosition(this);
-    int thumbLen = theme()->thumbLength(this);
-    int trackLen = theme()->trackLength(this);
+    int thumbPos = theme().thumbPosition(*this);
+    int thumbLen = theme().thumbLength(*this);
+    int trackLen = theme().trackLength(*this);
     ASSERT(thumbLen <= trackLen);
     if (thumbLen == trackLen)
         return;
@@ -314,7 +311,7 @@
     if (part == m_hoveredPart)
         return;
 
-    if (((m_hoveredPart == NoPart || part == NoPart) && theme()->invalidateOnMouseEnterExit())
+    if (((m_hoveredPart == NoPart || part == NoPart) && theme().invalidateOnMouseEnterExit())
         // When there's a pressed part, we don't draw a hovered state, so there's no reason to invalidate.
         || m_pressedPart == NoPart)
         setNeedsPaintInvalidation();
@@ -335,7 +332,7 @@
 {
     switch (evt.type()) {
     case PlatformEvent::GestureTapDown:
-        setPressedPart(theme()->hitTest(this, evt.position()));
+        setPressedPart(theme().hitTest(*this, evt.position()));
         m_pressedPos = orientation() == HorizontalScrollbar ? convertFromRootFrame(evt.position()).x() : convertFromRootFrame(evt.position()).y();
         return true;
     case PlatformEvent::GestureTapDownCancel:
@@ -376,14 +373,14 @@
 void Scrollbar::mouseMoved(const PlatformMouseEvent& evt)
 {
     if (m_pressedPart == ThumbPart) {
-        if (theme()->shouldSnapBackToDragOrigin(this, evt)) {
+        if (theme().shouldSnapBackToDragOrigin(*this, evt)) {
             if (m_scrollableArea) {
                 m_scrollableArea->setScrollPositionSingleAxis(m_orientation, m_dragOrigin + m_scrollableArea->minimumScrollPosition(m_orientation), UserScroll);
             }
         } else {
             moveThumb(m_orientation == HorizontalScrollbar
                 ? convertFromRootFrame(evt.position()).x()
-                : convertFromRootFrame(evt.position()).y(), theme()->shouldDragDocumentInsteadOfThumb(this, evt));
+                : convertFromRootFrame(evt.position()).y(), theme().shouldDragDocumentInsteadOfThumb(*this, evt));
         }
         return;
     }
@@ -391,13 +388,13 @@
     if (m_pressedPart != NoPart)
         m_pressedPos = orientation() == HorizontalScrollbar ? convertFromRootFrame(evt.position()).x() : convertFromRootFrame(evt.position()).y();
 
-    ScrollbarPart part = theme()->hitTest(this, evt.position());
+    ScrollbarPart part = theme().hitTest(*this, evt.position());
     if (part != m_hoveredPart) {
         if (m_pressedPart != NoPart) {
             if (part == m_pressedPart) {
                 // The mouse is moving back over the pressed part.  We
                 // need to start up the timer action again.
-                startTimerIfNeeded(theme()->autoscrollTimerDelay());
+                startTimerIfNeeded(theme().autoscrollTimerDelay());
                 setNeedsPaintInvalidation();
             } else if (m_hoveredPart == m_pressedPart) {
                 // The mouse is leaving the pressed part.  Kill our timer
@@ -416,13 +413,13 @@
 void Scrollbar::mouseEntered()
 {
     if (m_scrollableArea)
-        m_scrollableArea->mouseEnteredScrollbar(this);
+        m_scrollableArea->mouseEnteredScrollbar(*this);
 }
 
 void Scrollbar::mouseExited()
 {
     if (m_scrollableArea)
-        m_scrollableArea->mouseExitedScrollbar(this);
+        m_scrollableArea->mouseExitedScrollbar(*this);
     setHoveredPart(NoPart);
 }
 
@@ -436,9 +433,9 @@
     if (m_scrollableArea) {
         // m_hoveredPart won't be updated until the next mouseMoved or mouseDown, so we have to hit test
         // to really know if the mouse has exited the scrollbar on a mouseUp.
-        ScrollbarPart part = theme()->hitTest(this, mouseEvent.position());
+        ScrollbarPart part = theme().hitTest(*this, mouseEvent.position());
         if (part == NoPart)
-            m_scrollableArea->mouseExitedScrollbar(this);
+            m_scrollableArea->mouseExitedScrollbar(*this);
     }
 }
 
@@ -448,26 +445,27 @@
     if (evt.button() == RightButton)
         return;
 
-    setPressedPart(theme()->hitTest(this, evt.position()));
+    setPressedPart(theme().hitTest(*this, evt.position()));
     int pressedPos = orientation() == HorizontalScrollbar ? convertFromRootFrame(evt.position()).x() : convertFromRootFrame(evt.position()).y();
 
-    if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && theme()->shouldCenterOnThumb(this, evt)) {
+    if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && theme().shouldCenterOnThumb(*this, evt)) {
         setHoveredPart(ThumbPart);
         setPressedPart(ThumbPart);
         m_dragOrigin = m_currentPos;
-        int thumbLen = theme()->thumbLength(this);
+        int thumbLen = theme().thumbLength(*this);
         int desiredPos = pressedPos;
         // Set the pressed position to the middle of the thumb so that when we do the move, the delta
         // will be from the current pixel position of the thumb to the new desired position for the thumb.
-        m_pressedPos = theme()->trackPosition(this) + theme()->thumbPosition(this) + thumbLen / 2;
+        m_pressedPos = theme().trackPosition(*this) + theme().thumbPosition(*this) + thumbLen / 2;
         moveThumb(desiredPos);
         return;
-    } else if (m_pressedPart == ThumbPart)
+    }
+    if (m_pressedPart == ThumbPart)
         m_dragOrigin = m_currentPos;
 
     m_pressedPos = pressedPos;
 
-    autoscrollPressedPart(theme()->initialAutoscrollTimerDelay());
+    autoscrollPressedPart(theme().initialAutoscrollTimerDelay());
 }
 
 void Scrollbar::visibilityChanged()
@@ -481,13 +479,13 @@
     if (m_enabled == e)
         return;
     m_enabled = e;
-    theme()->updateEnabledState(this);
+    theme().updateEnabledState(*this);
     setNeedsPaintInvalidation();
 }
 
 bool Scrollbar::isOverlayScrollbar() const
 {
-    return m_theme->usesOverlayScrollbars();
+    return m_theme.usesOverlayScrollbars();
 }
 
 bool Scrollbar::shouldParticipateInHitTesting()
@@ -495,7 +493,7 @@
     // Non-overlay scrollbars should always participate in hit testing.
     if (!isOverlayScrollbar())
         return true;
-    return m_scrollableArea->scrollAnimator()->shouldScrollbarParticipateInHitTesting(this);
+    return m_scrollableArea->scrollAnimator().shouldScrollbarParticipateInHitTesting(*this);
 }
 
 // Don't use this method. It will be removed later.
@@ -506,7 +504,7 @@
     // On Snow Leopard, scrollbars need to be invalidated when the window
     // activity changes so that they take on the "inactive" scrollbar
     // appearance. Later OS X releases do not have such an appearance.
-    if (m_theme && m_theme->invalidateOnWindowActiveChange()) {
+    if (m_theme.invalidateOnWindowActiveChange()) {
         ASSERT(IsOSSnowLeopard());
         invalidate();
     }
@@ -521,7 +519,7 @@
 IntRect Scrollbar::convertToContainingWidget(const IntRect& localRect) const
 {
     if (m_scrollableArea)
-        return m_scrollableArea->convertFromScrollbarToContainingWidget(this, localRect);
+        return m_scrollableArea->convertFromScrollbarToContainingWidget(*this, localRect);
 
     return Widget::convertToContainingWidget(localRect);
 }
@@ -529,7 +527,7 @@
 IntRect Scrollbar::convertFromContainingWidget(const IntRect& parentRect) const
 {
     if (m_scrollableArea)
-        return m_scrollableArea->convertFromContainingWidgetToScrollbar(this, parentRect);
+        return m_scrollableArea->convertFromContainingWidgetToScrollbar(*this, parentRect);
 
     return Widget::convertFromContainingWidget(parentRect);
 }
@@ -537,7 +535,7 @@
 IntPoint Scrollbar::convertToContainingWidget(const IntPoint& localPoint) const
 {
     if (m_scrollableArea)
-        return m_scrollableArea->convertFromScrollbarToContainingWidget(this, localPoint);
+        return m_scrollableArea->convertFromScrollbarToContainingWidget(*this, localPoint);
 
     return Widget::convertToContainingWidget(localPoint);
 }
@@ -545,7 +543,7 @@
 IntPoint Scrollbar::convertFromContainingWidget(const IntPoint& parentPoint) const
 {
     if (m_scrollableArea)
-        return m_scrollableArea->convertFromContainingWidgetToScrollbar(this, parentPoint);
+        return m_scrollableArea->convertFromContainingWidgetToScrollbar(*this, parentPoint);
 
     return Widget::convertFromContainingWidget(parentPoint);
 }
@@ -563,12 +561,12 @@
 
 void Scrollbar::setNeedsPaintInvalidation()
 {
-    if (m_theme->shouldRepaintAllPartsOnInvalidation()) {
+    if (m_theme.shouldRepaintAllPartsOnInvalidation()) {
         m_trackNeedsRepaint = true;
         m_thumbNeedsRepaint = true;
     }
     if (m_scrollableArea)
-        m_scrollableArea->setScrollbarNeedsPaintInvalidation(this);
+        m_scrollableArea->setScrollbarNeedsPaintInvalidation(orientation());
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/scroll/Scrollbar.h b/third_party/WebKit/Source/platform/scroll/Scrollbar.h
index 34c9ed1b..3d47eb6 100644
--- a/third_party/WebKit/Source/platform/scroll/Scrollbar.h
+++ b/third_party/WebKit/Source/platform/scroll/Scrollbar.h
@@ -104,7 +104,7 @@
     void setProportion(int visibleSize, int totalSize);
     void setPressedPos(int p) { m_pressedPos = p; }
 
-    void paint(GraphicsContext*, const CullRect&) const final;
+    void paint(GraphicsContext&, const CullRect&) const final;
 
     bool isOverlayScrollbar() const override;
     bool shouldParticipateInHitTesting();
@@ -125,7 +125,7 @@
     void mouseUp(const PlatformMouseEvent&);
     void mouseDown(const PlatformMouseEvent&);
 
-    ScrollbarTheme* theme() const { return m_theme; }
+    ScrollbarTheme& theme() const { return m_theme; }
 
     IntRect convertToContainingWidget(const IntRect&) const override;
     IntRect convertFromContainingWidget(const IntRect&) const override;
@@ -149,8 +149,7 @@
     bool overlapsResizer() const { return m_overlapsResizer; }
     void setOverlapsResizer(bool overlapsResizer) { m_overlapsResizer = overlapsResizer; }
 
-    DisplayItemClient displayItemClient() const override { return toDisplayItemClient(this); }
-    String debugName() const override { return m_orientation == HorizontalScrollbar ? "HorizontalScrollbar" : "VerticalScrollbar"; }
+    String debugName() const final { return m_orientation == HorizontalScrollbar ? "HorizontalScrollbar" : "VerticalScrollbar"; }
 
     void setNeedsPaintInvalidation();
 
@@ -178,7 +177,7 @@
     RawPtrWillBeMember<ScrollableArea> m_scrollableArea;
     ScrollbarOrientation m_orientation;
     ScrollbarControlSize m_controlSize;
-    ScrollbarTheme* m_theme;
+    ScrollbarTheme& m_theme;
 
     int m_visibleSize;
     int m_totalSize;
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarTheme.cpp b/third_party/WebKit/Source/platform/scroll/ScrollbarTheme.cpp
index 06d83b2..7d641481 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarTheme.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarTheme.cpp
@@ -56,7 +56,7 @@
     return (!partRect.isEmpty()) || cullRect.intersectsCullRect(partRect);
 }
 
-bool ScrollbarTheme::paint(const ScrollbarThemeClient* scrollbar, GraphicsContext* graphicsContext, const CullRect& cullRect)
+bool ScrollbarTheme::paint(const ScrollbarThemeClient& scrollbar, GraphicsContext& graphicsContext, const CullRect& cullRect)
 {
     // Create the ScrollbarControlPartMask based on the cullRect
     ScrollbarControlPartMask scrollMask = NoPart;
@@ -130,16 +130,16 @@
     return true;
 }
 
-ScrollbarPart ScrollbarTheme::hitTest(const ScrollbarThemeClient* scrollbar, const IntPoint& positionInRootFrame)
+ScrollbarPart ScrollbarTheme::hitTest(const ScrollbarThemeClient& scrollbar, const IntPoint& positionInRootFrame)
 {
     ScrollbarPart result = NoPart;
-    if (!scrollbar->enabled())
+    if (!scrollbar.enabled())
         return result;
 
-    IntPoint testPosition = scrollbar->convertFromRootFrame(positionInRootFrame);
-    testPosition.move(scrollbar->x(), scrollbar->y());
+    IntPoint testPosition = scrollbar.convertFromRootFrame(positionInRootFrame);
+    testPosition.move(scrollbar.x(), scrollbar.y());
 
-    if (!scrollbar->frameRect().contains(testPosition))
+    if (!scrollbar.frameRect().contains(testPosition))
         return NoPart;
 
     result = ScrollbarBGPart;
@@ -170,57 +170,57 @@
     return result;
 }
 
-void ScrollbarTheme::paintScrollCorner(GraphicsContext* context, const DisplayItemClientWrapper& displayItemClient, const IntRect& cornerRect)
+void ScrollbarTheme::paintScrollCorner(GraphicsContext& context, const DisplayItemClient& displayItemClient, const IntRect& cornerRect)
 {
     if (cornerRect.isEmpty())
         return;
 
-    if (DrawingRecorder::useCachedDrawingIfPossible(*context, displayItemClient, DisplayItem::ScrollbarCorner))
+    if (DrawingRecorder::useCachedDrawingIfPossible(context, displayItemClient, DisplayItem::ScrollbarCorner))
         return;
 
-    DrawingRecorder recorder(*context, displayItemClient, DisplayItem::ScrollbarCorner, cornerRect);
+    DrawingRecorder recorder(context, displayItemClient, DisplayItem::ScrollbarCorner, cornerRect);
 #if OS(MACOSX)
-    context->fillRect(cornerRect, Color::white);
+    context.fillRect(cornerRect, Color::white);
 #else
-    Platform::current()->themeEngine()->paint(context->canvas(), WebThemeEngine::PartScrollbarCorner, WebThemeEngine::StateNormal, WebRect(cornerRect), 0);
+    Platform::current()->themeEngine()->paint(context.canvas(), WebThemeEngine::PartScrollbarCorner, WebThemeEngine::StateNormal, WebRect(cornerRect), 0);
 #endif
 }
 
-bool ScrollbarTheme::shouldCenterOnThumb(const ScrollbarThemeClient* scrollbar, const PlatformMouseEvent& evt)
+bool ScrollbarTheme::shouldCenterOnThumb(const ScrollbarThemeClient& scrollbar, const PlatformMouseEvent& evt)
 {
     return Platform::current()->scrollbarBehavior()->shouldCenterOnThumb(static_cast<WebScrollbarBehavior::Button>(evt.button()), evt.shiftKey(), evt.altKey());
 }
 
-bool ScrollbarTheme::shouldSnapBackToDragOrigin(const ScrollbarThemeClient* scrollbar, const PlatformMouseEvent& evt)
+bool ScrollbarTheme::shouldSnapBackToDragOrigin(const ScrollbarThemeClient& scrollbar, const PlatformMouseEvent& evt)
 {
-    IntPoint mousePosition = scrollbar->convertFromRootFrame(evt.position());
-    mousePosition.move(scrollbar->x(), scrollbar->y());
-    return Platform::current()->scrollbarBehavior()->shouldSnapBackToDragOrigin(mousePosition, trackRect(scrollbar), scrollbar->orientation() == HorizontalScrollbar);
+    IntPoint mousePosition = scrollbar.convertFromRootFrame(evt.position());
+    mousePosition.move(scrollbar.x(), scrollbar.y());
+    return Platform::current()->scrollbarBehavior()->shouldSnapBackToDragOrigin(mousePosition, trackRect(scrollbar), scrollbar.orientation() == HorizontalScrollbar);
 }
 
-int ScrollbarTheme::thumbPosition(const ScrollbarThemeClient* scrollbar)
+int ScrollbarTheme::thumbPosition(const ScrollbarThemeClient& scrollbar)
 {
-    if (scrollbar->enabled()) {
-        float size = scrollbar->totalSize() - scrollbar->visibleSize();
+    if (scrollbar.enabled()) {
+        float size = scrollbar.totalSize() - scrollbar.visibleSize();
         // Avoid doing a floating point divide by zero and return 1 when usedTotalSize == visibleSize.
         if (!size)
             return 0;
-        float pos = std::max(0.0f, scrollbar->currentPos()) * (trackLength(scrollbar) - thumbLength(scrollbar)) / size;
+        float pos = std::max(0.0f, scrollbar.currentPos()) * (trackLength(scrollbar) - thumbLength(scrollbar)) / size;
         return (pos < 1 && pos > 0) ? 1 : pos;
     }
     return 0;
 }
 
-int ScrollbarTheme::thumbLength(const ScrollbarThemeClient* scrollbar)
+int ScrollbarTheme::thumbLength(const ScrollbarThemeClient& scrollbar)
 {
-    if (!scrollbar->enabled())
+    if (!scrollbar.enabled())
         return 0;
 
-    float overhang = fabsf(scrollbar->elasticOverscroll());
+    float overhang = fabsf(scrollbar.elasticOverscroll());
     float proportion = 0.0f;
-    float totalSize = scrollbar->totalSize();
+    float totalSize = scrollbar.totalSize();
     if (totalSize > 0.0f) {
-        proportion = (scrollbar->visibleSize() - overhang) / totalSize;
+        proportion = (scrollbar.visibleSize() - overhang) / totalSize;
     }
     int trackLen = trackLength(scrollbar);
     int length = round(proportion * trackLen);
@@ -230,19 +230,19 @@
     return length;
 }
 
-int ScrollbarTheme::trackPosition(const ScrollbarThemeClient* scrollbar)
+int ScrollbarTheme::trackPosition(const ScrollbarThemeClient& scrollbar)
 {
     IntRect constrainedTrackRect = constrainTrackRectToTrackPieces(scrollbar, trackRect(scrollbar));
-    return (scrollbar->orientation() == HorizontalScrollbar) ? constrainedTrackRect.x() - scrollbar->x() : constrainedTrackRect.y() - scrollbar->y();
+    return (scrollbar.orientation() == HorizontalScrollbar) ? constrainedTrackRect.x() - scrollbar.x() : constrainedTrackRect.y() - scrollbar.y();
 }
 
-int ScrollbarTheme::trackLength(const ScrollbarThemeClient* scrollbar)
+int ScrollbarTheme::trackLength(const ScrollbarThemeClient& scrollbar)
 {
     IntRect constrainedTrackRect = constrainTrackRectToTrackPieces(scrollbar, trackRect(scrollbar));
-    return (scrollbar->orientation() == HorizontalScrollbar) ? constrainedTrackRect.width() : constrainedTrackRect.height();
+    return (scrollbar.orientation() == HorizontalScrollbar) ? constrainedTrackRect.width() : constrainedTrackRect.height();
 }
 
-IntRect ScrollbarTheme::thumbRect(const ScrollbarThemeClient* scrollbar)
+IntRect ScrollbarTheme::thumbRect(const ScrollbarThemeClient& scrollbar)
 {
     if (!hasThumb(scrollbar))
         return IntRect();
@@ -256,44 +256,44 @@
     return thumbRect;
 }
 
-int ScrollbarTheme::thumbThickness(const ScrollbarThemeClient* scrollbar)
+int ScrollbarTheme::thumbThickness(const ScrollbarThemeClient& scrollbar)
 {
     IntRect track = trackRect(scrollbar);
-    return scrollbar->orientation() == HorizontalScrollbar ? track.height() : track.width();
+    return scrollbar.orientation() == HorizontalScrollbar ? track.height() : track.width();
 }
 
-int ScrollbarTheme::minimumThumbLength(const ScrollbarThemeClient* scrollbar)
+int ScrollbarTheme::minimumThumbLength(const ScrollbarThemeClient& scrollbar)
 {
-    return scrollbarThickness(scrollbar->controlSize());
+    return scrollbarThickness(scrollbar.controlSize());
 }
 
-void ScrollbarTheme::splitTrack(const ScrollbarThemeClient* scrollbar, const IntRect& unconstrainedTrackRect, IntRect& beforeThumbRect, IntRect& thumbRect, IntRect& afterThumbRect)
+void ScrollbarTheme::splitTrack(const ScrollbarThemeClient& scrollbar, const IntRect& unconstrainedTrackRect, IntRect& beforeThumbRect, IntRect& thumbRect, IntRect& afterThumbRect)
 {
     // This function won't even get called unless we're big enough to have some combination of these three rects where at least
     // one of them is non-empty.
     IntRect trackRect = constrainTrackRectToTrackPieces(scrollbar, unconstrainedTrackRect);
     int thumbPos = thumbPosition(scrollbar);
-    if (scrollbar->orientation() == HorizontalScrollbar) {
-        thumbRect = IntRect(trackRect.x() + thumbPos, trackRect.y(), thumbLength(scrollbar), scrollbar->height());
+    if (scrollbar.orientation() == HorizontalScrollbar) {
+        thumbRect = IntRect(trackRect.x() + thumbPos, trackRect.y(), thumbLength(scrollbar), scrollbar.height());
         beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), thumbPos + thumbRect.width() / 2, trackRect.height());
         afterThumbRect = IntRect(trackRect.x() + beforeThumbRect.width(), trackRect.y(), trackRect.maxX() - beforeThumbRect.maxX(), trackRect.height());
     } else {
-        thumbRect = IntRect(trackRect.x(), trackRect.y() + thumbPos, scrollbar->width(), thumbLength(scrollbar));
+        thumbRect = IntRect(trackRect.x(), trackRect.y() + thumbPos, scrollbar.width(), thumbLength(scrollbar));
         beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), trackRect.width(), thumbPos + thumbRect.height() / 2);
         afterThumbRect = IntRect(trackRect.x(), trackRect.y() + beforeThumbRect.height(), trackRect.width(), trackRect.maxY() - beforeThumbRect.maxY());
     }
 }
 
-ScrollbarTheme* ScrollbarTheme::theme()
+ScrollbarTheme& ScrollbarTheme::theme()
 {
     if (ScrollbarTheme::mockScrollbarsEnabled()) {
         if (RuntimeEnabledFeatures::overlayScrollbarsEnabled()) {
             DEFINE_STATIC_LOCAL(ScrollbarThemeOverlayMock, overlayMockTheme, ());
-            return &overlayMockTheme;
+            return overlayMockTheme;
         }
 
         DEFINE_STATIC_LOCAL(ScrollbarThemeMock, mockTheme, ());
-        return &mockTheme;
+        return mockTheme;
     }
     return nativeTheme();
 }
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarTheme.h b/third_party/WebKit/Source/platform/scroll/ScrollbarTheme.h
index 560ee0d..8a0ad33 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarTheme.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarTheme.h
@@ -53,11 +53,11 @@
     // Scrollbar::setTrackNeedsRepaint.
     virtual bool shouldRepaintAllPartsOnInvalidation() const { return true; }
 
-    virtual void updateEnabledState(const ScrollbarThemeClient*) { }
+    virtual void updateEnabledState(const ScrollbarThemeClient&) { }
 
-    virtual bool paint(const ScrollbarThemeClient*, GraphicsContext*, const CullRect&);
+    virtual bool paint(const ScrollbarThemeClient&, GraphicsContext&, const CullRect&);
 
-    virtual ScrollbarPart hitTest(const ScrollbarThemeClient*, const IntPoint&);
+    virtual ScrollbarPart hitTest(const ScrollbarThemeClient&, const IntPoint&);
 
     virtual int scrollbarThickness(ScrollbarControlSize = RegularScrollbar) { return 0; }
     virtual int scrollbarMargin() const { return 0; }
@@ -66,61 +66,61 @@
 
     virtual bool supportsControlTints() const { return false; }
     virtual bool usesOverlayScrollbars() const { return false; }
-    virtual void updateScrollbarOverlayStyle(const ScrollbarThemeClient*) { }
+    virtual void updateScrollbarOverlayStyle(const ScrollbarThemeClient&) { }
 
     virtual bool invalidateOnMouseEnterExit() { return false; }
     virtual bool invalidateOnWindowActiveChange() const { return false; }
 
-    virtual void paintScrollCorner(GraphicsContext*, const DisplayItemClientWrapper&, const IntRect& cornerRect);
-    virtual void paintTickmarks(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&) { }
+    virtual void paintScrollCorner(GraphicsContext&, const DisplayItemClient&, const IntRect& cornerRect);
+    virtual void paintTickmarks(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&) { }
 
-    virtual bool shouldCenterOnThumb(const ScrollbarThemeClient*, const PlatformMouseEvent&);
-    virtual bool shouldSnapBackToDragOrigin(const ScrollbarThemeClient*, const PlatformMouseEvent&);
-    virtual bool shouldDragDocumentInsteadOfThumb(const ScrollbarThemeClient*, const PlatformMouseEvent&) { return false; }
+    virtual bool shouldCenterOnThumb(const ScrollbarThemeClient&, const PlatformMouseEvent&);
+    virtual bool shouldSnapBackToDragOrigin(const ScrollbarThemeClient&, const PlatformMouseEvent&);
+    virtual bool shouldDragDocumentInsteadOfThumb(const ScrollbarThemeClient&, const PlatformMouseEvent&) { return false; }
 
     // The position of the thumb relative to the track.
-    virtual int thumbPosition(const ScrollbarThemeClient*);
+    virtual int thumbPosition(const ScrollbarThemeClient&);
     // The length of the thumb along the axis of the scrollbar.
-    virtual int thumbLength(const ScrollbarThemeClient*);
+    virtual int thumbLength(const ScrollbarThemeClient&);
     // The position of the track relative to the scrollbar.
-    virtual int trackPosition(const ScrollbarThemeClient*);
+    virtual int trackPosition(const ScrollbarThemeClient&);
     // The length of the track along the axis of the scrollbar.
-    virtual int trackLength(const ScrollbarThemeClient*);
+    virtual int trackLength(const ScrollbarThemeClient&);
     // The opacity to be applied to the thumb.
-    virtual float thumbOpacity(const ScrollbarThemeClient*) const { return 1.0f; }
+    virtual float thumbOpacity(const ScrollbarThemeClient&) const { return 1.0f; }
 
-    virtual bool hasButtons(const ScrollbarThemeClient*) = 0;
-    virtual bool hasThumb(const ScrollbarThemeClient*) = 0;
+    virtual bool hasButtons(const ScrollbarThemeClient&) = 0;
+    virtual bool hasThumb(const ScrollbarThemeClient&) = 0;
 
-    virtual IntRect backButtonRect(const ScrollbarThemeClient*, ScrollbarPart, bool painting = false) = 0;
-    virtual IntRect forwardButtonRect(const ScrollbarThemeClient*, ScrollbarPart, bool painting = false) = 0;
-    virtual IntRect trackRect(const ScrollbarThemeClient*, bool painting = false) = 0;
-    virtual IntRect thumbRect(const ScrollbarThemeClient*);
-    virtual int thumbThickness(const ScrollbarThemeClient*);
+    virtual IntRect backButtonRect(const ScrollbarThemeClient&, ScrollbarPart, bool painting = false) = 0;
+    virtual IntRect forwardButtonRect(const ScrollbarThemeClient&, ScrollbarPart, bool painting = false) = 0;
+    virtual IntRect trackRect(const ScrollbarThemeClient&, bool painting = false) = 0;
+    virtual IntRect thumbRect(const ScrollbarThemeClient&);
+    virtual int thumbThickness(const ScrollbarThemeClient&);
 
-    virtual int minimumThumbLength(const ScrollbarThemeClient*);
+    virtual int minimumThumbLength(const ScrollbarThemeClient&);
 
-    virtual void splitTrack(const ScrollbarThemeClient*, const IntRect& track, IntRect& startTrack, IntRect& thumb, IntRect& endTrack);
+    virtual void splitTrack(const ScrollbarThemeClient&, const IntRect& track, IntRect& startTrack, IntRect& thumb, IntRect& endTrack);
 
-    virtual void paintScrollbarBackground(GraphicsContext*, const ScrollbarThemeClient*) { }
-    virtual void paintTrackBackground(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&) { }
-    virtual void paintTrackPiece(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&, ScrollbarPart) { }
-    virtual void paintButton(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&, ScrollbarPart) { }
-    virtual void paintThumb(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&) { }
+    virtual void paintScrollbarBackground(GraphicsContext&, const ScrollbarThemeClient&) { }
+    virtual void paintTrackBackground(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&) { }
+    virtual void paintTrackPiece(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&, ScrollbarPart) { }
+    virtual void paintButton(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&, ScrollbarPart) { }
+    virtual void paintThumb(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&) { }
 
     virtual int maxOverlapBetweenPages() { return std::numeric_limits<int>::max(); }
 
     virtual double initialAutoscrollTimerDelay() { return 0.25; }
     virtual double autoscrollTimerDelay() { return 0.05; }
 
-    virtual IntRect constrainTrackRectToTrackPieces(const ScrollbarThemeClient*, const IntRect& rect) { return rect; }
+    virtual IntRect constrainTrackRectToTrackPieces(const ScrollbarThemeClient&, const IntRect& rect) { return rect; }
 
-    virtual void registerScrollbar(ScrollbarThemeClient*) { }
-    virtual void unregisterScrollbar(ScrollbarThemeClient*) { }
+    virtual void registerScrollbar(ScrollbarThemeClient&) { }
+    virtual void unregisterScrollbar(ScrollbarThemeClient&) { }
 
     virtual bool isMockTheme() const { return false; }
 
-    static ScrollbarTheme* theme();
+    static ScrollbarTheme& theme();
 
     static void setMockScrollbarsEnabled(bool flag);
     static bool mockScrollbarsEnabled();
@@ -130,7 +130,7 @@
     static DisplayItem::Type trackPiecePartToDisplayItemType(ScrollbarPart);
 
 private:
-    static ScrollbarTheme* nativeTheme(); // Must be implemented to return the correct theme subclass.
+    static ScrollbarTheme& nativeTheme(); // Must be implemented to return the correct theme subclass.
     static bool gMockScrollbarsEnabled;
 };
 
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAndroid.cpp b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAndroid.cpp
index 1b1dacdc..f41fdb9 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAndroid.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAndroid.cpp
@@ -30,7 +30,7 @@
 
 namespace blink {
 
-ScrollbarTheme* ScrollbarTheme::nativeTheme()
+ScrollbarTheme& ScrollbarTheme::nativeTheme()
 {
     return ScrollbarThemeOverlay::mobileTheme();
 }
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAura.cpp b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAura.cpp
index 1bed9c4..590a5ff 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAura.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAura.cpp
@@ -49,15 +49,15 @@
     return LayoutTestSupport::isRunningLayoutTest();
 }
 
-ScrollbarTheme* ScrollbarTheme::nativeTheme()
+ScrollbarTheme& ScrollbarTheme::nativeTheme()
 {
     if (RuntimeEnabledFeatures::overlayScrollbarsEnabled()) {
         DEFINE_STATIC_LOCAL(ScrollbarThemeOverlay, theme, (10, 0, ScrollbarThemeOverlay::AllowHitTest));
-        return &theme;
+        return theme;
     }
 
     DEFINE_STATIC_LOCAL(ScrollbarThemeAura, theme, ());
-    return &theme;
+    return theme;
 }
 
 int ScrollbarThemeAura::scrollbarThickness(ScrollbarControlSize controlSize)
@@ -70,17 +70,17 @@
     return scrollbarSize.width();
 }
 
-void ScrollbarThemeAura::paintTrackPiece(GraphicsContext* gc, const ScrollbarThemeClient* scrollbar, const IntRect& rect, ScrollbarPart partType)
+void ScrollbarThemeAura::paintTrackPiece(GraphicsContext& gc, const ScrollbarThemeClient& scrollbar, const IntRect& rect, ScrollbarPart partType)
 {
     DisplayItem::Type displayItemType = trackPiecePartToDisplayItemType(partType);
-    if (DrawingRecorder::useCachedDrawingIfPossible(*gc, *scrollbar, displayItemType))
+    if (DrawingRecorder::useCachedDrawingIfPossible(gc, scrollbar, displayItemType))
         return;
 
-    DrawingRecorder recorder(*gc, *scrollbar, displayItemType, rect);
+    DrawingRecorder recorder(gc, scrollbar, displayItemType, rect);
 
-    WebThemeEngine::State state = scrollbar->hoveredPart() == partType ? WebThemeEngine::StateHover : WebThemeEngine::StateNormal;
+    WebThemeEngine::State state = scrollbar.hoveredPart() == partType ? WebThemeEngine::StateHover : WebThemeEngine::StateNormal;
 
-    if (useMockTheme() && !scrollbar->enabled())
+    if (useMockTheme() && !scrollbar.enabled())
         state = WebThemeEngine::StateDisabled;
 
     IntRect alignRect = trackRect(scrollbar, false);
@@ -90,17 +90,17 @@
     extraParams.scrollbarTrack.trackY = alignRect.y();
     extraParams.scrollbarTrack.trackWidth = alignRect.width();
     extraParams.scrollbarTrack.trackHeight = alignRect.height();
-    Platform::current()->themeEngine()->paint(gc->canvas(), scrollbar->orientation() == HorizontalScrollbar ? WebThemeEngine::PartScrollbarHorizontalTrack : WebThemeEngine::PartScrollbarVerticalTrack, state, WebRect(rect), &extraParams);
+    Platform::current()->themeEngine()->paint(gc.canvas(), scrollbar.orientation() == HorizontalScrollbar ? WebThemeEngine::PartScrollbarHorizontalTrack : WebThemeEngine::PartScrollbarVerticalTrack, state, WebRect(rect), &extraParams);
 }
 
-void ScrollbarThemeAura::paintButton(GraphicsContext* gc, const ScrollbarThemeClient* scrollbar, const IntRect& rect, ScrollbarPart part)
+void ScrollbarThemeAura::paintButton(GraphicsContext& gc, const ScrollbarThemeClient& scrollbar, const IntRect& rect, ScrollbarPart part)
 {
     WebThemeEngine::Part paintPart;
     WebThemeEngine::State state = WebThemeEngine::StateNormal;
     bool checkMin = false;
     bool checkMax = false;
 
-    if (scrollbar->orientation() == HorizontalScrollbar) {
+    if (scrollbar.orientation() == HorizontalScrollbar) {
         if (part == BackButtonStartPart) {
             paintPart = WebThemeEngine::PartScrollbarLeftArrow;
             checkMin = true;
@@ -123,58 +123,58 @@
     }
 
     DisplayItem::Type displayItemType = buttonPartToDisplayItemType(part);
-    if (DrawingRecorder::useCachedDrawingIfPossible(*gc, *scrollbar, displayItemType))
+    if (DrawingRecorder::useCachedDrawingIfPossible(gc, scrollbar, displayItemType))
         return;
 
-    DrawingRecorder recorder(*gc, *scrollbar, displayItemType, rect);
+    DrawingRecorder recorder(gc, scrollbar, displayItemType, rect);
 
-    if (useMockTheme() && !scrollbar->enabled()) {
+    if (useMockTheme() && !scrollbar.enabled()) {
         state = WebThemeEngine::StateDisabled;
-    } else if (!useMockTheme() && ((checkMin && (scrollbar->currentPos() <= 0))
-        || (checkMax && scrollbar->currentPos() >= scrollbar->maximum()))) {
+    } else if (!useMockTheme() && ((checkMin && (scrollbar.currentPos() <= 0))
+        || (checkMax && scrollbar.currentPos() >= scrollbar.maximum()))) {
         state = WebThemeEngine::StateDisabled;
     } else {
-        if (part == scrollbar->pressedPart())
+        if (part == scrollbar.pressedPart())
             state = WebThemeEngine::StatePressed;
-        else if (part == scrollbar->hoveredPart())
+        else if (part == scrollbar.hoveredPart())
             state = WebThemeEngine::StateHover;
     }
-    Platform::current()->themeEngine()->paint(gc->canvas(), paintPart, state, WebRect(rect), 0);
+    Platform::current()->themeEngine()->paint(gc.canvas(), paintPart, state, WebRect(rect), 0);
 }
 
-void ScrollbarThemeAura::paintThumb(GraphicsContext* gc, const ScrollbarThemeClient* scrollbar, const IntRect& rect)
+void ScrollbarThemeAura::paintThumb(GraphicsContext& gc, const ScrollbarThemeClient& scrollbar, const IntRect& rect)
 {
-    if (DrawingRecorder::useCachedDrawingIfPossible(*gc, *scrollbar, DisplayItem::ScrollbarThumb))
+    if (DrawingRecorder::useCachedDrawingIfPossible(gc, scrollbar, DisplayItem::ScrollbarThumb))
         return;
 
-    DrawingRecorder recorder(*gc, *scrollbar, DisplayItem::ScrollbarThumb, rect);
+    DrawingRecorder recorder(gc, scrollbar, DisplayItem::ScrollbarThumb, rect);
 
     WebThemeEngine::State state;
-    WebCanvas* canvas = gc->canvas();
-    if (scrollbar->pressedPart() == ThumbPart)
+    WebCanvas* canvas = gc.canvas();
+    if (scrollbar.pressedPart() == ThumbPart)
         state = WebThemeEngine::StatePressed;
-    else if (scrollbar->hoveredPart() == ThumbPart)
+    else if (scrollbar.hoveredPart() == ThumbPart)
         state = WebThemeEngine::StateHover;
     else
         state = WebThemeEngine::StateNormal;
-    Platform::current()->themeEngine()->paint(canvas, scrollbar->orientation() == HorizontalScrollbar ? WebThemeEngine::PartScrollbarHorizontalThumb : WebThemeEngine::PartScrollbarVerticalThumb, state, WebRect(rect), 0);
+    Platform::current()->themeEngine()->paint(canvas, scrollbar.orientation() == HorizontalScrollbar ? WebThemeEngine::PartScrollbarHorizontalThumb : WebThemeEngine::PartScrollbarVerticalThumb, state, WebRect(rect), 0);
 }
 
-IntSize ScrollbarThemeAura::buttonSize(const ScrollbarThemeClient* scrollbar)
+IntSize ScrollbarThemeAura::buttonSize(const ScrollbarThemeClient& scrollbar)
 {
-    if (scrollbar->orientation() == VerticalScrollbar) {
+    if (scrollbar.orientation() == VerticalScrollbar) {
         IntSize size = Platform::current()->themeEngine()->getSize(WebThemeEngine::PartScrollbarUpArrow);
-        return IntSize(size.width(), scrollbar->height() < 2 * size.height() ? scrollbar->height() / 2 : size.height());
+        return IntSize(size.width(), scrollbar.height() < 2 * size.height() ? scrollbar.height() / 2 : size.height());
     }
 
     // HorizontalScrollbar
     IntSize size = Platform::current()->themeEngine()->getSize(WebThemeEngine::PartScrollbarLeftArrow);
-    return IntSize(scrollbar->width() < 2 * size.width() ? scrollbar->width() / 2 : size.width(), size.height());
+    return IntSize(scrollbar.width() < 2 * size.width() ? scrollbar.width() / 2 : size.width(), size.height());
 }
 
-int ScrollbarThemeAura::minimumThumbLength(const ScrollbarThemeClient* scrollbar)
+int ScrollbarThemeAura::minimumThumbLength(const ScrollbarThemeClient& scrollbar)
 {
-    if (scrollbar->orientation() == VerticalScrollbar) {
+    if (scrollbar.orientation() == VerticalScrollbar) {
         IntSize size = Platform::current()->themeEngine()->getSize(WebThemeEngine::PartScrollbarVerticalThumb);
         return size.height();
     }
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAura.h b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAura.h
index 64b641c0..b5ddd4f 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAura.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAura.h
@@ -40,11 +40,11 @@
     int scrollbarThickness(ScrollbarControlSize) override;
 
 protected:
-    void paintTrackPiece(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&, ScrollbarPart) override;
-    void paintButton(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&, ScrollbarPart) override;
-    void paintThumb(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&) override;
-    IntSize buttonSize(const ScrollbarThemeClient*) override;
-    int minimumThumbLength(const ScrollbarThemeClient*) override;
+    void paintTrackPiece(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&, ScrollbarPart) override;
+    void paintButton(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&, ScrollbarPart) override;
+    void paintThumb(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&) override;
+    IntSize buttonSize(const ScrollbarThemeClient&) override;
+    int minimumThumbLength(const ScrollbarThemeClient&) override;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeClient.h b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeClient.h
index 552a1e9..a545944 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeClient.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeClient.h
@@ -39,7 +39,7 @@
 
 class Widget;
 
-class PLATFORM_EXPORT ScrollbarThemeClient {
+class PLATFORM_EXPORT ScrollbarThemeClient : public DisplayItemClient {
 public:
     virtual int x() const = 0;
     virtual int y() const = 0;
@@ -96,9 +96,6 @@
     virtual bool thumbNeedsRepaint() const = 0;
     virtual void setThumbNeedsRepaint(bool) = 0;
 
-    virtual DisplayItemClient displayItemClient() const = 0;
-    virtual String debugName() const = 0;
-
 protected:
     virtual ~ScrollbarThemeClient() { }
 };
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacCommon.h b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacCommon.h
index c412faa..036083b 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacCommon.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacCommon.h
@@ -39,8 +39,8 @@
 public:
     ~ScrollbarThemeMacCommon() override;
 
-    void registerScrollbar(ScrollbarThemeClient*) override;
-    void unregisterScrollbar(ScrollbarThemeClient*) override;
+    void registerScrollbar(ScrollbarThemeClient&) override;
+    void unregisterScrollbar(ScrollbarThemeClient&) override;
     void preferencesChanged(float initialButtonDelay, float autoscrollButtonDelay, NSScrollerStyle preferredScrollerStyle, bool redraw, bool scrollAnimationEnabled, ScrollbarButtonsPlacement);
 
     bool supportsControlTints() const override { return true; }
@@ -48,7 +48,7 @@
     double initialAutoscrollTimerDelay() override;
     double autoscrollTimerDelay() override;
 
-    void paintTickmarks(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&) override;
+    void paintTickmarks(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&) override;
 
     static NSScrollerStyle recommendedScrollerStyle();
 
@@ -59,12 +59,12 @@
 protected:
     int maxOverlapBetweenPages() override { return 40; }
 
-    bool shouldDragDocumentInsteadOfThumb(const ScrollbarThemeClient*, const PlatformMouseEvent&) override;
+    bool shouldDragDocumentInsteadOfThumb(const ScrollbarThemeClient&, const PlatformMouseEvent&) override;
     int scrollbarPartToHIPressedState(ScrollbarPart);
 
     virtual void updateButtonPlacement(ScrollbarButtonsPlacement) {}
 
-    void paintGivenTickmarks(SkCanvas*, const ScrollbarThemeClient*, const IntRect&, const Vector<IntRect>&);
+    void paintGivenTickmarks(SkCanvas*, const ScrollbarThemeClient&, const IntRect&, const Vector<IntRect>&);
 
     RefPtr<Pattern> m_overhangPattern;
 };
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacCommon.mm b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacCommon.mm
index 4ab88e4..b72b1b2 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacCommon.mm
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacCommon.mm
@@ -69,34 +69,31 @@
 static NSScrollerStyle gPreferredScrollerStyle = NSScrollerStyleLegacy;
 static bool gScrollAnimationEnabledForSystem = false;
 
-ScrollbarTheme* ScrollbarTheme::nativeTheme()
+ScrollbarTheme& ScrollbarTheme::nativeTheme()
 {
-    static ScrollbarThemeMacCommon* theme = NULL;
-    if (theme)
-        return theme;
     if (ScrollbarThemeMacCommon::isOverlayAPIAvailable()) {
         DEFINE_STATIC_LOCAL(ScrollbarThemeMacOverlayAPI, overlayTheme, ());
-        theme = &overlayTheme;
-    } else {
-        DEFINE_STATIC_LOCAL(ScrollbarThemeMacNonOverlayAPI, nonOverlayTheme, ());
-        theme = &nonOverlayTheme;
+        return overlayTheme;
     }
-    return theme;
+    {
+        DEFINE_STATIC_LOCAL(ScrollbarThemeMacNonOverlayAPI, nonOverlayTheme, ());
+        return nonOverlayTheme;
+    }
 }
 
-void ScrollbarThemeMacCommon::registerScrollbar(ScrollbarThemeClient* scrollbar)
+void ScrollbarThemeMacCommon::registerScrollbar(ScrollbarThemeClient& scrollbar)
 {
-    scrollbarSet().add(scrollbar);
+    scrollbarSet().add(&scrollbar);
 }
 
-void ScrollbarThemeMacCommon::unregisterScrollbar(ScrollbarThemeClient* scrollbar)
+void ScrollbarThemeMacCommon::unregisterScrollbar(ScrollbarThemeClient& scrollbar)
 {
-    scrollbarSet().remove(scrollbar);
+    scrollbarSet().remove(&scrollbar);
 }
 
-void ScrollbarThemeMacCommon::paintGivenTickmarks(SkCanvas* canvas, const ScrollbarThemeClient* scrollbar, const IntRect& rect, const Vector<IntRect>& tickmarks)
+void ScrollbarThemeMacCommon::paintGivenTickmarks(SkCanvas* canvas, const ScrollbarThemeClient& scrollbar, const IntRect& rect, const Vector<IntRect>& tickmarks)
 {
-    if (scrollbar->orientation() != VerticalScrollbar)
+    if (scrollbar.orientation() != VerticalScrollbar)
         return;
 
     if (rect.height() <= 0 || rect.width() <= 0)
@@ -119,7 +116,7 @@
 
     for (Vector<IntRect>::const_iterator i = tickmarks.begin(); i != tickmarks.end(); ++i) {
         // Calculate how far down (in %) the tick-mark should appear.
-        const float percent = static_cast<float>(i->y()) / scrollbar->totalSize();
+        const float percent = static_cast<float>(i->y()) / scrollbar.totalSize();
         if (percent < 0.0 || percent > 1.0)
             continue;
 
@@ -133,30 +130,30 @@
     }
 }
 
-void ScrollbarThemeMacCommon::paintTickmarks(GraphicsContext* context, const ScrollbarThemeClient* scrollbar, const IntRect& rect)
+void ScrollbarThemeMacCommon::paintTickmarks(GraphicsContext& context, const ScrollbarThemeClient& scrollbar, const IntRect& rect)
 {
     // Note: This is only used for css-styled scrollbars on mac.
-    if (scrollbar->orientation() != VerticalScrollbar)
+    if (scrollbar.orientation() != VerticalScrollbar)
         return;
 
     if (rect.height() <= 0 || rect.width() <= 0)
         return;
 
     Vector<IntRect> tickmarks;
-    scrollbar->getTickmarks(tickmarks);
+    scrollbar.getTickmarks(tickmarks);
     if (!tickmarks.size())
         return;
 
-    if (DrawingRecorder::useCachedDrawingIfPossible(*context, *scrollbar, DisplayItem::ScrollbarTickmarks))
+    if (DrawingRecorder::useCachedDrawingIfPossible(context, scrollbar, DisplayItem::ScrollbarTickmarks))
         return;
 
-    DrawingRecorder recorder(*context, *scrollbar, DisplayItem::ScrollbarTickmarks, rect);
+    DrawingRecorder recorder(context, scrollbar, DisplayItem::ScrollbarTickmarks, rect);
 
     // Inset a bit.
     IntRect tickmarkTrackRect = rect;
     tickmarkTrackRect.setX(tickmarkTrackRect.x() + 1);
     tickmarkTrackRect.setWidth(tickmarkTrackRect.width() - 2);
-    paintGivenTickmarks(context->canvas(), scrollbar, tickmarkTrackRect, tickmarks);
+    paintGivenTickmarks(context.canvas(), scrollbar, tickmarkTrackRect, tickmarks);
 }
 
 ScrollbarThemeMacCommon::~ScrollbarThemeMacCommon()
@@ -201,7 +198,7 @@
     return gAutoscrollButtonDelay;
 }
 
-bool ScrollbarThemeMacCommon::shouldDragDocumentInsteadOfThumb(const ScrollbarThemeClient*, const PlatformMouseEvent& event)
+bool ScrollbarThemeMacCommon::shouldDragDocumentInsteadOfThumb(const ScrollbarThemeClient&, const PlatformMouseEvent& event)
 {
     return event.altKey();
 }
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacNonOverlayAPI.h b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacNonOverlayAPI.h
index 42547296..15d287c29 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacNonOverlayAPI.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacNonOverlayAPI.h
@@ -43,20 +43,20 @@
     bool usesOverlayScrollbars() const override { return false; }
     ScrollbarButtonsPlacement buttonsPlacement() const override;
 
-    bool paint(const ScrollbarThemeClient*, GraphicsContext*, const CullRect&) override;
+    bool paint(const ScrollbarThemeClient&, GraphicsContext&, const CullRect&) override;
     bool invalidateOnWindowActiveChange() const override { return true; }
 
 protected:
-    IntRect trackRect(const ScrollbarThemeClient*, bool painting = false) override;
-    IntRect backButtonRect(const ScrollbarThemeClient*, ScrollbarPart, bool painting = false) override;
-    IntRect forwardButtonRect(const ScrollbarThemeClient*, ScrollbarPart, bool painting = false) override;
+    IntRect trackRect(const ScrollbarThemeClient&, bool painting = false) override;
+    IntRect backButtonRect(const ScrollbarThemeClient&, ScrollbarPart, bool painting = false) override;
+    IntRect forwardButtonRect(const ScrollbarThemeClient&, ScrollbarPart, bool painting = false) override;
 
     void updateButtonPlacement(ScrollbarButtonsPlacement) override;
 
-    bool hasButtons(const ScrollbarThemeClient*) override;
-    bool hasThumb(const ScrollbarThemeClient*) override;
+    bool hasButtons(const ScrollbarThemeClient&) override;
+    bool hasThumb(const ScrollbarThemeClient&) override;
 
-    int minimumThumbLength(const ScrollbarThemeClient*) override;
+    int minimumThumbLength(const ScrollbarThemeClient&) override;
 };
 
 }
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacNonOverlayAPI.mm b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacNonOverlayAPI.mm
index 12770029..7004667 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacNonOverlayAPI.mm
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacNonOverlayAPI.mm
@@ -68,41 +68,41 @@
 //     - drawing using WebThemeEngine functions
 //     - drawing tickmarks
 //     - Skia specific changes
-bool ScrollbarThemeMacNonOverlayAPI::paint(const ScrollbarThemeClient* scrollbar, GraphicsContext* context, const CullRect& cullRect)
+bool ScrollbarThemeMacNonOverlayAPI::paint(const ScrollbarThemeClient& scrollbar, GraphicsContext& context, const CullRect& cullRect)
 {
-    DisplayItem::Type displayItemType = scrollbar->orientation() == HorizontalScrollbar ? DisplayItem::ScrollbarHorizontal : DisplayItem::ScrollbarVertical;
-    if (DrawingRecorder::useCachedDrawingIfPossible(*context, *scrollbar, displayItemType))
+    DisplayItem::Type displayItemType = scrollbar.orientation() == HorizontalScrollbar ? DisplayItem::ScrollbarHorizontal : DisplayItem::ScrollbarVertical;
+    if (DrawingRecorder::useCachedDrawingIfPossible(context, scrollbar, displayItemType))
         return true;
 
-    DrawingRecorder recorder(*context, *scrollbar, displayItemType, scrollbar->frameRect());
+    DrawingRecorder recorder(context, scrollbar, displayItemType, scrollbar.frameRect());
 
     // Get the tickmarks for the frameview.
     Vector<IntRect> tickmarks;
-    scrollbar->getTickmarks(tickmarks);
+    scrollbar.getTickmarks(tickmarks);
 
     HIThemeTrackDrawInfo trackInfo;
     trackInfo.version = 0;
-    trackInfo.kind = scrollbar->controlSize() == RegularScrollbar ? kThemeMediumScrollBar : kThemeSmallScrollBar;
-    trackInfo.bounds = scrollbar->frameRect();
+    trackInfo.kind = scrollbar.controlSize() == RegularScrollbar ? kThemeMediumScrollBar : kThemeSmallScrollBar;
+    trackInfo.bounds = scrollbar.frameRect();
     trackInfo.min = 0;
-    trackInfo.max = scrollbar->maximum();
-    trackInfo.value = scrollbar->currentPos();
-    trackInfo.trackInfo.scrollbar.viewsize = scrollbar->visibleSize();
+    trackInfo.max = scrollbar.maximum();
+    trackInfo.value = scrollbar.currentPos();
+    trackInfo.trackInfo.scrollbar.viewsize = scrollbar.visibleSize();
     trackInfo.attributes = hasThumb(scrollbar) ? kThemeTrackShowThumb : 0;
 
-    if (scrollbar->orientation() == HorizontalScrollbar)
+    if (scrollbar.orientation() == HorizontalScrollbar)
         trackInfo.attributes |= kThemeTrackHorizontal;
 
-    if (!scrollbar->enabled())
+    if (!scrollbar.enabled())
         trackInfo.enableState = kThemeTrackDisabled;
     else
-        trackInfo.enableState = scrollbar->isScrollableAreaActive() ? kThemeTrackActive : kThemeTrackInactive;
+        trackInfo.enableState = scrollbar.isScrollableAreaActive() ? kThemeTrackActive : kThemeTrackInactive;
 
     if (!hasButtons(scrollbar))
         trackInfo.enableState = kThemeTrackNothingToScroll;
-    trackInfo.trackInfo.scrollbar.pressState = scrollbarPartToHIPressedState(scrollbar->pressedPart());
+    trackInfo.trackInfo.scrollbar.pressState = scrollbarPartToHIPressedState(scrollbar.pressedPart());
 
-    SkCanvas* canvas = context->canvas();
+    SkCanvas* canvas = context.canvas();
     CGAffineTransform currentCTM = gfx::SkMatrixToCGAffineTransform(canvas->getTotalMatrix());
 
     // The Aqua scrollbar is buggy when rotated and scaled.  We will just draw into a bitmap if we detect a scale or rotation.
@@ -110,11 +110,11 @@
     OwnPtr<ImageBuffer> imageBuffer;
     SkCanvas* drawingCanvas;
     if (!canDrawDirectly) {
-        trackInfo.bounds = IntRect(IntPoint(), scrollbar->frameRect().size());
+        trackInfo.bounds = IntRect(IntPoint(), scrollbar.frameRect().size());
 
-        IntRect bufferRect(scrollbar->frameRect());
+        IntRect bufferRect(scrollbar.frameRect());
         bufferRect.intersect(cullRect.m_rect);
-        bufferRect.move(-scrollbar->frameRect().x(), -scrollbar->frameRect().y());
+        bufferRect.move(-scrollbar.frameRect().x(), -scrollbar.frameRect().y());
 
         imageBuffer = ImageBuffer::create(bufferRect.size());
         if (!imageBuffer)
@@ -128,8 +128,8 @@
     // Draw the track and its thumb.
     gfx::SkiaBitLocker bitLocker(
         drawingCanvas,
-        ThemeMac::inflateRectForAA(scrollbar->frameRect()),
-        canDrawDirectly ? context->deviceScaleFactor() : 1.0f);
+        ThemeMac::inflateRectForAA(scrollbar.frameRect()),
+        canDrawDirectly ? context.deviceScaleFactor() : 1.0f);
     CGContextRef cgContext = bitLocker.cgContext();
     HIThemeDrawTrack(&trackInfo, 0, cgContext, kHIThemeOrientationNormal);
 
@@ -147,8 +147,8 @@
 
     if (!canDrawDirectly) {
         ASSERT(imageBuffer);
-        if (!context->contextDisabled()) {
-            imageBuffer->draw(context, FloatRect(scrollbar->frameRect().location(), FloatSize(imageBuffer->size())),
+        if (!context.contextDisabled()) {
+            imageBuffer->draw(&context, FloatRect(scrollbar.frameRect().location(), FloatSize(imageBuffer->size())),
                 nullptr, SkXfermode::kSrcOver_Mode);
         }
     }
@@ -166,20 +166,20 @@
     return gButtonPlacement;
 }
 
-bool ScrollbarThemeMacNonOverlayAPI::hasButtons(const ScrollbarThemeClient* scrollbar)
+bool ScrollbarThemeMacNonOverlayAPI::hasButtons(const ScrollbarThemeClient& scrollbar)
 {
-    return scrollbar->enabled() && buttonsPlacement() != ScrollbarButtonsPlacementNone
-             && (scrollbar->orientation() == HorizontalScrollbar
-             ? scrollbar->width()
-             : scrollbar->height()) >= 2 * (cRealButtonLength[scrollbar->controlSize()] - cButtonHitInset[scrollbar->controlSize()]);
+    return scrollbar.enabled() && buttonsPlacement() != ScrollbarButtonsPlacementNone
+             && (scrollbar.orientation() == HorizontalScrollbar
+             ? scrollbar.width()
+             : scrollbar.height()) >= 2 * (cRealButtonLength[scrollbar.controlSize()] - cButtonHitInset[scrollbar.controlSize()]);
 }
 
-bool ScrollbarThemeMacNonOverlayAPI::hasThumb(const ScrollbarThemeClient* scrollbar)
+bool ScrollbarThemeMacNonOverlayAPI::hasThumb(const ScrollbarThemeClient& scrollbar)
 {
-    int minLengthForThumb = 2 * cButtonInset[scrollbar->controlSize()] + cThumbMinLength[scrollbar->controlSize()] + 1;
-    return scrollbar->enabled() && (scrollbar->orientation() == HorizontalScrollbar ?
-             scrollbar->width() :
-             scrollbar->height()) >= minLengthForThumb;
+    int minLengthForThumb = 2 * cButtonInset[scrollbar.controlSize()] + cThumbMinLength[scrollbar.controlSize()] + 1;
+    return scrollbar.enabled() && (scrollbar.orientation() == HorizontalScrollbar ?
+             scrollbar.width() :
+             scrollbar.height()) >= minLengthForThumb;
 }
 
 static IntRect buttonRepaintRect(const IntRect& buttonRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize, bool start)
@@ -200,7 +200,7 @@
     return paintRect;
 }
 
-IntRect ScrollbarThemeMacNonOverlayAPI::backButtonRect(const ScrollbarThemeClient* scrollbar, ScrollbarPart part, bool painting)
+IntRect ScrollbarThemeMacNonOverlayAPI::backButtonRect(const ScrollbarThemeClient& scrollbar, ScrollbarPart part, bool painting)
 {
     IntRect result;
 
@@ -210,31 +210,31 @@
     if (part == BackButtonEndPart && (buttonsPlacement() == ScrollbarButtonsPlacementNone || buttonsPlacement() == ScrollbarButtonsPlacementDoubleStart || buttonsPlacement() == ScrollbarButtonsPlacementSingle))
         return result;
 
-    int thickness = scrollbarThickness(scrollbar->controlSize());
+    int thickness = scrollbarThickness(scrollbar.controlSize());
     bool outerButton = part == BackButtonStartPart && (buttonsPlacement() == ScrollbarButtonsPlacementDoubleStart || buttonsPlacement() == ScrollbarButtonsPlacementDoubleBoth);
     if (outerButton) {
-        if (scrollbar->orientation() == HorizontalScrollbar)
-            result = IntRect(scrollbar->x(), scrollbar->y(), cOuterButtonLength[scrollbar->controlSize()] + (painting ? cOuterButtonOverlap : 0), thickness);
+        if (scrollbar.orientation() == HorizontalScrollbar)
+            result = IntRect(scrollbar.x(), scrollbar.y(), cOuterButtonLength[scrollbar.controlSize()] + (painting ? cOuterButtonOverlap : 0), thickness);
         else
-            result = IntRect(scrollbar->x(), scrollbar->y(), thickness, cOuterButtonLength[scrollbar->controlSize()] + (painting ? cOuterButtonOverlap : 0));
+            result = IntRect(scrollbar.x(), scrollbar.y(), thickness, cOuterButtonLength[scrollbar.controlSize()] + (painting ? cOuterButtonOverlap : 0));
         return result;
     }
 
     // Our repaint rect is slightly larger, since we are a button that is adjacent to the track.
-    if (scrollbar->orientation() == HorizontalScrollbar) {
-        int start = part == BackButtonStartPart ? scrollbar->x() : scrollbar->x() + scrollbar->width() - cOuterButtonLength[scrollbar->controlSize()] - cButtonLength[scrollbar->controlSize()];
-        result = IntRect(start, scrollbar->y(), cButtonLength[scrollbar->controlSize()], thickness);
+    if (scrollbar.orientation() == HorizontalScrollbar) {
+        int start = part == BackButtonStartPart ? scrollbar.x() : scrollbar.x() + scrollbar.width() - cOuterButtonLength[scrollbar.controlSize()] - cButtonLength[scrollbar.controlSize()];
+        result = IntRect(start, scrollbar.y(), cButtonLength[scrollbar.controlSize()], thickness);
     } else {
-        int start = part == BackButtonStartPart ? scrollbar->y() : scrollbar->y() + scrollbar->height() - cOuterButtonLength[scrollbar->controlSize()] - cButtonLength[scrollbar->controlSize()];
-        result = IntRect(scrollbar->x(), start, thickness, cButtonLength[scrollbar->controlSize()]);
+        int start = part == BackButtonStartPart ? scrollbar.y() : scrollbar.y() + scrollbar.height() - cOuterButtonLength[scrollbar.controlSize()] - cButtonLength[scrollbar.controlSize()];
+        result = IntRect(scrollbar.x(), start, thickness, cButtonLength[scrollbar.controlSize()]);
     }
 
     if (painting)
-        return buttonRepaintRect(result, scrollbar->orientation(), scrollbar->controlSize(), part == BackButtonStartPart);
+        return buttonRepaintRect(result, scrollbar.orientation(), scrollbar.controlSize(), part == BackButtonStartPart);
     return result;
 }
 
-IntRect ScrollbarThemeMacNonOverlayAPI::forwardButtonRect(const ScrollbarThemeClient* scrollbar, ScrollbarPart part, bool painting)
+IntRect ScrollbarThemeMacNonOverlayAPI::forwardButtonRect(const ScrollbarThemeClient& scrollbar, ScrollbarPart part, bool painting)
 {
     IntRect result;
 
@@ -244,47 +244,47 @@
     if (part == ForwardButtonStartPart && (buttonsPlacement() == ScrollbarButtonsPlacementNone || buttonsPlacement() == ScrollbarButtonsPlacementDoubleEnd || buttonsPlacement() == ScrollbarButtonsPlacementSingle))
         return result;
 
-    int thickness = scrollbarThickness(scrollbar->controlSize());
-    int outerButtonLength = cOuterButtonLength[scrollbar->controlSize()];
-    int buttonLength = cButtonLength[scrollbar->controlSize()];
+    int thickness = scrollbarThickness(scrollbar.controlSize());
+    int outerButtonLength = cOuterButtonLength[scrollbar.controlSize()];
+    int buttonLength = cButtonLength[scrollbar.controlSize()];
 
     bool outerButton = part == ForwardButtonEndPart && (buttonsPlacement() == ScrollbarButtonsPlacementDoubleEnd || buttonsPlacement() == ScrollbarButtonsPlacementDoubleBoth);
     if (outerButton) {
-        if (scrollbar->orientation() == HorizontalScrollbar) {
-            result = IntRect(scrollbar->x() + scrollbar->width() - outerButtonLength, scrollbar->y(), outerButtonLength, thickness);
+        if (scrollbar.orientation() == HorizontalScrollbar) {
+            result = IntRect(scrollbar.x() + scrollbar.width() - outerButtonLength, scrollbar.y(), outerButtonLength, thickness);
             if (painting)
                 result.inflateX(cOuterButtonOverlap);
         } else {
-            result = IntRect(scrollbar->x(), scrollbar->y() + scrollbar->height() - outerButtonLength, thickness, outerButtonLength);
+            result = IntRect(scrollbar.x(), scrollbar.y() + scrollbar.height() - outerButtonLength, thickness, outerButtonLength);
             if (painting)
                 result.inflateY(cOuterButtonOverlap);
         }
         return result;
     }
 
-    if (scrollbar->orientation() == HorizontalScrollbar) {
-        int start = part == ForwardButtonEndPart ? scrollbar->x() + scrollbar->width() - buttonLength : scrollbar->x() + outerButtonLength;
-        result = IntRect(start, scrollbar->y(), buttonLength, thickness);
+    if (scrollbar.orientation() == HorizontalScrollbar) {
+        int start = part == ForwardButtonEndPart ? scrollbar.x() + scrollbar.width() - buttonLength : scrollbar.x() + outerButtonLength;
+        result = IntRect(start, scrollbar.y(), buttonLength, thickness);
     } else {
-        int start = part == ForwardButtonEndPart ? scrollbar->y() + scrollbar->height() - buttonLength : scrollbar->y() + outerButtonLength;
-        result = IntRect(scrollbar->x(), start, thickness, buttonLength);
+        int start = part == ForwardButtonEndPart ? scrollbar.y() + scrollbar.height() - buttonLength : scrollbar.y() + outerButtonLength;
+        result = IntRect(scrollbar.x(), start, thickness, buttonLength);
     }
     if (painting)
-        return buttonRepaintRect(result, scrollbar->orientation(), scrollbar->controlSize(), part == ForwardButtonStartPart);
+        return buttonRepaintRect(result, scrollbar.orientation(), scrollbar.controlSize(), part == ForwardButtonStartPart);
     return result;
 }
 
-IntRect ScrollbarThemeMacNonOverlayAPI::trackRect(const ScrollbarThemeClient* scrollbar, bool painting)
+IntRect ScrollbarThemeMacNonOverlayAPI::trackRect(const ScrollbarThemeClient& scrollbar, bool painting)
 {
     if (painting || !hasButtons(scrollbar))
-        return scrollbar->frameRect();
+        return scrollbar.frameRect();
 
     IntRect result;
-    int thickness = scrollbarThickness(scrollbar->controlSize());
+    int thickness = scrollbarThickness(scrollbar.controlSize());
     int startWidth = 0;
     int endWidth = 0;
-    int outerButtonLength = cOuterButtonLength[scrollbar->controlSize()];
-    int buttonLength = cButtonLength[scrollbar->controlSize()];
+    int outerButtonLength = cOuterButtonLength[scrollbar.controlSize()];
+    int buttonLength = cButtonLength[scrollbar.controlSize()];
     int doubleButtonLength = outerButtonLength + buttonLength;
     switch (buttonsPlacement()) {
         case ScrollbarButtonsPlacementSingle:
@@ -306,14 +306,14 @@
     }
 
     int totalWidth = startWidth + endWidth;
-    if (scrollbar->orientation() == HorizontalScrollbar)
-        return IntRect(scrollbar->x() + startWidth, scrollbar->y(), scrollbar->width() - totalWidth, thickness);
-    return IntRect(scrollbar->x(), scrollbar->y() + startWidth, thickness, scrollbar->height() - totalWidth);
+    if (scrollbar.orientation() == HorizontalScrollbar)
+        return IntRect(scrollbar.x() + startWidth, scrollbar.y(), scrollbar.width() - totalWidth, thickness);
+    return IntRect(scrollbar.x(), scrollbar.y() + startWidth, thickness, scrollbar.height() - totalWidth);
 }
 
-int ScrollbarThemeMacNonOverlayAPI::minimumThumbLength(const ScrollbarThemeClient* scrollbar)
+int ScrollbarThemeMacNonOverlayAPI::minimumThumbLength(const ScrollbarThemeClient& scrollbar)
 {
-    return cThumbMinLength[scrollbar->controlSize()];
+    return cThumbMinLength[scrollbar.controlSize()];
 }
 
 }
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacOverlayAPI.h b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacOverlayAPI.h
index d74d840..d4c62a6 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacOverlayAPI.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacOverlayAPI.h
@@ -40,32 +40,32 @@
 class PLATFORM_EXPORT ScrollbarThemeMacOverlayAPI : public ScrollbarThemeMacCommon {
 public:
     bool shouldRepaintAllPartsOnInvalidation() const override { return false; }
-    void updateEnabledState(const ScrollbarThemeClient*) override;
+    void updateEnabledState(const ScrollbarThemeClient&) override;
     int scrollbarThickness(ScrollbarControlSize = RegularScrollbar) override;
     bool usesOverlayScrollbars() const override;
-    void updateScrollbarOverlayStyle(const ScrollbarThemeClient*) override;
+    void updateScrollbarOverlayStyle(const ScrollbarThemeClient&) override;
     ScrollbarButtonsPlacement buttonsPlacement() const override;
 
-    void registerScrollbar(ScrollbarThemeClient*) override;
-    void unregisterScrollbar(ScrollbarThemeClient*) override;
+    void registerScrollbar(ScrollbarThemeClient&) override;
+    void unregisterScrollbar(ScrollbarThemeClient&) override;
 
-    void setNewPainterForScrollbar(ScrollbarThemeClient*, ScrollbarPainter);
-    ScrollbarPainter painterForScrollbar(const ScrollbarThemeClient*) const;
+    void setNewPainterForScrollbar(ScrollbarThemeClient&, ScrollbarPainter);
+    ScrollbarPainter painterForScrollbar(const ScrollbarThemeClient&) const;
 
-    void paintTrackBackground(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&) override;
-    void paintThumb(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&) override;
+    void paintTrackBackground(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&) override;
+    void paintThumb(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&) override;
 
-    float thumbOpacity(const ScrollbarThemeClient*) const override;
+    float thumbOpacity(const ScrollbarThemeClient&) const override;
 
 protected:
-    IntRect trackRect(const ScrollbarThemeClient*, bool painting = false) override;
-    IntRect backButtonRect(const ScrollbarThemeClient*, ScrollbarPart, bool painting = false) override;
-    IntRect forwardButtonRect(const ScrollbarThemeClient*, ScrollbarPart, bool painting = false) override;
+    IntRect trackRect(const ScrollbarThemeClient&, bool painting = false) override;
+    IntRect backButtonRect(const ScrollbarThemeClient&, ScrollbarPart, bool painting = false) override;
+    IntRect forwardButtonRect(const ScrollbarThemeClient&, ScrollbarPart, bool painting = false) override;
 
-    bool hasButtons(const ScrollbarThemeClient*) override { return false; }
-    bool hasThumb(const ScrollbarThemeClient*) override;
+    bool hasButtons(const ScrollbarThemeClient&) override { return false; }
+    bool hasThumb(const ScrollbarThemeClient&) override;
 
-    int minimumThumbLength(const ScrollbarThemeClient*) override;
+    int minimumThumbLength(const ScrollbarThemeClient&) override;
 };
 
 }
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacOverlayAPI.mm b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacOverlayAPI.mm
index 91d5131..45df5b1 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacOverlayAPI.mm
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacOverlayAPI.mm
@@ -92,10 +92,10 @@
 
 typedef HashMap<ScrollbarThemeClient*, RetainPtr<WebCoreScrollbarObserver> > ScrollbarPainterMap;
 
-static ScrollbarPainterMap* scrollbarPainterMap()
+static ScrollbarPainterMap& scrollbarPainterMap()
 {
     static ScrollbarPainterMap* map = new ScrollbarPainterMap;
-    return map;
+    return *map;
 }
 
 static bool supportsExpandedScrollbars()
@@ -105,76 +105,76 @@
     return globalSupportsExpandedScrollbars;
 }
 
-void ScrollbarThemeMacOverlayAPI::registerScrollbar(ScrollbarThemeClient* scrollbar)
+void ScrollbarThemeMacOverlayAPI::registerScrollbar(ScrollbarThemeClient& scrollbar)
 {
     ScrollbarThemeMacCommon::registerScrollbar(scrollbar);
 
-    bool isHorizontal = scrollbar->orientation() == HorizontalScrollbar;
-    ScrollbarPainter scrollbarPainter = [NSClassFromString(@"NSScrollerImp") scrollerImpWithStyle:recommendedScrollerStyle() controlSize:(NSControlSize)scrollbar->controlSize() horizontal:isHorizontal replacingScrollerImp:nil];
-    RetainPtr<WebCoreScrollbarObserver> observer = [[WebCoreScrollbarObserver alloc] initWithScrollbar:scrollbar painter:scrollbarPainter];
+    bool isHorizontal = scrollbar.orientation() == HorizontalScrollbar;
+    ScrollbarPainter scrollbarPainter = [NSClassFromString(@"NSScrollerImp") scrollerImpWithStyle:recommendedScrollerStyle() controlSize:(NSControlSize)scrollbar.controlSize() horizontal:isHorizontal replacingScrollerImp:nil];
+    RetainPtr<WebCoreScrollbarObserver> observer = [[WebCoreScrollbarObserver alloc] initWithScrollbar:&scrollbar painter:scrollbarPainter];
 
-    scrollbarPainterMap()->add(scrollbar, observer);
+    scrollbarPainterMap().add(&scrollbar, observer);
     updateEnabledState(scrollbar);
     updateScrollbarOverlayStyle(scrollbar);
 }
 
-void ScrollbarThemeMacOverlayAPI::unregisterScrollbar(ScrollbarThemeClient* scrollbar)
+void ScrollbarThemeMacOverlayAPI::unregisterScrollbar(ScrollbarThemeClient& scrollbar)
 {
-    scrollbarPainterMap()->remove(scrollbar);
+    scrollbarPainterMap().remove(&scrollbar);
 
     ScrollbarThemeMacCommon::unregisterScrollbar(scrollbar);
 }
 
-void ScrollbarThemeMacOverlayAPI::setNewPainterForScrollbar(ScrollbarThemeClient* scrollbar, ScrollbarPainter newPainter)
+void ScrollbarThemeMacOverlayAPI::setNewPainterForScrollbar(ScrollbarThemeClient& scrollbar, ScrollbarPainter newPainter)
 {
-    RetainPtr<WebCoreScrollbarObserver> observer = [[WebCoreScrollbarObserver alloc] initWithScrollbar:scrollbar painter:newPainter];
-    scrollbarPainterMap()->set(scrollbar, observer);
+    RetainPtr<WebCoreScrollbarObserver> observer = [[WebCoreScrollbarObserver alloc] initWithScrollbar:&scrollbar painter:newPainter];
+    scrollbarPainterMap().set(&scrollbar, observer);
     updateEnabledState(scrollbar);
     updateScrollbarOverlayStyle(scrollbar);
 }
 
-ScrollbarPainter ScrollbarThemeMacOverlayAPI::painterForScrollbar(const ScrollbarThemeClient* scrollbar) const
+ScrollbarPainter ScrollbarThemeMacOverlayAPI::painterForScrollbar(const ScrollbarThemeClient& scrollbar) const
 {
-    return [scrollbarPainterMap()->get(const_cast<ScrollbarThemeClient*>(scrollbar)).get() painter];
+    return [scrollbarPainterMap().get(const_cast<ScrollbarThemeClient*>(&scrollbar)).get() painter];
 }
 
-void ScrollbarThemeMacOverlayAPI::paintTrackBackground(GraphicsContext* context, const ScrollbarThemeClient* scrollbar, const IntRect& rect) {
-    if (DrawingRecorder::useCachedDrawingIfPossible(*context, *scrollbar, DisplayItem::ScrollbarTrackBackground))
+void ScrollbarThemeMacOverlayAPI::paintTrackBackground(GraphicsContext& context, const ScrollbarThemeClient& scrollbar, const IntRect& rect) {
+    if (DrawingRecorder::useCachedDrawingIfPossible(context, scrollbar, DisplayItem::ScrollbarTrackBackground))
         return;
 
-    DrawingRecorder recorder(*context, *scrollbar, DisplayItem::ScrollbarTrackBackground, rect);
+    DrawingRecorder recorder(context, scrollbar, DisplayItem::ScrollbarTrackBackground, rect);
 
     ASSERT(isOverlayAPIAvailable());
 
-    GraphicsContextStateSaver stateSaver(*context);
-    context->translate(rect.x(), rect.y());
-    LocalCurrentGraphicsContext localContext(context, IntRect(IntPoint(), rect.size()));
+    GraphicsContextStateSaver stateSaver(context);
+    context.translate(rect.x(), rect.y());
+    LocalCurrentGraphicsContext localContext(&context, IntRect(IntPoint(), rect.size()));
 
-    CGRect frameRect = scrollbar->frameRect();
+    CGRect frameRect = scrollbar.frameRect();
     ScrollbarPainter scrollbarPainter = painterForScrollbar(scrollbar);
-    [scrollbarPainter setEnabled:scrollbar->enabled()];
+    [scrollbarPainter setEnabled:scrollbar.enabled()];
     [scrollbarPainter setBoundsSize: NSSizeFromCGSize(frameRect.size)];
     NSRect trackRect = NSMakeRect(0, 0, frameRect.size.width, frameRect.size.height);
     [scrollbarPainter drawKnobSlotInRect:trackRect highlight:NO];
 }
 
-void ScrollbarThemeMacOverlayAPI::paintThumb(GraphicsContext* context, const ScrollbarThemeClient* scrollbar, const IntRect& rect) {
-    if (DrawingRecorder::useCachedDrawingIfPossible(*context, *scrollbar, DisplayItem::ScrollbarThumb))
+void ScrollbarThemeMacOverlayAPI::paintThumb(GraphicsContext& context, const ScrollbarThemeClient& scrollbar, const IntRect& rect) {
+    if (DrawingRecorder::useCachedDrawingIfPossible(context, scrollbar, DisplayItem::ScrollbarThumb))
         return;
 
     // Expand dirty rect to allow for scroll thumb anti-aliasing in minimum thumb size case.
     IntRect dirtyRect = IntRect(rect);
     dirtyRect.inflate(1);
-    DrawingRecorder recorder(*context, *scrollbar, DisplayItem::ScrollbarThumb, dirtyRect);
+    DrawingRecorder recorder(context, scrollbar, DisplayItem::ScrollbarThumb, dirtyRect);
 
     ASSERT(isOverlayAPIAvailable());
 
-    GraphicsContextStateSaver stateSaver(*context);
-    context->translate(rect.x(), rect.y());
-    LocalCurrentGraphicsContext localContext(context, IntRect(IntPoint(), rect.size()));
+    GraphicsContextStateSaver stateSaver(context);
+    context.translate(rect.x(), rect.y());
+    LocalCurrentGraphicsContext localContext(&context, IntRect(IntPoint(), rect.size()));
 
     ScrollbarPainter scrollbarPainter = painterForScrollbar(scrollbar);
-    [scrollbarPainter setEnabled:scrollbar->enabled()];
+    [scrollbarPainter setEnabled:scrollbar.enabled()];
     [scrollbarPainter setBoundsSize:NSSizeFromCGSize(rect.size())];
     [scrollbarPainter setDoubleValue:0];
     [scrollbarPainter setKnobProportion:1];
@@ -182,12 +182,12 @@
     CGFloat oldKnobAlpha = [scrollbarPainter knobAlpha];
     [scrollbarPainter setKnobAlpha:1];
 
-    if (scrollbar->enabled())
+    if (scrollbar.enabled())
         [scrollbarPainter drawKnob];
 
     // If this state is not set, then moving the cursor over the scrollbar area will only cause the
     // scrollbar to engorge when moved over the top of the scrollbar area.
-    [scrollbarPainter setBoundsSize: NSSizeFromCGSize(scrollbar->frameRect().size())];
+    [scrollbarPainter setBoundsSize: NSSizeFromCGSize(scrollbar.frameRect().size())];
     [scrollbarPainter setKnobAlpha:oldKnobAlpha];
 }
 
@@ -211,10 +211,10 @@
     return recommendedScrollerStyle() == NSScrollerStyleOverlay;
 }
 
-void ScrollbarThemeMacOverlayAPI::updateScrollbarOverlayStyle(const ScrollbarThemeClient* scrollbar)
+void ScrollbarThemeMacOverlayAPI::updateScrollbarOverlayStyle(const ScrollbarThemeClient& scrollbar)
 {
     ScrollbarPainter painter = painterForScrollbar(scrollbar);
-    switch (scrollbar->scrollbarOverlayStyle()) {
+    switch (scrollbar.scrollbarOverlayStyle()) {
     case ScrollbarOverlayStyleDefault:
         [painter setKnobStyle:NSScrollerKnobStyleDefault];
         break;
@@ -232,45 +232,45 @@
     return ScrollbarButtonsPlacementNone;
 }
 
-bool ScrollbarThemeMacOverlayAPI::hasThumb(const ScrollbarThemeClient* scrollbar)
+bool ScrollbarThemeMacOverlayAPI::hasThumb(const ScrollbarThemeClient& scrollbar)
 {
     ScrollbarPainter painter = painterForScrollbar(scrollbar);
     int minLengthForThumb = [painter knobMinLength] + [painter trackOverlapEndInset] + [painter knobOverlapEndInset]
         + 2 * ([painter trackEndInset] + [painter knobEndInset]);
-    return scrollbar->enabled() && (scrollbar->orientation() == HorizontalScrollbar ?
-             scrollbar->width() :
-             scrollbar->height()) >= minLengthForThumb;
+    return scrollbar.enabled() && (scrollbar.orientation() == HorizontalScrollbar ?
+             scrollbar.width() :
+             scrollbar.height()) >= minLengthForThumb;
 }
 
-IntRect ScrollbarThemeMacOverlayAPI::backButtonRect(const ScrollbarThemeClient* scrollbar, ScrollbarPart part, bool painting)
+IntRect ScrollbarThemeMacOverlayAPI::backButtonRect(const ScrollbarThemeClient& scrollbar, ScrollbarPart part, bool painting)
 {
     ASSERT(buttonsPlacement() == ScrollbarButtonsPlacementNone);
     return IntRect();
 }
 
-IntRect ScrollbarThemeMacOverlayAPI::forwardButtonRect(const ScrollbarThemeClient* scrollbar, ScrollbarPart part, bool painting)
+IntRect ScrollbarThemeMacOverlayAPI::forwardButtonRect(const ScrollbarThemeClient& scrollbar, ScrollbarPart part, bool painting)
 {
     ASSERT(buttonsPlacement() == ScrollbarButtonsPlacementNone);
     return IntRect();
 }
 
-IntRect ScrollbarThemeMacOverlayAPI::trackRect(const ScrollbarThemeClient* scrollbar, bool painting)
+IntRect ScrollbarThemeMacOverlayAPI::trackRect(const ScrollbarThemeClient& scrollbar, bool painting)
 {
     ASSERT(!hasButtons(scrollbar));
-    return scrollbar->frameRect();
+    return scrollbar.frameRect();
 }
 
-int ScrollbarThemeMacOverlayAPI::minimumThumbLength(const ScrollbarThemeClient* scrollbar)
+int ScrollbarThemeMacOverlayAPI::minimumThumbLength(const ScrollbarThemeClient& scrollbar)
 {
     return [painterForScrollbar(scrollbar) knobMinLength];
 }
 
-void ScrollbarThemeMacOverlayAPI::updateEnabledState(const ScrollbarThemeClient* scrollbar)
+void ScrollbarThemeMacOverlayAPI::updateEnabledState(const ScrollbarThemeClient& scrollbar)
 {
-    [painterForScrollbar(scrollbar) setEnabled:scrollbar->enabled()];
+    [painterForScrollbar(scrollbar) setEnabled:scrollbar.enabled()];
 }
 
-float ScrollbarThemeMacOverlayAPI::thumbOpacity(const ScrollbarThemeClient* scrollbar) const {
+float ScrollbarThemeMacOverlayAPI::thumbOpacity(const ScrollbarThemeClient& scrollbar) const {
     ScrollbarPainter scrollbarPainter = painterForScrollbar(scrollbar);
     return [scrollbarPainter knobAlpha];
 }
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMock.cpp b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMock.cpp
index 4007cbb6..8a7d2d9 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMock.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMock.cpp
@@ -57,31 +57,30 @@
     return gShouldRepaintAllPartsOnInvalidation;
 }
 
-IntRect ScrollbarThemeMock::trackRect(const ScrollbarThemeClient* scrollbar, bool)
+IntRect ScrollbarThemeMock::trackRect(const ScrollbarThemeClient& scrollbar, bool)
 {
-    return scrollbar->frameRect();
+    return scrollbar.frameRect();
 }
 
-
-void ScrollbarThemeMock::paintTrackBackground(GraphicsContext* context, const ScrollbarThemeClient* scrollbar, const IntRect& trackRect)
+void ScrollbarThemeMock::paintTrackBackground(GraphicsContext& context, const ScrollbarThemeClient& scrollbar, const IntRect& trackRect)
 {
-    if (DrawingRecorder::useCachedDrawingIfPossible(*context, *scrollbar, DisplayItem::ScrollbarTrackBackground))
+    if (DrawingRecorder::useCachedDrawingIfPossible(context, scrollbar, DisplayItem::ScrollbarTrackBackground))
         return;
 
-    DrawingRecorder recorder(*context, *scrollbar, DisplayItem::ScrollbarTrackBackground, trackRect);
-    context->fillRect(trackRect, scrollbar->enabled() ? Color::lightGray : Color(0xFFE0E0E0));
+    DrawingRecorder recorder(context, scrollbar, DisplayItem::ScrollbarTrackBackground, trackRect);
+    context.fillRect(trackRect, scrollbar.enabled() ? Color::lightGray : Color(0xFFE0E0E0));
 }
 
-void ScrollbarThemeMock::paintThumb(GraphicsContext* context, const ScrollbarThemeClient* scrollbar, const IntRect& thumbRect)
+void ScrollbarThemeMock::paintThumb(GraphicsContext& context, const ScrollbarThemeClient& scrollbar, const IntRect& thumbRect)
 {
-    if (!scrollbar->enabled())
+    if (!scrollbar.enabled())
         return;
 
-    if (DrawingRecorder::useCachedDrawingIfPossible(*context, *scrollbar, DisplayItem::ScrollbarThumb))
+    if (DrawingRecorder::useCachedDrawingIfPossible(context, scrollbar, DisplayItem::ScrollbarThumb))
         return;
 
-    DrawingRecorder recorder(*context, *scrollbar, DisplayItem::ScrollbarThumb, thumbRect);
-    context->fillRect(thumbRect, Color::darkGray);
+    DrawingRecorder recorder(context, scrollbar, DisplayItem::ScrollbarThumb, thumbRect);
+    context.fillRect(thumbRect, Color::darkGray);
 }
 
 }
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMock.h b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMock.h
index f14f4b5..6d752e3 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMock.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMock.h
@@ -40,15 +40,15 @@
 
 protected:
     bool shouldRepaintAllPartsOnInvalidation() const override;
-    bool hasButtons(const ScrollbarThemeClient*) override { return false; }
-    bool hasThumb(const ScrollbarThemeClient*) override { return true; }
+    bool hasButtons(const ScrollbarThemeClient&) override { return false; }
+    bool hasThumb(const ScrollbarThemeClient&) override { return true; }
 
-    IntRect backButtonRect(const ScrollbarThemeClient*, ScrollbarPart, bool /*painting*/ = false) override { return IntRect(); }
-    IntRect forwardButtonRect(const ScrollbarThemeClient*, ScrollbarPart, bool /*painting*/ = false) override { return IntRect(); }
-    IntRect trackRect(const ScrollbarThemeClient*, bool painting = false) override;
+    IntRect backButtonRect(const ScrollbarThemeClient&, ScrollbarPart, bool /*painting*/ = false) override { return IntRect(); }
+    IntRect forwardButtonRect(const ScrollbarThemeClient&, ScrollbarPart, bool /*painting*/ = false) override { return IntRect(); }
+    IntRect trackRect(const ScrollbarThemeClient&, bool painting = false) override;
 
-    void paintTrackBackground(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&) override;
-    void paintThumb(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&) override;
+    void paintTrackBackground(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&) override;
+    void paintThumb(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&) override;
 
 private:
     bool isMockTheme() const final { return true; }
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeNonMacCommon.cpp b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeNonMacCommon.cpp
index 0a5e43b..0a55ef8 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeNonMacCommon.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeNonMacCommon.cpp
@@ -35,24 +35,24 @@
 
 namespace blink {
 
-bool ScrollbarThemeNonMacCommon::hasThumb(const ScrollbarThemeClient* scrollbar)
+bool ScrollbarThemeNonMacCommon::hasThumb(const ScrollbarThemeClient& scrollbar)
 {
     // This method is just called as a paint-time optimization to see if
     // painting the thumb can be skipped. We don't have to be exact here.
     return thumbLength(scrollbar) > 0;
 }
 
-IntRect ScrollbarThemeNonMacCommon::backButtonRect(const ScrollbarThemeClient* scrollbar, ScrollbarPart part, bool)
+IntRect ScrollbarThemeNonMacCommon::backButtonRect(const ScrollbarThemeClient& scrollbar, ScrollbarPart part, bool)
 {
     // Windows and Linux just have single arrows.
     if (part == BackButtonEndPart)
         return IntRect();
 
     IntSize size = buttonSize(scrollbar);
-    return IntRect(scrollbar->x(), scrollbar->y(), size.width(), size.height());
+    return IntRect(scrollbar.x(), scrollbar.y(), size.width(), size.height());
 }
 
-IntRect ScrollbarThemeNonMacCommon::forwardButtonRect(const ScrollbarThemeClient* scrollbar, ScrollbarPart part, bool)
+IntRect ScrollbarThemeNonMacCommon::forwardButtonRect(const ScrollbarThemeClient& scrollbar, ScrollbarPart part, bool)
 {
     // Windows and Linux just have single arrows.
     if (part == ForwardButtonStartPart)
@@ -60,41 +60,41 @@
 
     IntSize size = buttonSize(scrollbar);
     int x, y;
-    if (scrollbar->orientation() == HorizontalScrollbar) {
-        x = scrollbar->x() + scrollbar->width() - size.width();
-        y = scrollbar->y();
+    if (scrollbar.orientation() == HorizontalScrollbar) {
+        x = scrollbar.x() + scrollbar.width() - size.width();
+        y = scrollbar.y();
     } else {
-        x = scrollbar->x();
-        y = scrollbar->y() + scrollbar->height() - size.height();
+        x = scrollbar.x();
+        y = scrollbar.y() + scrollbar.height() - size.height();
     }
     return IntRect(x, y, size.width(), size.height());
 }
 
-IntRect ScrollbarThemeNonMacCommon::trackRect(const ScrollbarThemeClient* scrollbar, bool)
+IntRect ScrollbarThemeNonMacCommon::trackRect(const ScrollbarThemeClient& scrollbar, bool)
 {
     // The track occupies all space between the two buttons.
     IntSize bs = buttonSize(scrollbar);
-    int thickness = scrollbarThickness(scrollbar->controlSize());
-    if (scrollbar->orientation() == HorizontalScrollbar) {
-        if (scrollbar->width() <= 2 * bs.width())
+    int thickness = scrollbarThickness(scrollbar.controlSize());
+    if (scrollbar.orientation() == HorizontalScrollbar) {
+        if (scrollbar.width() <= 2 * bs.width())
             return IntRect();
-        return IntRect(scrollbar->x() + bs.width(), scrollbar->y(), scrollbar->width() - 2 * bs.width(), thickness);
+        return IntRect(scrollbar.x() + bs.width(), scrollbar.y(), scrollbar.width() - 2 * bs.width(), thickness);
     }
-    if (scrollbar->height() <= 2 * bs.height())
+    if (scrollbar.height() <= 2 * bs.height())
         return IntRect();
-    return IntRect(scrollbar->x(), scrollbar->y() + bs.height(), thickness, scrollbar->height() - 2 * bs.height());
+    return IntRect(scrollbar.x(), scrollbar.y() + bs.height(), thickness, scrollbar.height() - 2 * bs.height());
 }
 
-void ScrollbarThemeNonMacCommon::paintTrackBackground(GraphicsContext* context, const ScrollbarThemeClient* scrollbar, const IntRect& rect)
+void ScrollbarThemeNonMacCommon::paintTrackBackground(GraphicsContext& context, const ScrollbarThemeClient& scrollbar, const IntRect& rect)
 {
     // Just assume a forward track part. We only paint the track as a single piece when there is no thumb.
     if (!hasThumb(scrollbar))
         paintTrackPiece(context, scrollbar, rect, ForwardTrackPart);
 }
 
-void ScrollbarThemeNonMacCommon::paintTickmarks(GraphicsContext* context, const ScrollbarThemeClient* scrollbar, const IntRect& rect)
+void ScrollbarThemeNonMacCommon::paintTickmarks(GraphicsContext& context, const ScrollbarThemeClient& scrollbar, const IntRect& rect)
 {
-    if (scrollbar->orientation() != VerticalScrollbar)
+    if (scrollbar.orientation() != VerticalScrollbar)
         return;
 
     if (rect.height() <= 0 || rect.width() <= 0)
@@ -102,29 +102,29 @@
 
     // Get the tickmarks for the frameview.
     Vector<IntRect> tickmarks;
-    scrollbar->getTickmarks(tickmarks);
+    scrollbar.getTickmarks(tickmarks);
     if (!tickmarks.size())
         return;
 
-    if (DrawingRecorder::useCachedDrawingIfPossible(*context, *scrollbar, DisplayItem::ScrollbarTickmarks))
+    if (DrawingRecorder::useCachedDrawingIfPossible(context, scrollbar, DisplayItem::ScrollbarTickmarks))
         return;
 
-    DrawingRecorder recorder(*context, *scrollbar, DisplayItem::ScrollbarTickmarks, rect);
-    GraphicsContextStateSaver stateSaver(*context);
-    context->setShouldAntialias(false);
+    DrawingRecorder recorder(context, scrollbar, DisplayItem::ScrollbarTickmarks, rect);
+    GraphicsContextStateSaver stateSaver(context);
+    context.setShouldAntialias(false);
 
     for (Vector<IntRect>::const_iterator i = tickmarks.begin(); i != tickmarks.end(); ++i) {
         // Calculate how far down (in %) the tick-mark should appear.
-        const float percent = static_cast<float>(i->y()) / scrollbar->totalSize();
+        const float percent = static_cast<float>(i->y()) / scrollbar.totalSize();
 
         // Calculate how far down (in pixels) the tick-mark should appear.
         const int yPos = rect.y() + (rect.height() * percent);
 
         FloatRect tickRect(rect.x(), yPos, rect.width(), 3);
-        context->fillRect(tickRect, Color(0xCC, 0xAA, 0x00, 0xFF));
+        context.fillRect(tickRect, Color(0xCC, 0xAA, 0x00, 0xFF));
 
         FloatRect tickStroke(rect.x(), yPos + 1, rect.width(), 1);
-        context->fillRect(tickStroke, Color(0xFF, 0xDD, 0x00, 0xFF));
+        context.fillRect(tickStroke, Color(0xFF, 0xDD, 0x00, 0xFF));
     }
 }
 
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeNonMacCommon.h b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeNonMacCommon.h
index 4f5155d..38b52d2f 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeNonMacCommon.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeNonMacCommon.h
@@ -37,17 +37,17 @@
 
 class PLATFORM_EXPORT ScrollbarThemeNonMacCommon : public ScrollbarTheme {
 protected:
-    bool hasButtons(const ScrollbarThemeClient*) override { return true; }
-    bool hasThumb(const ScrollbarThemeClient*) override;
+    bool hasButtons(const ScrollbarThemeClient&) override { return true; }
+    bool hasThumb(const ScrollbarThemeClient&) override;
 
-    IntRect backButtonRect(const ScrollbarThemeClient*, ScrollbarPart, bool painting = false) override;
-    IntRect forwardButtonRect(const ScrollbarThemeClient*, ScrollbarPart, bool painting = false) override;
-    IntRect trackRect(const ScrollbarThemeClient*, bool painting = false) override;
+    IntRect backButtonRect(const ScrollbarThemeClient&, ScrollbarPart, bool painting = false) override;
+    IntRect forwardButtonRect(const ScrollbarThemeClient&, ScrollbarPart, bool painting = false) override;
+    IntRect trackRect(const ScrollbarThemeClient&, bool painting = false) override;
 
-    void paintTrackBackground(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&) override;
-    void paintTickmarks(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&) override;
+    void paintTrackBackground(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&) override;
+    void paintTickmarks(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&) override;
 
-    virtual IntSize buttonSize(const ScrollbarThemeClient*) = 0;
+    virtual IntSize buttonSize(const ScrollbarThemeClient&) = 0;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeOverlay.cpp b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeOverlay.cpp
index 27efae78..0e1bfd3 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeOverlay.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeOverlay.cpp
@@ -73,96 +73,96 @@
     return true;
 }
 
-int ScrollbarThemeOverlay::thumbPosition(const ScrollbarThemeClient* scrollbar)
+int ScrollbarThemeOverlay::thumbPosition(const ScrollbarThemeClient& scrollbar)
 {
-    if (!scrollbar->totalSize())
+    if (!scrollbar.totalSize())
         return 0;
 
     int trackLen = trackLength(scrollbar);
-    float proportion = static_cast<float>(scrollbar->currentPos()) / scrollbar->totalSize();
+    float proportion = static_cast<float>(scrollbar.currentPos()) / scrollbar.totalSize();
     return round(proportion * trackLen);
 }
 
-int ScrollbarThemeOverlay::thumbLength(const ScrollbarThemeClient* scrollbar)
+int ScrollbarThemeOverlay::thumbLength(const ScrollbarThemeClient& scrollbar)
 {
     int trackLen = trackLength(scrollbar);
 
-    if (!scrollbar->totalSize())
+    if (!scrollbar.totalSize())
         return trackLen;
 
-    float proportion = static_cast<float>(scrollbar->visibleSize()) / scrollbar->totalSize();
+    float proportion = static_cast<float>(scrollbar.visibleSize()) / scrollbar.totalSize();
     int length = round(proportion * trackLen);
     length = std::min(std::max(length, minimumThumbLength(scrollbar)), trackLen);
     return length;
 }
 
-bool ScrollbarThemeOverlay::hasThumb(const ScrollbarThemeClient* scrollbar)
+bool ScrollbarThemeOverlay::hasThumb(const ScrollbarThemeClient& scrollbar)
 {
     return true;
 }
 
-IntRect ScrollbarThemeOverlay::backButtonRect(const ScrollbarThemeClient*, ScrollbarPart, bool)
+IntRect ScrollbarThemeOverlay::backButtonRect(const ScrollbarThemeClient&, ScrollbarPart, bool)
 {
     return IntRect();
 }
 
-IntRect ScrollbarThemeOverlay::forwardButtonRect(const ScrollbarThemeClient*, ScrollbarPart, bool)
+IntRect ScrollbarThemeOverlay::forwardButtonRect(const ScrollbarThemeClient&, ScrollbarPart, bool)
 {
     return IntRect();
 }
 
-IntRect ScrollbarThemeOverlay::trackRect(const ScrollbarThemeClient* scrollbar, bool)
+IntRect ScrollbarThemeOverlay::trackRect(const ScrollbarThemeClient& scrollbar, bool)
 {
-    IntRect rect = scrollbar->frameRect();
-    if (scrollbar->orientation() == HorizontalScrollbar)
+    IntRect rect = scrollbar.frameRect();
+    if (scrollbar.orientation() == HorizontalScrollbar)
         rect.inflateX(-m_scrollbarMargin);
     else
         rect.inflateY(-m_scrollbarMargin);
     return rect;
 }
 
-int ScrollbarThemeOverlay::thumbThickness(const ScrollbarThemeClient*)
+int ScrollbarThemeOverlay::thumbThickness(const ScrollbarThemeClient&)
 {
     return m_thumbThickness;
 }
 
-void ScrollbarThemeOverlay::paintThumb(GraphicsContext* context, const ScrollbarThemeClient* scrollbar, const IntRect& rect)
+void ScrollbarThemeOverlay::paintThumb(GraphicsContext& context, const ScrollbarThemeClient& scrollbar, const IntRect& rect)
 {
-    if (DrawingRecorder::useCachedDrawingIfPossible(*context, *scrollbar, DisplayItem::ScrollbarThumb))
+    if (DrawingRecorder::useCachedDrawingIfPossible(context, scrollbar, DisplayItem::ScrollbarThumb))
         return;
 
-    DrawingRecorder recorder(*context, *scrollbar, DisplayItem::ScrollbarThumb, rect);
+    DrawingRecorder recorder(context, scrollbar, DisplayItem::ScrollbarThumb, rect);
 
     IntRect thumbRect = rect;
-    if (scrollbar->orientation() == HorizontalScrollbar) {
+    if (scrollbar.orientation() == HorizontalScrollbar) {
         thumbRect.setHeight(thumbRect.height() - m_scrollbarMargin);
     } else {
         thumbRect.setWidth(thumbRect.width() - m_scrollbarMargin);
-        if (scrollbar->isLeftSideVerticalScrollbar())
+        if (scrollbar.isLeftSideVerticalScrollbar())
             thumbRect.setX(thumbRect.x() + m_scrollbarMargin);
     }
 
     if (m_useSolidColor) {
-        context->fillRect(thumbRect, m_color);
+        context.fillRect(thumbRect, m_color);
         return;
     }
 
     WebThemeEngine::State state = WebThemeEngine::StateNormal;
-    if (scrollbar->pressedPart() == ThumbPart)
+    if (scrollbar.pressedPart() == ThumbPart)
         state = WebThemeEngine::StatePressed;
-    else if (scrollbar->hoveredPart() == ThumbPart)
+    else if (scrollbar.hoveredPart() == ThumbPart)
         state = WebThemeEngine::StateHover;
 
-    WebCanvas* canvas = context->canvas();
+    WebCanvas* canvas = context.canvas();
 
     WebThemeEngine::Part part = WebThemeEngine::PartScrollbarHorizontalThumb;
-    if (scrollbar->orientation() == VerticalScrollbar)
+    if (scrollbar.orientation() == VerticalScrollbar)
         part = WebThemeEngine::PartScrollbarVerticalThumb;
 
     Platform::current()->themeEngine()->paint(canvas, part, state, WebRect(rect), 0);
 }
 
-ScrollbarPart ScrollbarThemeOverlay::hitTest(const ScrollbarThemeClient* scrollbar, const IntPoint& position)
+ScrollbarPart ScrollbarThemeOverlay::hitTest(const ScrollbarThemeClient& scrollbar, const IntPoint& position)
 {
     if (m_allowHitTest == DisallowHitTest)
         return NoPart;
@@ -170,10 +170,10 @@
     return ScrollbarTheme::hitTest(scrollbar, position);
 }
 
-ScrollbarTheme* ScrollbarThemeOverlay::mobileTheme()
+ScrollbarThemeOverlay& ScrollbarThemeOverlay::mobileTheme()
 {
     DEFINE_STATIC_LOCAL(ScrollbarThemeOverlay, theme, (3, 3, ScrollbarThemeOverlay::DisallowHitTest, Color(128, 128, 128, 128)));
-    return &theme;
+    return theme;
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeOverlay.h b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeOverlay.h
index c9087c69..0af2c04 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeOverlay.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeOverlay.h
@@ -45,21 +45,22 @@
     int scrollbarMargin() const override;
     bool usesOverlayScrollbars() const override;
 
-    int thumbPosition(const ScrollbarThemeClient*) override;
-    int thumbLength(const ScrollbarThemeClient*) override;
+    int thumbPosition(const ScrollbarThemeClient&) override;
+    int thumbLength(const ScrollbarThemeClient&) override;
 
-    bool hasButtons(const ScrollbarThemeClient*) override { return false; }
-    bool hasThumb(const ScrollbarThemeClient*) override;
+    bool hasButtons(const ScrollbarThemeClient&) override { return false; }
+    bool hasThumb(const ScrollbarThemeClient&) override;
 
-    IntRect backButtonRect(const ScrollbarThemeClient*, ScrollbarPart, bool painting = false) override;
-    IntRect forwardButtonRect(const ScrollbarThemeClient*, ScrollbarPart, bool painting = false) override;
-    IntRect trackRect(const ScrollbarThemeClient*, bool painting = false) override;
-    int thumbThickness(const ScrollbarThemeClient*) override;
+    IntRect backButtonRect(const ScrollbarThemeClient&, ScrollbarPart, bool painting = false) override;
+    IntRect forwardButtonRect(const ScrollbarThemeClient&, ScrollbarPart, bool painting = false) override;
+    IntRect trackRect(const ScrollbarThemeClient&, bool painting = false) override;
+    int thumbThickness(const ScrollbarThemeClient&) override;
+    int thumbThickness() { return m_thumbThickness; }
 
-    void paintThumb(GraphicsContext*, const ScrollbarThemeClient*, const IntRect&) override;
-    ScrollbarPart hitTest(const ScrollbarThemeClient*, const IntPoint&) override;
+    void paintThumb(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&) override;
+    ScrollbarPart hitTest(const ScrollbarThemeClient&, const IntPoint&) override;
 
-    static ScrollbarTheme* mobileTheme();
+    static ScrollbarThemeOverlay& mobileTheme();
 
 private:
     int m_thumbThickness;
diff --git a/third_party/WebKit/Source/platform/testing/GeometryPrinters.cpp b/third_party/WebKit/Source/platform/testing/GeometryPrinters.cpp
index 6b81fcef..8861bf2b 100644
--- a/third_party/WebKit/Source/platform/testing/GeometryPrinters.cpp
+++ b/third_party/WebKit/Source/platform/testing/GeometryPrinters.cpp
@@ -105,9 +105,9 @@
     *os << ", ";
     PrintTo(radii.topRight(), os);
     *os << ", ";
-    PrintTo(radii.bottomRight(), os);
-    *os << ", ";
     PrintTo(radii.bottomLeft(), os);
+    *os << ", ";
+    PrintTo(radii.bottomRight(), os);
     *os << ")";
 }
 
diff --git a/third_party/WebKit/Source/platform/testing/PaintPrinters.cpp b/third_party/WebKit/Source/platform/testing/PaintPrinters.cpp
index 4abd589c..ffd0c9e 100644
--- a/third_party/WebKit/Source/platform/testing/PaintPrinters.cpp
+++ b/third_party/WebKit/Source/platform/testing/PaintPrinters.cpp
@@ -35,8 +35,8 @@
 {
     *os << "ClipPaintPropertyNode(clip=";
     PrintTo(node.clipRect(), os);
-    *os << ", base=";
-    PrintPointer(node.base(), *os);
+    *os << ", localTransformSpace=";
+    PrintPointer(node.localTransformSpace(), *os);
     *os << ", parent=";
     PrintPointer(node.parent(), *os);
     *os << ")";
diff --git a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h
index e2468fd..7a286da 100644
--- a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h
+++ b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h
@@ -151,6 +151,7 @@
     //
     // WARNING: This is an extremely powerful ability. Use with caution!
     void grantUniversalAccess();
+    bool isGrantedUniversalAccess() const { return m_universalAccess; }
 
     bool canAccessDatabase() const { return !isUnique(); }
     bool canAccessLocalStorage() const { return !isUnique(); }
diff --git a/third_party/WebKit/Source/web/BUILD.gn b/third_party/WebKit/Source/web/BUILD.gn
index 14d51c1..caa4ea1 100644
--- a/third_party/WebKit/Source/web/BUILD.gn
+++ b/third_party/WebKit/Source/web/BUILD.gn
@@ -97,6 +97,15 @@
   }
 }
 
+# TODO(GYP): Delete this after we've converted everything to GN.
+# The _run targets exist only for compatibility w/ GYP.
+group("webkit_unit_tests_run") {
+  testonly = true
+  deps = [
+    ":webkit_unit_tests",
+  ]
+}
+
 # GYP version: WebKit/Source/web/web_tests.gyp:webkit_unit_tests
 test("webkit_unit_tests") {
   visibility = []  # Allow re-assignment of list.
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.cpp b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
index 5488a95..58fc1eb 100644
--- a/third_party/WebKit/Source/web/ChromeClientImpl.cpp
+++ b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
@@ -753,6 +753,17 @@
     }
 }
 
+void ChromeClientImpl::didPaint(const PaintArtifact& paintArtifact)
+{
+    // TODO(jbroman): This doesn't handle OOPIF correctly. We probably need a
+    // branch for WebFrameWidget, like attachRootGraphicsLayer.
+
+    // TODO(jbroman): We shouldn't reattach the root layer every time.
+    m_webView->attachPaintArtifactCompositor();
+
+    m_webView->paintArtifactCompositor().update(paintArtifact);
+}
+
 void ChromeClientImpl::attachCompositorAnimationTimeline(WebCompositorAnimationTimeline* compositorTimeline, LocalFrame* localRoot)
 {
     // FIXME: For top-level frames we still use the WebView as a WebWidget. This
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.h b/third_party/WebKit/Source/web/ChromeClientImpl.h
index ea028bcb..5be3646a 100644
--- a/third_party/WebKit/Source/web/ChromeClientImpl.h
+++ b/third_party/WebKit/Source/web/ChromeClientImpl.h
@@ -120,6 +120,8 @@
     // Pass 0 as the GraphicsLayer to detatch the root layer.
     void attachRootGraphicsLayer(GraphicsLayer*, LocalFrame* localRoot) override;
 
+    void didPaint(const PaintArtifact&) override;
+
     void attachCompositorAnimationTimeline(WebCompositorAnimationTimeline*, LocalFrame* localRoot) override;
     void detachCompositorAnimationTimeline(WebCompositorAnimationTimeline*, LocalFrame* localRoot) override;
 
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
index df4026a..19de8ca 100644
--- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
+++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
@@ -677,6 +677,18 @@
         m_webFrame->client()->didDispatchPingLoader(m_webFrame, url);
 }
 
+void FrameLoaderClientImpl::didDisplayContentWithCertificateErrors(const KURL& url, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo)
+{
+    if (m_webFrame->client())
+        m_webFrame->client()->didDisplayContentWithCertificateErrors(url, securityInfo, mainResourceUrl, mainResourceSecurityInfo);
+}
+
+void FrameLoaderClientImpl::didRunContentWithCertificateErrors(const KURL& url, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo)
+{
+    if (m_webFrame->client())
+        m_webFrame->client()->didRunContentWithCertificateErrors(url, securityInfo, mainResourceUrl, mainResourceSecurityInfo);
+}
+
 void FrameLoaderClientImpl::didChangePerformanceTiming()
 {
     if (m_webFrame->client())
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
index 518325b..360f5b00 100644
--- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
+++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
@@ -113,6 +113,8 @@
     void didRunInsecureContent(SecurityOrigin*, const KURL& insecureURL) override;
     void didDetectXSS(const KURL&, bool didBlockEntirePage) override;
     void didDispatchPingLoader(const KURL&) override;
+    void didDisplayContentWithCertificateErrors(const KURL&, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) override;
+    void didRunContentWithCertificateErrors(const KURL&, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) override;
     void didChangePerformanceTiming() override;
     void selectorMatchChanged(const Vector<String>& addedSelectors, const Vector<String>& removedSelectors) override;
     PassRefPtrWillBeRawPtr<DocumentLoader> createDocumentLoader(LocalFrame*, const ResourceRequest&, const SubstituteData&) override;
diff --git a/third_party/WebKit/Source/web/InspectorOverlay.cpp b/third_party/WebKit/Source/web/InspectorOverlay.cpp
index e38da0a..7e5f6607 100644
--- a/third_party/WebKit/Source/web/InspectorOverlay.cpp
+++ b/third_party/WebKit/Source/web/InspectorOverlay.cpp
@@ -119,7 +119,7 @@
         DisplayItemCacheSkipper cacheSkipper(graphicsContext);
         FrameView* view = m_overlay->overlayMainFrame()->view();
         ASSERT(!view->needsLayout());
-        view->paint(&graphicsContext, CullRect(IntRect(0, 0, view->width(), view->height())));
+        view->paint(graphicsContext, CullRect(IntRect(0, 0, view->width(), view->height())));
     }
 
 private:
diff --git a/third_party/WebKit/Source/web/LinkHighlightImpl.cpp b/third_party/WebKit/Source/web/LinkHighlightImpl.cpp
index 4996a4416..fd57056e 100644
--- a/third_party/WebKit/Source/web/LinkHighlightImpl.cpp
+++ b/third_party/WebKit/Source/web/LinkHighlightImpl.cpp
@@ -270,7 +270,8 @@
         return;
 
     SkPictureRecorder recorder;
-    SkCanvas* canvas = recorder.beginRecording(paintableRegion().width(), paintableRegion().height());
+    gfx::Rect visualRect = paintableRegion();
+    SkCanvas* canvas = recorder.beginRecording(visualRect.width(), visualRect.height());
 
     SkPaint paint;
     paint.setStyle(SkPaint::kFill_Style);
@@ -279,8 +280,7 @@
     canvas->drawPath(m_path.skPath(), paint);
 
     RefPtr<const SkPicture> picture = adoptRef(recorder.endRecording());
-    // TODO(wkorman): Pass actual visual rect with the drawing item.
-    webDisplayItemList->appendDrawingItem(IntRect(), picture.get());
+    webDisplayItemList->appendDrawingItem(WebRect(visualRect.x(), visualRect.y(), visualRect.width(), visualRect.height()), picture.get());
 }
 
 void LinkHighlightImpl::startHighlightAnimationIfNeeded()
diff --git a/third_party/WebKit/Source/web/LinkHighlightImplTest.cpp b/third_party/WebKit/Source/web/LinkHighlightImplTest.cpp
index 4ac463f..66f9057 100644
--- a/third_party/WebKit/Source/web/LinkHighlightImplTest.cpp
+++ b/third_party/WebKit/Source/web/LinkHighlightImplTest.cpp
@@ -201,7 +201,6 @@
 
     // Mimic the logic from RenderWidget::Close:
     webViewImpl->willCloseLayerTreeView();
-    webViewClient.clear();
     webViewHelper.reset();
 
     Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
diff --git a/third_party/WebKit/Source/web/PageOverlay.h b/third_party/WebKit/Source/web/PageOverlay.h
index 87f772f..c1a021b 100644
--- a/third_party/WebKit/Source/web/PageOverlay.h
+++ b/third_party/WebKit/Source/web/PageOverlay.h
@@ -47,7 +47,7 @@
 //
 // With Slimming Paint, internal clients can extract a GraphicsContext to add
 // to the PaintController owned by the GraphicsLayer
-class PageOverlay : public GraphicsLayerClient {
+class PageOverlay : public GraphicsLayerClient, public DisplayItemClient {
 public:
     class Delegate : public GarbageCollectedFinalized<Delegate> {
     public:
@@ -65,8 +65,7 @@
     void update();
 
     GraphicsLayer* graphicsLayer() const { return m_layer.get(); }
-    DisplayItemClient displayItemClient() const { return toDisplayItemClient(this); }
-    String debugName() const { return "PageOverlay"; }
+    String debugName() const final { return "PageOverlay"; }
 
     // GraphicsLayerClient implementation
     IntRect computeInterestRect(const GraphicsLayer*, const IntRect&) const override;
diff --git a/third_party/WebKit/Source/web/PageWidgetDelegate.cpp b/third_party/WebKit/Source/web/PageWidgetDelegate.cpp
index 4337e611..5cd1e6f 100644
--- a/third_party/WebKit/Source/web/PageWidgetDelegate.cpp
+++ b/third_party/WebKit/Source/web/PageWidgetDelegate.cpp
@@ -93,7 +93,7 @@
         if (view) {
             ClipRecorder clipRecorder(paintContext, root, DisplayItem::PageWidgetDelegateClip, LayoutRect(dirtyRect));
 
-            view->paint(&paintContext, globalPaintFlags, CullRect(dirtyRect));
+            view->paint(paintContext, globalPaintFlags, CullRect(dirtyRect));
         } else if (!DrawingRecorder::useCachedDrawingIfPossible(paintContext, root, DisplayItem::PageWidgetDelegateBackgroundFallback)) {
             DrawingRecorder drawingRecorder(paintContext, root, DisplayItem::PageWidgetDelegateBackgroundFallback, dirtyRect);
             paintContext.fillRect(dirtyRect, Color::white);
diff --git a/third_party/WebKit/Source/web/SharedWorkerRepositoryClientImpl.cpp b/third_party/WebKit/Source/web/SharedWorkerRepositoryClientImpl.cpp
index 1141c3a1..b782192 100644
--- a/third_party/WebKit/Source/web/SharedWorkerRepositoryClientImpl.cpp
+++ b/third_party/WebKit/Source/web/SharedWorkerRepositoryClientImpl.cpp
@@ -130,13 +130,20 @@
     }
 
     WebWorkerCreationError creationError;
-    OwnPtr<WebSharedWorkerConnector> webWorkerConnector = adoptPtr(m_client->createSharedWorkerConnector(url, name, getId(document), header, headerType, &creationError));
+    String unusedSecureContextError;
+    bool isSecureContext = worker->executionContext()->isSecureContext(unusedSecureContextError);
+    OwnPtr<WebSharedWorkerConnector> webWorkerConnector = adoptPtr(m_client->createSharedWorkerConnector(url, name, getId(document), header, headerType, isSecureContext ? WebSharedWorkerCreationContextTypeSecure : WebSharedWorkerCreationContextTypeNonsecure, &creationError));
     if (!webWorkerConnector) {
-        // TODO(estark): This assertion will shortly go away and each
-        // different error type will be handled. https://crbug.com/561216
-        ASSERT(creationError == WebWorkerCreationErrorURLMismatch);
-        // Existing worker does not match this url, so return an error back to the caller.
-        exceptionState.throwDOMException(URLMismatchError, "The location of the SharedWorker named '" + name + "' does not exactly match the provided URL ('" + url.elidedString() + "').");
+        if (creationError == WebWorkerCreationErrorURLMismatch) {
+            // Existing worker does not match this url, so return an error back to the caller.
+            exceptionState.throwDOMException(URLMismatchError, "The location of the SharedWorker named '" + name + "' does not exactly match the provided URL ('" + url.elidedString() + "').");
+        } else if (creationError == WebWorkerCreationErrorSecureContextMismatch) {
+            if (isSecureContext) {
+                exceptionState.throwSecurityError("The SharedWorker named '" + name + "' was created from a nonsecure context and this context is secure.");
+            } else {
+                exceptionState.throwSecurityError("The SharedWorker named '" + name + "' was created from a secure context and this context is not secure.");
+            }
+        }
         return;
     }
 
diff --git a/third_party/WebKit/Source/web/WebDocument.cpp b/third_party/WebKit/Source/web/WebDocument.cpp
index f3b4146c7..a1b8ec2 100644
--- a/third_party/WebKit/Source/web/WebDocument.cpp
+++ b/third_party/WebKit/Source/web/WebDocument.cpp
@@ -322,6 +322,18 @@
     return DocumentStatisticsCollector::collectStatistics(*unwrap<Document>());
 }
 
+bool WebDocument::attemptedToDetermineEncodingFromContentSniffing() const
+{
+    const Document* document = constUnwrap<Document>();
+    return document->attemptedToDetermineEncodingFromContentSniffing();
+}
+
+bool WebDocument::encodingWasDetectedFromContentSniffing() const
+{
+    const Document* document = constUnwrap<Document>();
+    return document->encodingWasDetectedFromContentSniffing();
+}
+
 WebDocument::WebDocument(const PassRefPtrWillBeRawPtr<Document>& elem)
     : WebNode(elem)
 {
diff --git a/third_party/WebKit/Source/web/WebFontImpl.h b/third_party/WebKit/Source/web/WebFontImpl.h
index b6c2378..2929dcf 100644
--- a/third_party/WebKit/Source/web/WebFontImpl.h
+++ b/third_party/WebKit/Source/web/WebFontImpl.h
@@ -39,7 +39,7 @@
 
 class FontDescription;
 
-class WebFontImpl final : public WebFont {
+class WebFontImpl final : public WebFont, public DisplayItemClient {
 public:
     explicit WebFontImpl(const FontDescription&);
 
@@ -59,8 +59,7 @@
     WebFloatRect selectionRectForText(const WebTextRun&, const WebFloatPoint& leftBaseline,
         int height, int from = 0, int to = -1) const override;
 
-    DisplayItemClient displayItemClient() const { return toDisplayItemClient(this); }
-    String debugName() const { return "WebFontImpl"; }
+    String debugName() const final { return "WebFontImpl"; }
 
 private:
     Font m_font;
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
index 89295a1..5414170 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -335,7 +335,7 @@
 
 // Simple class to override some of PrintContext behavior. Some of the methods
 // made virtual so that they can be overridden by ChromePluginPrintContext.
-class ChromePrintContext : public PrintContext {
+class ChromePrintContext : public PrintContext, public DisplayItemClient {
     WTF_MAKE_NONCOPYABLE(ChromePrintContext);
 public:
     ChromePrintContext(LocalFrame* frame)
@@ -375,7 +375,6 @@
 
         float scale = spoolPage(pictureBuilder.context(), pageNumber);
         pictureBuilder.endRecording()->playback(canvas);
-        outputLinkedDestinations(canvas, pageRect);
         return scale;
     }
 
@@ -403,7 +402,7 @@
         GraphicsContext& context = pictureBuilder.context();
 
         // Fill the whole background by white.
-        if (!DrawingRecorder::useCachedDrawingIfPossible(context, *this, DisplayItem::PrintedContentBackground)) {
+        {
             DrawingRecorder backgroundRecorder(context, *this, DisplayItem::PrintedContentBackground, allPagesRect);
             context.fillRect(FloatRect(0, 0, pageWidth, totalHeight), Color::white);
         }
@@ -412,7 +411,7 @@
         for (size_t pageIndex = 0; pageIndex < numPages; pageIndex++) {
             ScopeRecorder scopeRecorder(context);
             // Draw a line for a page boundary if this isn't the first page.
-            if (pageIndex > 0 && !DrawingRecorder::useCachedDrawingIfPossible(context, *this, DisplayItem::PrintedContentLineBoundary)) {
+            if (pageIndex > 0) {
                 DrawingRecorder lineBoundaryRecorder(context, *this, DisplayItem::PrintedContentLineBoundary, allPagesRect);
                 context.save();
                 context.setStrokeColor(Color(0, 0, 255));
@@ -435,12 +434,9 @@
             currentHeight += pageSizeInPixels.height() + 1;
         }
         pictureBuilder.endRecording()->playback(canvas);
-        outputLinkedDestinations(canvas, allPagesRect);
     }
 
-    DisplayItemClient displayItemClient() const { return toDisplayItemClient(this); }
-
-    String debugName() const { return "ChromePrintContext"; }
+    String debugName() const final { return "ChromePrintContext"; }
 
 protected:
     // Spools the printed page, a subrect of frame(). Skip the scale step.
@@ -462,7 +458,12 @@
 
         ClipRecorder clipRecorder(context, *this, DisplayItem::ClipPrintedPage, LayoutRect(pageRect));
 
-        frame()->view()->paintContents(&context, GlobalPaintNormalPhase, pageRect);
+        frame()->view()->paintContents(context, GlobalPaintNormalPhase, pageRect);
+
+        {
+            DrawingRecorder lineBoundaryRecorder(context, *this, DisplayItem::PrintedContentDestinationLocations, pageRect);
+            outputLinkedDestinations(context, pageRect);
+        }
 
         return scale;
     }
@@ -1845,7 +1846,8 @@
 
     WebViewImpl* webView = viewImpl();
 
-    IntSize initialSize = frameWidget() ? (IntSize)frameWidget()->size() : webView->mainFrameSize();
+    bool isMainFrame = !parent();
+    IntSize initialSize = (isMainFrame || !frameWidget()) ? webView->mainFrameSize() : (IntSize)frameWidget()->size();
 
     frame()->createView(initialSize, webView->baseBackgroundColor(), webView->isTransparent());
     if (webView->shouldAutoResize() && frame()->isLocalRoot())
@@ -2082,6 +2084,17 @@
     toRemoteBridgeFrameOwner(owner)->setMarginHeight(frameOwnerProperties.marginHeight);
 }
 
+WebLocalFrameImpl* WebLocalFrameImpl::localRoot()
+{
+    // This can't use the LocalFrame::localFrameRoot, since it may be called
+    // when the WebLocalFrame exists but the core LocalFrame does not.
+    // TODO(alexmos, dcheng): Clean this up to only calculate this in one place.
+    WebLocalFrameImpl* localRoot = this;
+    while (!localRoot->frameWidget())
+        localRoot = toWebLocalFrameImpl(localRoot->parent());
+    return localRoot;
+}
+
 void WebLocalFrameImpl::sendPings(const WebNode& contextNode, const WebURL& destinationURL)
 {
     ASSERT(frame());
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.h b/third_party/WebKit/Source/web/WebLocalFrameImpl.h
index 147c417..2b6eba7 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.h
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.h
@@ -240,6 +240,7 @@
     void setDevToolsAgentClient(WebDevToolsAgentClient*) override;
     WebDevToolsAgent* devToolsAgent() override;
     void setFrameOwnerProperties(const WebFrameOwnerProperties&) override;
+    WebLocalFrameImpl* localRoot() override;
     void sendPings(const WebNode& contextNode, const WebURL& destinationURL) override;
     WebURLRequest requestFromHistoryItem(const WebHistoryItem&, WebURLRequest::CachePolicy)
         const override;
diff --git a/third_party/WebKit/Source/web/WebPageSerializer.cpp b/third_party/WebKit/Source/web/WebPageSerializer.cpp
index 501cb39b..4ac798c 100644
--- a/third_party/WebKit/Source/web/WebPageSerializer.cpp
+++ b/third_party/WebKit/Source/web/WebPageSerializer.cpp
@@ -206,14 +206,12 @@
     return WebCString(mhtml->data(), mhtml->size());
 }
 
-bool WebPageSerializer::serialize(WebLocalFrame* frame,
-                                  WebPageSerializerClient* client,
-                                  const WebVector<WebURL>& links,
-                                  const WebVector<WebString>& localPaths,
-                                  const WebString& localDirectoryName)
+bool WebPageSerializer::serialize(
+    WebLocalFrame* frame,
+    WebPageSerializerClient* client,
+    const WebVector<std::pair<WebURL, WebString>>& urlsToLocalPaths)
 {
-    WebPageSerializerImpl serializerImpl(
-        frame, client, links, localPaths, localDirectoryName);
+    WebPageSerializerImpl serializerImpl(frame, client, urlsToLocalPaths);
     return serializerImpl.serialize();
 }
 
diff --git a/third_party/WebKit/Source/web/WebPageSerializerImpl.cpp b/third_party/WebKit/Source/web/WebPageSerializerImpl.cpp
index e76398e..3c933e1 100644
--- a/third_party/WebKit/Source/web/WebPageSerializerImpl.cpp
+++ b/third_party/WebKit/Source/web/WebPageSerializerImpl.cpp
@@ -104,12 +104,10 @@
 
 WebPageSerializerImpl::SerializeDomParam::SerializeDomParam(const KURL& url,
                                                             const WTF::TextEncoding& textEncoding,
-                                                            Document* document,
-                                                            const String& directoryName)
+                                                            Document* document)
     : url(url)
     , textEncoding(textEncoding)
     , document(document)
-    , directoryName(directoryName)
     , isHTMLDocument(document->isHTMLDocument())
     , haveSeenDocType(false)
     , haveAddedCharsetDeclaration(false)
@@ -316,11 +314,6 @@
                     String completeURL = param->document->completeURL(attrValue);
                     // Check whether we have local files for those link.
                     if (m_localLinks.contains(completeURL)) {
-                        if (!param->directoryName.isEmpty()) {
-                            result.appendLiteral("./");
-                            result.append(param->directoryName);
-                            result.append('/');
-                        }
                         result.append(m_htmlEntities.convertEntitiesInString(m_localLinks.get(completeURL)));
                     } else {
                         result.append(m_htmlEntities.convertEntitiesInString(completeURL));
@@ -416,13 +409,11 @@
     }
 }
 
-WebPageSerializerImpl::WebPageSerializerImpl(WebLocalFrame* frame,
-                                             WebPageSerializerClient* client,
-                                             const WebVector<WebURL>& links,
-                                             const WebVector<WebString>& localPaths,
-                                             const WebString& localDirectoryName)
+WebPageSerializerImpl::WebPageSerializerImpl(
+    WebLocalFrame* frame,
+    WebPageSerializerClient* client,
+    const WebVector<std::pair<WebURL, WebString>>& urlsToLocalPaths)
     : m_client(client)
-    , m_localDirectoryName(localDirectoryName)
     , m_htmlEntities(false)
     , m_xmlEntities(true)
 {
@@ -432,11 +423,10 @@
     // Make sure we have non 0 client.
     ASSERT(client);
     // Build local resources map.
-    ASSERT(links.size() == localPaths.size());
-    for (size_t i = 0; i < links.size(); i++) {
-        KURL url = links[i];
+    for (const auto& it : urlsToLocalPaths) {
+        KURL url = it.first;
         ASSERT(!m_localLinks.contains(url.string()));
-        m_localLinks.set(url.string(), localPaths[i]);
+        m_localLinks.set(url.string(), it.second);
     }
 
     ASSERT(m_dataBuffer.isEmpty());
@@ -454,7 +444,7 @@
 
         const WTF::TextEncoding& textEncoding = document->encoding().isValid() ? document->encoding() : UTF8Encoding();
 
-        SerializeDomParam param(url, textEncoding, document, m_localDirectoryName);
+        SerializeDomParam param(url, textEncoding, document);
 
         Element* documentElement = document->documentElement();
         if (documentElement)
diff --git a/third_party/WebKit/Source/web/WebPageSerializerImpl.h b/third_party/WebKit/Source/web/WebPageSerializerImpl.h
index fd20800..212135c 100644
--- a/third_party/WebKit/Source/web/WebPageSerializerImpl.h
+++ b/third_party/WebKit/Source/web/WebPageSerializerImpl.h
@@ -75,16 +75,12 @@
     // The parameter delegate specifies the pointer of interface
     // DomSerializerDelegate provide sink interface which can receive the
     // individual chunks of data to be saved.
-    // The parameter links contain original URLs of all saved links.
-    // The parameter local_paths contain corresponding local file paths of all
-    // saved links, which matched with vector:links one by one.
-    // The parameter local_directory_name is relative path of directory which
-    // contain all saved auxiliary files included all sub frames and resources.
-    WebPageSerializerImpl(WebLocalFrame*,
-                          WebPageSerializerClient* client,
-                          const WebVector<WebURL>& links,
-                          const WebVector<WebString>& localPaths,
-                          const WebString& localDirectoryName);
+    // The parameter urlsToLocalPaths contains a mapping between original URLs
+    // of saved resources and corresponding local file paths.
+    WebPageSerializerImpl(
+        WebLocalFrame*,
+        WebPageSerializerClient*,
+        const WebVector<std::pair<WebURL, WebString>>& urlsToLocalPaths);
 
 private:
     // Specified frame which need to be serialized;
@@ -99,8 +95,6 @@
     LinkLocalPathMap m_localLinks;
     // Data buffer for saving result of serialized DOM data.
     StringBuilder m_dataBuffer;
-    // Local directory name of all local resource files.
-    WTF::String m_localDirectoryName;
 
     // Web entities conversion maps.
     WebEntities m_htmlEntities;
@@ -109,12 +103,11 @@
     class SerializeDomParam {
         STACK_ALLOCATED();
     public:
-        SerializeDomParam(const KURL&, const WTF::TextEncoding&, Document*, const WTF::String& directoryName);
+        SerializeDomParam(const KURL&, const WTF::TextEncoding&, Document*);
 
         const KURL& url;
         const WTF::TextEncoding& textEncoding;
         RawPtrWillBeMember<Document> document;
-        const WTF::String& directoryName;
         bool isHTMLDocument; // document.isHTMLDocument()
         bool haveSeenDocType;
         bool haveAddedCharsetDeclaration;
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
index 8de3047c..64ee6a6 100644
--- a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
+++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
@@ -114,7 +114,7 @@
     m_webPlugin->layoutIfNeeded();
 }
 
-void WebPluginContainerImpl::paint(GraphicsContext* context, const CullRect& cullRect) const
+void WebPluginContainerImpl::paint(GraphicsContext& context, const CullRect& cullRect) const
 {
     if (!parent())
         return;
@@ -123,11 +123,11 @@
     if (!cullRect.intersectsCullRect(frameRect()))
         return;
 
-    if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*context, *m_element->layoutObject(), DisplayItem::Type::WebPlugin, LayoutPoint()))
+    if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, *m_element->layoutObject(), DisplayItem::Type::WebPlugin, LayoutPoint()))
         return;
 
-    LayoutObjectDrawingRecorder drawingRecorder(*context, *m_element->layoutObject(), DisplayItem::Type::WebPlugin, cullRect.m_rect, LayoutPoint());
-    context->save();
+    LayoutObjectDrawingRecorder drawingRecorder(context, *m_element->layoutObject(), DisplayItem::Type::WebPlugin, cullRect.m_rect, LayoutPoint());
+    context.save();
 
     ASSERT(parent()->isFrameView());
     FrameView* view =  toFrameView(parent());
@@ -135,14 +135,14 @@
     // The plugin is positioned in the root frame's coordinates, so it needs to
     // be painted in them too.
     IntPoint origin = view->contentsToRootFrame(IntPoint(0, 0));
-    context->translate(static_cast<float>(-origin.x()), static_cast<float>(-origin.y()));
+    context.translate(static_cast<float>(-origin.x()), static_cast<float>(-origin.y()));
 
-    WebCanvas* canvas = context->canvas();
+    WebCanvas* canvas = context.canvas();
 
     IntRect windowRect = view->contentsToRootFrame(cullRect.m_rect);
     m_webPlugin->paint(canvas, windowRect);
 
-    context->restore();
+    context.restore();
 }
 
 void WebPluginContainerImpl::invalidateRect(const IntRect& rect)
@@ -819,9 +819,9 @@
 
     if (webEvent.type == WebInputEvent::KeyDown) {
 #if OS(MACOSX)
-        if (webEvent.modifiers == WebInputEvent::MetaKey
+        if ((webEvent.modifiers & WebInputEvent::InputModifiers) == WebInputEvent::MetaKey
 #else
-        if (webEvent.modifiers == WebInputEvent::ControlKey
+        if ((webEvent.modifiers & WebInputEvent::InputModifiers) == WebInputEvent::ControlKey
 #endif
             && (webEvent.windowsKeyCode == VKEY_C || webEvent.windowsKeyCode == VKEY_INSERT)
             // Only copy if there's a selection, so that we only ever do this
@@ -953,7 +953,7 @@
 
     // The frameRect is already in absolute space, except for scrolling of the root frame.
     windowRect = frameRect();
-    windowRect.moveBy(roundedIntPoint(-rootView->viewRect().location()));
+    windowRect = enclosingIntRect(m_element->document().view()->layoutView()->localToAbsoluteQuad(FloatQuad(FloatRect(frameRect())), TraverseDocumentBoundaries).boundingBox());
 
     clippedLocalRect = enclosingIntRect(unclippedAbsoluteRect);
     unclippedIntLocalRect = clippedLocalRect;
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.h b/third_party/WebKit/Source/web/WebPluginContainerImpl.h
index a79503b..7eabf917 100644
--- a/third_party/WebKit/Source/web/WebPluginContainerImpl.h
+++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.h
@@ -81,7 +81,7 @@
 
     // Widget methods
     void setFrameRect(const IntRect&) override;
-    void paint(GraphicsContext*, const CullRect&) const override;
+    void paint(GraphicsContext&, const CullRect&) const override;
     void invalidateRect(const IntRect&) override;
     void setFocus(bool, WebFocusType) override;
     void show() override;
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp
index 3efbcdf..45606d3 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -323,6 +323,69 @@
     WebColor m_color;
 };
 
+#if OS(ANDROID)
+// Array used to convert canonical encoding method name to index to be
+// uploaded to UMA for the experiment on text encoding auto detection.
+// The listed order should be in sync with the enum definition 'EncodingMethod'
+// in tools/metrics/histograms/histograms.xml.
+static const char* kEncodingNames[] = {
+    "UNKNOWN",
+    "Big5",
+    "EUC-JP",
+    "EUC-KR",
+    "GBK",
+    "IBM866",
+    "ISO-2022-JP",
+    "ISO-8859-10",
+    "ISO-8859-13",
+    "ISO-8859-14",
+    "ISO-8859-15",
+    "ISO-8859-16",
+    "ISO-8859-2",
+    "ISO-8859-3",
+    "ISO-8859-4",
+    "ISO-8859-5",
+    "ISO-8859-6",
+    "ISO-8859-7",
+    "ISO-8859-8",
+    "ISO-8859-8-I",
+    "KOI8-R",
+    "KOI8-U",
+    "Shift_JIS",
+    "UTF-16LE",
+    "UTF-8",
+    "gb18030",
+    "macintosh",
+    "windows-1250",
+    "windows-1251",
+    "windows-1252",
+    "windows-1253",
+    "windows-1254",
+    "windows-1255",
+    "windows-1256",
+    "windows-1257",
+    "windows-1258",
+    "windows-874"
+};
+
+// Returns the index of the entry in the array that matches
+// the given encoding method.
+static int encodingToUmaId(const WTF::TextEncoding& encoding)
+{
+    const char* encodingName = encoding.name();
+    for (size_t i = 0; i < WTF_ARRAY_LENGTH(kEncodingNames); ++i) {
+        if (!strcasecmp(kEncodingNames[i], encodingName))
+            return i;
+    }
+    return 0;
+}
+
+static bool isInternalURL(const KURL& url)
+{
+    const String& protocol = url.protocol();
+    return protocol == "chrome" || protocol == "chrome-native" || protocol == "swappedout";
+}
+#endif
 } // namespace
 
 // WebView ----------------------------------------------------------------
@@ -2692,6 +2755,8 @@
 
 bool WebViewImpl::isAcceleratedCompositingActive() const
 {
+    if (RuntimeEnabledFeatures::slimmingPaintV2Enabled())
+        return m_paintArtifactCompositor.webLayer();
     return m_rootLayer;
 }
 
@@ -2706,7 +2771,11 @@
     if (m_layerTreeView)
         page()->willCloseLayerTreeView(*m_layerTreeView);
 
-    setRootGraphicsLayer(nullptr);
+    if (RuntimeEnabledFeatures::slimmingPaintV2Enabled())
+        detachPaintArtifactCompositor();
+    else
+        setRootGraphicsLayer(nullptr);
+
     m_layerTreeView = nullptr;
 }
 
@@ -3957,6 +4026,18 @@
     if (webframe != mainFrameImpl())
         return;
     resumeTreeViewCommitsIfRenderingReady();
+#if OS(ANDROID)
+    if (!isInternalURL(webframe->frame()->document()->baseURL()) && page()->settings().usesEncodingDetector()) {
+        const Document& document = *webframe->frame()->document();
+
+        // "AutodetectEncoding.Attempted" is of boolean type - either 0 or 1. Use 2 for the boundary value.
+        Platform::current()->histogramEnumeration("AutodetectEncoding.Attempted", document.attemptedToDetermineEncodingFromContentSniffing(), 2);
+        if (document.encodingWasDetectedFromContentSniffing()) {
+            int encodingId = encodingToUmaId(document.encoding());
+            Platform::current()->histogramEnumeration("AutodetectEncoding.Detected", encodingId, WTF_ARRAY_LENGTH(kEncodingNames) + 1);
+        }
+    }
+#endif
 }
 
 void WebViewImpl::didRemoveAllPendingStylesheet(WebLocalFrameImpl* webframe)
@@ -4170,6 +4251,10 @@
     if (!m_layerTreeView)
         return;
 
+    // In SPv2, we attach layers via PaintArtifactCompositor, rather than
+    // supplying a root GraphicsLayer from PaintLayerCompositor.
+    ASSERT(!RuntimeEnabledFeatures::slimmingPaintV2Enabled());
+
     VisualViewport& visualViewport = page()->frameHost().visualViewport();
     visualViewport.attachToLayerTree(layer, graphicsLayerFactory());
     if (layer) {
@@ -4497,4 +4582,36 @@
     }
 }
 
+void WebViewImpl::attachPaintArtifactCompositor()
+{
+    if (!m_layerTreeView)
+        return;
+
+    // Otherwise, PaintLayerCompositor is expected to supply a root
+    // GraphicsLayer via setRootGraphicsLayer.
+    ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
+
+    // TODO(jbroman): This should probably have hookups for overlays, visual
+    // viewport, etc.
+
+    m_paintArtifactCompositor.initializeIfNeeded();
+    WebLayer* rootLayer = m_paintArtifactCompositor.webLayer();
+    ASSERT(rootLayer);
+    m_layerTreeView->setRootLayer(*rootLayer);
+
+    // TODO(jbroman): This is cargo-culted from setRootGraphicsLayer. Is it
+    // necessary?
+    bool visible = page()->visibilityState() == PageVisibilityStateVisible;
+    m_layerTreeView->setVisible(visible);
+}
+
+void WebViewImpl::detachPaintArtifactCompositor()
+{
+    if (!m_layerTreeView)
+        return;
+
+    m_layerTreeView->setDeferCommits(true);
+    m_layerTreeView->clearRootLayer();
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/web/WebViewImpl.h b/third_party/WebKit/Source/web/WebViewImpl.h
index c4453c1..d68739e1 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.h
+++ b/third_party/WebKit/Source/web/WebViewImpl.h
@@ -36,6 +36,7 @@
 #include "platform/geometry/IntPoint.h"
 #include "platform/geometry/IntRect.h"
 #include "platform/graphics/GraphicsLayer.h"
+#include "platform/graphics/compositing/PaintArtifactCompositor.h"
 #include "platform/heap/Handle.h"
 #include "public/platform/WebCompositorAnimationTimeline.h"
 #include "public/platform/WebDisplayMode.h"
@@ -525,6 +526,17 @@
 
     WebViewScheduler* scheduler() const { return m_scheduler.get(); }
 
+    // Attaches the PaintArtifactCompositor's tree to this WebView's layer tree
+    // view.
+    void attachPaintArtifactCompositor();
+
+    // Detaches the PaintArtifactCompositor and clears the layer tree view's
+    // root layer.
+    void detachPaintArtifactCompositor();
+
+    // Use in Slimming Paint v2 to update the layer tree for the content.
+    PaintArtifactCompositor& paintArtifactCompositor() { return m_paintArtifactCompositor; }
+
 private:
     InspectorOverlay* inspectorOverlay();
 
@@ -756,6 +768,9 @@
     WebPageImportanceSignals m_pageImportanceSignals;
 
     const OwnPtr<WebViewScheduler> m_scheduler;
+
+    // Manages the layer tree created for this page in Slimming Paint v2.
+    PaintArtifactCompositor m_paintArtifactCompositor;
 };
 
 DEFINE_TYPE_CASTS(WebViewImpl, WebWidget, widget, widget->isWebView(), widget.isWebView());
diff --git a/third_party/WebKit/Source/web/WebViewImplPaintArtifactCompositorTest.cpp b/third_party/WebKit/Source/web/WebViewImplPaintArtifactCompositorTest.cpp
new file mode 100644
index 0000000..5fdba9d
--- /dev/null
+++ b/third_party/WebKit/Source/web/WebViewImplPaintArtifactCompositorTest.cpp
@@ -0,0 +1,86 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "web/WebViewImpl.h"
+
+#include "platform/RuntimeEnabledFeatures.h"
+#include "platform/graphics/compositing/PaintArtifactCompositor.h"
+#include "public/platform/WebLayerTreeView.h"
+#include "public/web/WebViewClient.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "web/tests/FrameTestHelpers.h"
+
+// Tests that WebViewImpl attaches the layer owned by PaintArtifactCompositor to
+// the WebLayerTreeView when requested.
+
+using testing::Property;
+
+namespace blink {
+namespace {
+
+class MockWebLayerTreeView : public WebLayerTreeView {
+public:
+    // WebLayerTreeView
+    MOCK_METHOD1(setRootLayer, void(const WebLayer&));
+    MOCK_METHOD0(clearRootLayer, void());
+};
+
+class TestWebViewClient : public WebViewClient {
+public:
+    TestWebViewClient(WebLayerTreeView* layerTreeView)
+        : m_layerTreeView(layerTreeView) { }
+
+    // WebViewClient
+    WebLayerTreeView* layerTreeView() override { return m_layerTreeView; }
+
+private:
+    WebLayerTreeView* m_layerTreeView;
+};
+
+class WebViewImplPaintArtifactCompositorTest : public testing::Test {
+protected:
+    WebViewImplPaintArtifactCompositorTest()
+        : m_webViewClient(&m_webLayerTreeView) { }
+
+    void SetUp() override
+    {
+        RuntimeEnabledFeatures::setSlimmingPaintV2Enabled(true);
+        m_helper.initialize(false, nullptr, &m_webViewClient);
+    }
+
+    void TearDown() override
+    {
+        m_featuresBackup.restore();
+    }
+
+    MockWebLayerTreeView& webLayerTreeView() { return m_webLayerTreeView; }
+    WebViewImpl& webViewImpl() { return *m_helper.webViewImpl(); }
+    PaintArtifactCompositor& paintArtifactCompositor() { return webViewImpl().paintArtifactCompositor(); }
+
+private:
+    RuntimeEnabledFeatures::Backup m_featuresBackup;
+    MockWebLayerTreeView m_webLayerTreeView;
+    TestWebViewClient m_webViewClient;
+    FrameTestHelpers::WebViewHelper m_helper;
+};
+
+TEST_F(WebViewImplPaintArtifactCompositorTest, AttachAndDetach)
+{
+    paintArtifactCompositor().initializeIfNeeded();
+    cc::Layer* rootLayer = paintArtifactCompositor().rootLayer();
+    ASSERT_TRUE(rootLayer);
+
+    EXPECT_CALL(webLayerTreeView(), setRootLayer(Property(&WebLayer::ccLayer, rootLayer)));
+    webViewImpl().attachPaintArtifactCompositor();
+    testing::Mock::VerifyAndClearExpectations(&webLayerTreeView());
+
+    EXPECT_CALL(webLayerTreeView(), clearRootLayer());
+    webViewImpl().detachPaintArtifactCompositor();
+    testing::Mock::VerifyAndClearExpectations(&webLayerTreeView());
+}
+
+} // namespace
+} // namespace blink
diff --git a/third_party/WebKit/Source/web/mac/WebScrollbarTheme.mm b/third_party/WebKit/Source/web/mac/WebScrollbarTheme.mm
index 804db7ee..78e6028d 100644
--- a/third_party/WebKit/Source/web/mac/WebScrollbarTheme.mm
+++ b/third_party/WebKit/Source/web/mac/WebScrollbarTheme.mm
@@ -47,11 +47,11 @@
     float initialButtonDelay, float autoscrollButtonDelay,
     ScrollerStyle preferredScrollerStyle, bool redraw, bool scrollAnimationEnabled, ScrollbarButtonsPlacement buttonPlacement)
 {
-    ScrollbarTheme* theme = ScrollbarTheme::theme();
-    if (theme->isMockTheme())
+    ScrollbarTheme& theme = ScrollbarTheme::theme();
+    if (theme.isMockTheme())
         return;
 
-    static_cast<ScrollbarThemeMacCommon*>(ScrollbarTheme::theme())->preferencesChanged(
+    static_cast<ScrollbarThemeMacCommon&>(theme).preferencesChanged(
         initialButtonDelay, autoscrollButtonDelay,
         static_cast<NSScrollerStyle>(preferredScrollerStyle),
         redraw, scrollAnimationEnabled, buttonPlacement);
diff --git a/third_party/WebKit/Source/web/tests/FrameTestHelpers.h b/third_party/WebKit/Source/web/tests/FrameTestHelpers.h
index 74be950..22302709 100644
--- a/third_party/WebKit/Source/web/tests/FrameTestHelpers.h
+++ b/third_party/WebKit/Source/web/tests/FrameTestHelpers.h
@@ -87,7 +87,7 @@
     {
         Settings::setMockScrollbarsEnabled(true);
         RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(true);
-        EXPECT_TRUE(ScrollbarTheme::theme()->usesOverlayScrollbars());
+        EXPECT_TRUE(ScrollbarTheme::theme().usesOverlayScrollbars());
     }
 
     ~UseMockScrollbarSettings()
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index 0e164e8..50dcaf209 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -2034,7 +2034,7 @@
 
     webViewHelper.webView()->setPageScaleFactor(2);
 
-    EXPECT_EQ(980, toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->contentLayoutObject()->unscaledDocumentRect().width());
+    EXPECT_EQ(980, toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->contentLayoutObject()->documentRect().width());
     EXPECT_EQ(980, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
 }
 
diff --git a/third_party/WebKit/Source/web/tests/WebPageSerializerTest.cpp b/third_party/WebKit/Source/web/tests/WebPageSerializerTest.cpp
index c7b87e5..c03377a 100644
--- a/third_party/WebKit/Source/web/tests/WebPageSerializerTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebPageSerializerTest.cpp
@@ -85,10 +85,10 @@
         KURL parsedURL(ParsedURLString, url);
         URLTestHelpers::registerMockedURLLoad(parsedURL, fileName, "pageserialization/", "text/html");
         FrameTestHelpers::loadFrame(mainFrameImpl(), url.utf8().data());
-        WebVector<WebURL> links(&parsedURL, 1);
-        WebVector<WebString> localPaths(&"local", 1);
+        std::vector<std::pair<WebURL, WebString>> urlsToLocalPaths;
+        urlsToLocalPaths.push_back(std::make_pair(parsedURL, WebString("local")));
         SimpleWebPageSerializerClient serializerClient;
-        WebPageSerializer::serialize(mainFrameImpl(), &serializerClient, links, localPaths, "");
+        WebPageSerializer::serialize(mainFrameImpl(), &serializerClient, urlsToLocalPaths);
         return serializerClient.toString();
     }
 
diff --git a/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp b/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp
index 6ff2ebb..918cbbd 100644
--- a/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp
@@ -287,9 +287,9 @@
     runPendingTasks();
 
     WebElement pluginContainerOneElement = webView->mainFrame()->document().getElementById(WebString::fromUTF8("translated-plugin"));
-    PlatformEvent::Modifiers modifierKey = PlatformEvent::CtrlKey;
+    PlatformEvent::Modifiers modifierKey = static_cast<PlatformEvent::Modifiers>(PlatformEvent::CtrlKey | PlatformEvent::NumLockOn | PlatformEvent::IsLeft);
 #if OS(MACOSX)
-    modifierKey = PlatformEvent::MetaKey;
+    modifierKey = static_cast<PlatformEvent::Modifiers>(PlatformEvent::MetaKey | PlatformEvent::NumLockOn | PlatformEvent::IsLeft);
 #endif
     PlatformKeyboardEvent platformKeyboardEventC(PlatformEvent::RawKeyDown, "", "", "67", "", "", 67, 0, false, modifierKey, 0.0);
     RefPtrWillBeRawPtr<KeyboardEvent> keyEventC = KeyboardEvent::create(platformKeyboardEventC, 0);
diff --git a/third_party/WebKit/Source/web/web.gypi b/third_party/WebKit/Source/web/web.gypi
index 70ffdc7..21b61a64 100644
--- a/third_party/WebKit/Source/web/web.gypi
+++ b/third_party/WebKit/Source/web/web.gypi
@@ -254,6 +254,7 @@
       'WebEmbeddedWorkerImplTest.cpp',
       'WebNodeTest.cpp',
       'WebElementTest.cpp',
+      'WebViewImplPaintArtifactCompositorTest.cpp',
       # FIXME: Move the tests from web/tests/ to appropriate places.
       # crbug.com/353585
       'tests/ActivityLoggerTest.cpp',
diff --git a/third_party/WebKit/Source/wtf/BUILD.gn b/third_party/WebKit/Source/wtf/BUILD.gn
index f4e21d7..5db6483a 100644
--- a/third_party/WebKit/Source/wtf/BUILD.gn
+++ b/third_party/WebKit/Source/wtf/BUILD.gn
@@ -95,6 +95,15 @@
   }
 }
 
+# TODO(GYP): Delete this after we've converted everything to GN.
+# The _run targets exist only for compatibility w/ GYP.
+group("wtf_unittests_run") {
+  testonly = true
+  deps = [
+    ":wtf_unittests",
+  ]
+}
+
 test("wtf_unittests") {
   visibility = []  # Allow re-assignment of list.
   visibility = [ "*" ]
diff --git a/third_party/WebKit/Source/wtf/BitVector.cpp b/third_party/WebKit/Source/wtf/BitVector.cpp
index 939875e..f85fdd2 100644
--- a/third_party/WebKit/Source/wtf/BitVector.cpp
+++ b/third_party/WebKit/Source/wtf/BitVector.cpp
@@ -79,6 +79,7 @@
     // will erroneously report a leak here.
     WTF_INTERNAL_LEAK_SANITIZER_DISABLED_SCOPE;
     numBits = (numBits + bitsInPointer() - 1) & ~(bitsInPointer() - 1);
+    numBits = (numBits + bitsInPointer() - 1) & ~(bitsInPointer() - static_cast<size_t>(1));
     size_t size = sizeof(OutOfLineBits) + sizeof(uintptr_t) * (numBits / bitsInPointer());
     void* allocation = Partitions::bufferMalloc(size, WTF_HEAP_PROFILER_TYPE_NAME(OutOfLineBits));
     OutOfLineBits* result = new (NotNull, allocation) OutOfLineBits(numBits);
diff --git a/third_party/WebKit/Source/wtf/CPU.h b/third_party/WebKit/Source/wtf/CPU.h
index a7035e5..dc80f30 100644
--- a/third_party/WebKit/Source/wtf/CPU.h
+++ b/third_party/WebKit/Source/wtf/CPU.h
@@ -176,9 +176,12 @@
 #define WTF_CPU_64BIT 1
 #endif
 
-/* This defines CPU(64BIT). */
-#if defined(__mips__) && (_MIPS_SIM == _ABI64)
+/* CPU(MIPS), CPU(MIPS64) */
+#if defined(__mips__) && (__mips == 64)
+#define WTF_CPU_MIPS64 1
 #define WTF_CPU_64BIT 1
+#elif defined(__mips__)
+#define WTF_CPU_MIPS 1
 #endif
 
 #if !defined(WTF_CPU_64BIT)
diff --git a/third_party/WebKit/Source/wtf/SpinLock.cpp b/third_party/WebKit/Source/wtf/SpinLock.cpp
index c85203b..968e4320 100644
--- a/third_party/WebKit/Source/wtf/SpinLock.cpp
+++ b/third_party/WebKit/Source/wtf/SpinLock.cpp
@@ -32,7 +32,14 @@
 #define YIELD_PROCESSOR __asm__ __volatile__("pause")
 #elif CPU(ARM) || CPU(ARM64)
 #define YIELD_PROCESSOR __asm__ __volatile__("yield")
-#elif defined(__mips__) && __mips_isa_rev >= 2
+#elif CPU(MIPS)
+// The MIPS32 docs state that the PAUSE instruction is a no-op on older
+// architectures (first added in MIPS32r2). To avoid assembler errors when
+// targeting pre-r2, we must encode the instruction manually.
+#define YIELD_PROCESSOR __asm__ __volatile__(".word 0x00000140")
+#elif CPU(MIPS64) && __mips_isa_rev >= 2
+// Don't bother doing using .word here since r2 is the lowest supported mips64
+// that Chromium supports.
 #define YIELD_PROCESSOR __asm__ __volatile__("pause")
 #endif
 #endif
diff --git a/third_party/WebKit/Source/wtf/TypeTraits.h b/third_party/WebKit/Source/wtf/TypeTraits.h
index c4a8ab85..5a3cc98b 100644
--- a/third_party/WebKit/Source/wtf/TypeTraits.h
+++ b/third_party/WebKit/Source/wtf/TypeTraits.h
@@ -178,8 +178,9 @@
     static const bool value = __is_polymorphic(T);
 };
 
-#if COMPILER(MSVC) && !COMPILER(CLANG)
+#if (COMPILER(MSVC) || !GCC_VERSION_AT_LEAST(4, 9, 0)) && !COMPILER(CLANG)
 // FIXME: MSVC bug workaround. Remove once MSVC STL is fixed.
+// FIXME: GCC before 4.9.0 seems to have the same issue.
 // C++ 2011 Spec (ISO/IEC 14882:2011(E)) 20.9.6.2 Table 51 states that
 // the template parameters shall be a complete type if they are different types.
 // However, MSVC checks for type completeness even if they are the same type.
diff --git a/third_party/WebKit/Source/wtf/text/AtomicString.h b/third_party/WebKit/Source/wtf/text/AtomicString.h
index 0a83aa7..32468cda 100644
--- a/third_party/WebKit/Source/wtf/text/AtomicString.h
+++ b/third_party/WebKit/Source/wtf/text/AtomicString.h
@@ -107,16 +107,16 @@
     bool startsWith(UChar character) const
         { return m_string.startsWith(character); }
     template<unsigned matchLength>
-    bool startsWith(const char (&prefix)[matchLength], TextCaseSensitivity caseSensitivity = TextCaseSensitive) const
-        { return m_string.startsWith<matchLength>(prefix, caseSensitivity); }
+    bool startsWith(const char (&prefix)[matchLength]) const
+        { return m_string.startsWith<matchLength>(prefix); }
 
     bool endsWith(const String& s, TextCaseSensitivity caseSensitivity = TextCaseSensitive) const
         { return m_string.endsWith(s, caseSensitivity); }
     bool endsWith(UChar character) const
         { return m_string.endsWith(character); }
     template<unsigned matchLength>
-    bool endsWith(const char (&prefix)[matchLength], TextCaseSensitivity caseSensitivity = TextCaseSensitive) const
-        { return m_string.endsWith<matchLength>(prefix, caseSensitivity); }
+    bool endsWith(const char (&prefix)[matchLength]) const
+        { return m_string.endsWith<matchLength>(prefix); }
 
     AtomicString lower() const;
     AtomicString upper() const { return AtomicString(impl()->upper()); }
diff --git a/third_party/WebKit/Source/wtf/text/StringImpl.cpp b/third_party/WebKit/Source/wtf/text/StringImpl.cpp
index 2163aaf..d3a07291 100644
--- a/third_party/WebKit/Source/wtf/text/StringImpl.cpp
+++ b/third_party/WebKit/Source/wtf/text/StringImpl.cpp
@@ -651,23 +651,26 @@
     return newImpl.release();
 }
 
-static bool inline localeIdMatchesLang(const AtomicString& localeId, const char* lang)
+ALWAYS_INLINE static bool startsWithIgnoringCase(const StringImpl* stringImpl, const LChar* prefix, unsigned prefixLength)
 {
-    if (equalIgnoringCase(localeId, lang))
-        return true;
-    static char localeIdPrefix[4];
-    static const char delimeter[4] = "-_@";
+    ASSERT(stringImpl);
+    if (prefixLength > stringImpl->length())
+        return false;
+    if (stringImpl->is8Bit())
+        return equalIgnoringCase(stringImpl->characters8(), prefix, prefixLength);
+    return equalIgnoringCase(stringImpl->characters16(), prefix, prefixLength);
+}
 
+static inline bool localeIdMatchesLang(const AtomicString& localeId, const char* lang)
+{
     size_t langLength = strlen(lang);
     RELEASE_ASSERT(langLength >= 2 && langLength <= 3);
-    strncpy(localeIdPrefix, lang, langLength);
-    for (int i = 0; i < 3; ++i) {
-        localeIdPrefix[langLength] = delimeter[i];
-        // case-insensitive comparison
-        if (localeId.impl() && localeId.impl()->startsWith(localeIdPrefix, langLength + 1, TextCaseInsensitive))
-            return true;
-    }
-    return false;
+    if (!localeId.impl() || !startsWithIgnoringCase(localeId.impl(), reinterpret_cast<const LChar*>(lang), langLength))
+        return false;
+    if (localeId.impl()->length() == langLength)
+        return true;
+    const UChar maybeDelimiter = (*localeId.impl())[langLength];
+    return maybeDelimiter == '-' || maybeDelimiter == '_' || maybeDelimiter == '@';
 }
 
 typedef int32_t (*icuCaseConverter)(UChar*, int32_t, const UChar*, int32_t, const char*, UErrorCode*);
@@ -1463,20 +1466,15 @@
     return reverseFindIgnoringCaseInner(characters16(), matchString->characters16(), index, ourLength, matchLength);
 }
 
-ALWAYS_INLINE static bool equalInner(const StringImpl* stringImpl, unsigned startOffset, const char* matchString, unsigned matchLength, TextCaseSensitivity caseSensitivity)
+ALWAYS_INLINE static bool equalInner(const StringImpl* stringImpl, unsigned startOffset, const LChar* matchString, unsigned matchLength)
 {
     ASSERT(stringImpl);
     ASSERT(matchLength <= stringImpl->length());
     ASSERT(startOffset + matchLength <= stringImpl->length());
 
-    if (caseSensitivity == TextCaseSensitive) {
-        if (stringImpl->is8Bit())
-            return equal(stringImpl->characters8() + startOffset, reinterpret_cast<const LChar*>(matchString), matchLength);
-        return equal(stringImpl->characters16() + startOffset, reinterpret_cast<const LChar*>(matchString), matchLength);
-    }
     if (stringImpl->is8Bit())
-        return equalIgnoringCase(stringImpl->characters8() + startOffset, reinterpret_cast<const LChar*>(matchString), matchLength);
-    return equalIgnoringCase(stringImpl->characters16() + startOffset, reinterpret_cast<const LChar*>(matchString), matchLength);
+        return equal(stringImpl->characters8() + startOffset, matchString, matchLength);
+    return equal(stringImpl->characters16() + startOffset, matchString, matchLength);
 }
 
 bool StringImpl::startsWith(UChar character) const
@@ -1484,24 +1482,68 @@
     return m_length && (*this)[0] == character;
 }
 
-bool StringImpl::startsWith(const char* matchString, unsigned matchLength, TextCaseSensitivity caseSensitivity) const
+bool StringImpl::startsWith(const char* matchString, unsigned matchLength) const
 {
     ASSERT(matchLength);
     if (matchLength > length())
         return false;
-    return equalInner(this, 0, matchString, matchLength, caseSensitivity);
+    return equalInner(this, 0, reinterpret_cast<const LChar*>(matchString), matchLength);
 }
 
-bool StringImpl::endsWith(StringImpl* matchString, TextCaseSensitivity caseSensitivity)
+ALWAYS_INLINE static bool equalSubstring(const StringImpl* stringImpl, unsigned startOffset, const StringImpl* matchString)
 {
+    ASSERT(stringImpl);
     ASSERT(matchString);
-    if (m_length >= matchString->m_length) {
-        unsigned start = m_length - matchString->m_length;
-        if (caseSensitivity == TextCaseSensitive)
-            return find(matchString, start) == start;
-        return findIgnoringCase(matchString, start) == start;
+    ASSERT(matchString->length() <= stringImpl->length());
+    ASSERT(startOffset + matchString->length() <= stringImpl->length());
+
+    unsigned matchLength = matchString->length();
+    if (stringImpl->is8Bit()) {
+        const LChar* start = stringImpl->characters8() + startOffset;
+        if (matchString->is8Bit())
+            return equal(start, matchString->characters8(), matchLength);
+        return equal(start, matchString->characters16(), matchLength);
     }
-    return false;
+    const UChar* start = stringImpl->characters16() + startOffset;
+    if (matchString->is8Bit())
+        return equal(start, matchString->characters8(), matchLength);
+    return equal(start, matchString->characters16(), matchLength);
+}
+
+bool StringImpl::startsWith(const StringImpl* prefix) const
+{
+    ASSERT(prefix);
+    if (prefix->length() > length())
+        return false;
+    return equalSubstring(this, 0, prefix);
+}
+
+ALWAYS_INLINE static bool equalSubstringIgnoringCase(const StringImpl* stringImpl, unsigned startOffset, const StringImpl* matchString)
+{
+    ASSERT(stringImpl);
+    ASSERT(matchString);
+    ASSERT(matchString->length() <= stringImpl->length());
+    ASSERT(startOffset + matchString->length() <= stringImpl->length());
+
+    unsigned matchLength = matchString->length();
+    if (stringImpl->is8Bit()) {
+        const LChar* start = stringImpl->characters8() + startOffset;
+        if (matchString->is8Bit())
+            return equalIgnoringCase(start, matchString->characters8(), matchLength);
+        return equalIgnoringCase(start, matchString->characters16(), matchLength);
+    }
+    const UChar* start = stringImpl->characters16() + startOffset;
+    if (matchString->is8Bit())
+        return equalIgnoringCase(start, matchString->characters8(), matchLength);
+    return equalIgnoringCase(start, matchString->characters16(), matchLength);
+}
+
+bool StringImpl::startsWithIgnoringCase(const StringImpl* prefix) const
+{
+    ASSERT(prefix);
+    if (prefix->length() > length())
+        return false;
+    return equalSubstringIgnoringCase(this, 0, prefix);
 }
 
 bool StringImpl::endsWith(UChar character) const
@@ -1509,13 +1551,30 @@
     return m_length && (*this)[m_length - 1] == character;
 }
 
-bool StringImpl::endsWith(const char* matchString, unsigned matchLength, TextCaseSensitivity caseSensitivity) const
+bool StringImpl::endsWith(const char* matchString, unsigned matchLength) const
 {
     ASSERT(matchLength);
     if (matchLength > length())
         return false;
-    unsigned startOffset = length() - matchLength;
-    return equalInner(this, startOffset, matchString, matchLength, caseSensitivity);
+    return equalInner(this, length() - matchLength, reinterpret_cast<const LChar*>(matchString), matchLength);
+}
+
+bool StringImpl::endsWith(const StringImpl* suffix) const
+{
+    ASSERT(suffix);
+    unsigned suffixLength = suffix->length();
+    if (suffixLength > length())
+        return false;
+    return equalSubstring(this, length() - suffixLength, suffix);
+}
+
+bool StringImpl::endsWithIgnoringCase(const StringImpl* suffix) const
+{
+    ASSERT(suffix);
+    unsigned suffixLength = suffix->length();
+    if (suffixLength > length())
+        return false;
+    return equalSubstringIgnoringCase(this, length() - suffixLength, suffix);
 }
 
 PassRefPtr<StringImpl> StringImpl::replace(UChar oldC, UChar newC)
diff --git a/third_party/WebKit/Source/wtf/text/StringImpl.h b/third_party/WebKit/Source/wtf/text/StringImpl.h
index cc01ab3..889e3252 100644
--- a/third_party/WebKit/Source/wtf/text/StringImpl.h
+++ b/third_party/WebKit/Source/wtf/text/StringImpl.h
@@ -383,17 +383,15 @@
 
     size_t count(LChar) const;
 
-    bool startsWith(StringImpl* str, TextCaseSensitivity caseSensitivity = TextCaseSensitive) { return ((caseSensitivity == TextCaseSensitive) ? reverseFind(str, 0) : reverseFindIgnoringCase(str, 0)) == 0; }
     bool startsWith(UChar) const;
-    bool startsWith(const char*, unsigned matchLength, TextCaseSensitivity) const;
-    template<unsigned matchLength>
-    bool startsWith(const char (&prefix)[matchLength], TextCaseSensitivity caseSensitivity = TextCaseSensitive) const { return startsWith(prefix, matchLength - 1, caseSensitivity); }
+    bool startsWith(const char*, unsigned matchLength) const;
+    bool startsWith(const StringImpl*) const;
+    bool startsWithIgnoringCase(const StringImpl*) const;
 
-    bool endsWith(StringImpl*, TextCaseSensitivity = TextCaseSensitive);
     bool endsWith(UChar) const;
-    bool endsWith(const char*, unsigned matchLength, TextCaseSensitivity) const;
-    template<unsigned matchLength>
-    bool endsWith(const char (&prefix)[matchLength], TextCaseSensitivity caseSensitivity = TextCaseSensitive) const { return endsWith(prefix, matchLength - 1, caseSensitivity); }
+    bool endsWith(const char*, unsigned matchLength) const;
+    bool endsWith(const StringImpl*) const;
+    bool endsWithIgnoringCase(const StringImpl*) const;
 
     PassRefPtr<StringImpl> replace(UChar, UChar);
     PassRefPtr<StringImpl> replace(UChar, StringImpl*);
diff --git a/third_party/WebKit/Source/wtf/text/WTFString.h b/third_party/WebKit/Source/wtf/text/WTFString.h
index f8e95c9..2f4be91 100644
--- a/third_party/WebKit/Source/wtf/text/WTFString.h
+++ b/third_party/WebKit/Source/wtf/text/WTFString.h
@@ -85,6 +85,10 @@
     StrictUTF8ConversionReplacingUnpairedSurrogatesWithFFFD
 };
 
+#define DISPATCH_CASE_OP(caseSensitivity, op, args)                     \
+    ((caseSensitivity == TextCaseSensitive) ? op args :                 \
+     op##IgnoringCase args)
+
 template<bool isSpecialCharacter(UChar), typename CharacterType>
 bool isAllSpecialCharacters(const CharacterType*, size_t);
 
@@ -236,9 +240,9 @@
 
     // Wrappers for find & reverseFind adding dynamic sensitivity check.
     size_t find(const LChar* str, unsigned start, TextCaseSensitivity caseSensitivity) const
-        { return (caseSensitivity == TextCaseSensitive) ? find(str, start) : findIgnoringCase(str, start); }
+        { return DISPATCH_CASE_OP(caseSensitivity, find, (str, start)); }
     size_t find(const String& str, unsigned start, TextCaseSensitivity caseSensitivity) const
-        { return (caseSensitivity == TextCaseSensitive) ? find(str, start) : findIgnoringCase(str, start); }
+        { return DISPATCH_CASE_OP(caseSensitivity, find, (str, start)); }
     size_t reverseFind(const String& str, unsigned start, TextCaseSensitivity caseSensitivity) const
         { return (caseSensitivity == TextCaseSensitive) ? reverseFind(str, start) : reverseFindIgnoringCase(str, start); }
 
@@ -261,20 +265,20 @@
     bool contains(const String& str, TextCaseSensitivity caseSensitivity = TextCaseSensitive) const { return find(str, 0, caseSensitivity) != kNotFound; }
 
     bool startsWith(const String& s, TextCaseSensitivity caseSensitivity = TextCaseSensitive) const
-        { return m_impl ? m_impl->startsWith(s.impl(), caseSensitivity) : s.isEmpty(); }
+        { return m_impl ? DISPATCH_CASE_OP(caseSensitivity, m_impl->startsWith, (s.impl())) : s.isEmpty(); }
     bool startsWith(UChar character) const
         { return m_impl ? m_impl->startsWith(character) : false; }
     template<unsigned matchLength>
-    bool startsWith(const char (&prefix)[matchLength], TextCaseSensitivity caseSensitivity = TextCaseSensitive) const
-        { return m_impl ? m_impl->startsWith<matchLength>(prefix, caseSensitivity) : !matchLength; }
+    bool startsWith(const char (&prefix)[matchLength]) const
+        { return m_impl ? m_impl->startsWith(prefix, matchLength - 1) : !matchLength; }
 
     bool endsWith(const String& s, TextCaseSensitivity caseSensitivity = TextCaseSensitive) const
-        { return m_impl ? m_impl->endsWith(s.impl(), caseSensitivity) : s.isEmpty(); }
+        { return m_impl ? DISPATCH_CASE_OP(caseSensitivity, m_impl->endsWith, (s.impl())) : s.isEmpty(); }
     bool endsWith(UChar character) const
         { return m_impl ? m_impl->endsWith(character) : false; }
     template<unsigned matchLength>
-    bool endsWith(const char (&prefix)[matchLength], TextCaseSensitivity caseSensitivity = TextCaseSensitive) const
-        { return m_impl ? m_impl->endsWith<matchLength>(prefix, caseSensitivity) : !matchLength; }
+    bool endsWith(const char (&prefix)[matchLength]) const
+        { return m_impl ? m_impl->endsWith(prefix, matchLength - 1) : !matchLength; }
 
     void append(const String&);
     void append(LChar);
@@ -466,6 +470,8 @@
     RefPtr<StringImpl> m_impl;
 };
 
+#undef DISPATCH_CASE_OP
+
 inline bool operator==(const String& a, const String& b) { return equal(a.impl(), b.impl()); }
 inline bool operator==(const String& a, const LChar* b) { return equal(a.impl(), b); }
 inline bool operator==(const String& a, const char* b) { return equal(a.impl(), reinterpret_cast<const LChar*>(b)); }
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index dde23d0..c605ad1 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -51,8 +51,8 @@
   public_deps = [
     "//third_party/WebKit/Source/core",
     "//third_party/WebKit/Source/modules",
-    "//third_party/WebKit/Source/platform:heap_unittests",
-    "//third_party/WebKit/Source/platform:platform_unittests",
+    "//third_party/WebKit/Source/platform:blink_heap_unittests",
+    "//third_party/WebKit/Source/platform:blink_platform_unittests",
     "//third_party/WebKit/Source/web",
     "//third_party/WebKit/Source/web:webkit_unit_tests",
     "//third_party/WebKit/Source/wtf:wtf_unittests",
@@ -61,8 +61,8 @@
   if (is_mac) {
     # TODO(GYP): Re-enable this as soon as we can link Blink binaries on mac.
     public_deps -= [
-      "//third_party/WebKit/Source/platform:heap_unittests",
-      "//third_party/WebKit/Source/platform:platform_unittests",
+      "//third_party/WebKit/Source/platform:blink_heap_unittests",
+      "//third_party/WebKit/Source/platform:blink_platform_unittests",
       "//third_party/WebKit/Source/web:webkit_unit_tests",
     ]
   }
diff --git a/third_party/WebKit/public/platform/WebScrollbarThemePainter.h b/third_party/WebKit/public/platform/WebScrollbarThemePainter.h
index fcbfe14b7..9675ac8e 100644
--- a/third_party/WebKit/public/platform/WebScrollbarThemePainter.h
+++ b/third_party/WebKit/public/platform/WebScrollbarThemePainter.h
@@ -71,7 +71,7 @@
     BLINK_PLATFORM_EXPORT bool thumbNeedsRepaint() const;
 
 #if INSIDE_BLINK
-    BLINK_PLATFORM_EXPORT WebScrollbarThemePainter(ScrollbarTheme*, Scrollbar*, float deviceScaleFactor);
+    BLINK_PLATFORM_EXPORT WebScrollbarThemePainter(ScrollbarTheme&, Scrollbar&, float deviceScaleFactor);
 #endif
 
 private:
diff --git a/third_party/WebKit/public/platform/WebURLResponse.h b/third_party/WebKit/public/platform/WebURLResponse.h
index c7a5b0b..3a64468 100644
--- a/third_party/WebKit/public/platform/WebURLResponse.h
+++ b/third_party/WebKit/public/platform/WebURLResponse.h
@@ -146,6 +146,8 @@
     BLINK_PLATFORM_EXPORT WebCString securityInfo() const;
     BLINK_PLATFORM_EXPORT void setSecurityInfo(const WebCString&);
 
+    BLINK_PLATFORM_EXPORT void setHasMajorCertificateErrors(bool);
+
     BLINK_PLATFORM_EXPORT SecurityStyle securityStyle() const;
     BLINK_PLATFORM_EXPORT void setSecurityStyle(SecurityStyle);
 
diff --git a/third_party/WebKit/public/web/WebDocument.h b/third_party/WebKit/public/web/WebDocument.h
index b81c119..16cb6c4 100644
--- a/third_party/WebKit/public/web/WebDocument.h
+++ b/third_party/WebKit/public/web/WebDocument.h
@@ -137,6 +137,9 @@
     BLINK_EXPORT bool manifestUseCredentials() const;
     BLINK_EXPORT WebDistillabilityFeatures distillabilityFeatures();
 
+    BLINK_EXPORT bool attemptedToDetermineEncodingFromContentSniffing() const;
+    BLINK_EXPORT bool encodingWasDetectedFromContentSniffing() const;
+
 #if BLINK_IMPLEMENTATION
     WebDocument(const PassRefPtrWillBeRawPtr<Document>&);
     WebDocument& operator=(const PassRefPtrWillBeRawPtr<Document>&);
diff --git a/third_party/WebKit/public/web/WebFrameClient.h b/third_party/WebKit/public/web/WebFrameClient.h
index e603a05..89f2cef 100644
--- a/third_party/WebKit/public/web/WebFrameClient.h
+++ b/third_party/WebKit/public/web/WebFrameClient.h
@@ -67,6 +67,7 @@
 class WebColorChooserClient;
 class WebContentDecryptionModule;
 class WebCookieJar;
+class WebCString;
 class WebDataSource;
 class WebEncryptedMediaClient;
 class WebExternalPopupMenu;
@@ -449,6 +450,13 @@
     // A PingLoader was created, and a request dispatched to a URL.
     virtual void didDispatchPingLoader(WebLocalFrame*, const WebURL&) { }
 
+    // This frame has displayed inactive content (such as an image) from
+    // a connection with certificate errors.
+    virtual void didDisplayContentWithCertificateErrors(const WebURL& url, const WebCString& securityInfo, const WebURL& mainResourceUrl, const WebCString& mainResourceSecurityInfo) {}
+    // This frame has run active content (such as a script) from a
+    // connection with certificate errors.
+    virtual void didRunContentWithCertificateErrors(const WebURL& url, const WebCString& securityInfo, const WebURL& mainResourceUrl, const WebCString& mainResourceSecurityInfo) {}
+
     // A performance timing event (e.g. first paint) occurred
     virtual void didChangePerformanceTiming() { }
 
diff --git a/third_party/WebKit/public/web/WebLocalFrame.h b/third_party/WebKit/public/web/WebLocalFrame.h
index d561de9..f048568 100644
--- a/third_party/WebKit/public/web/WebLocalFrame.h
+++ b/third_party/WebKit/public/web/WebLocalFrame.h
@@ -70,6 +70,11 @@
     // navigation.  This matches the in-process frame behavior.
     virtual void setFrameOwnerProperties(const WebFrameOwnerProperties&) = 0;
 
+    // Hierarchy ----------------------------------------------------------
+
+    // Get the highest-level LocalFrame in this frame's in-process subtree.
+    virtual WebLocalFrame* localRoot() = 0;
+
     // Navigation Ping --------------------------------------------------------
     virtual void sendPings(const WebNode& contextNode, const WebURL& destinationURL) = 0;
 
diff --git a/third_party/WebKit/public/web/WebPageSerializer.h b/third_party/WebKit/public/web/WebPageSerializer.h
index 285fc865..2ae2e25 100644
--- a/third_party/WebKit/public/web/WebPageSerializer.h
+++ b/third_party/WebKit/public/web/WebPageSerializer.h
@@ -69,17 +69,12 @@
     // The parameter client specifies the pointer of interface
     // WebPageSerializerClient providing a sink interface to receive the
     // individual chunks of data to be saved.
-    // The parameter links contain original URLs of all saved links.
-    // The parameter localPaths contain corresponding local file paths of all
-    // saved links, which matched with vector:links one by one.
-    // The parameter localDirectoryName is relative path of directory which
-    // contain all saved auxiliary files included all sub frames and resources.
+    // The parameter urlsToLocalPaths contains a mapping between original URLs
+    // of saved resources and corresponding local file paths.
     BLINK_EXPORT static bool serialize(
         WebLocalFrame*,
         WebPageSerializerClient*,
-        const WebVector<WebURL>& links,
-        const WebVector<WebString>& localPaths,
-        const WebString& localDirectoryName);
+        const WebVector<std::pair<WebURL, WebString>>& urlsToLocalPaths);
 
     // FIXME: The following are here for unit testing purposes. Consider
     // changing the unit tests instead.
diff --git a/third_party/WebKit/public/web/WebSharedWorkerCreationContextType.h b/third_party/WebKit/public/web/WebSharedWorkerCreationContextType.h
new file mode 100644
index 0000000..858a200
--- /dev/null
+++ b/third_party/WebKit/public/web/WebSharedWorkerCreationContextType.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 WebSharedWorkerCreationContextType_h
+#define WebSharedWorkerCreationContextType_h
+
+#include "../platform/WebCommon.h"
+
+namespace blink {
+
+// Describes the type of context (secure or non-secure) that created a SharedWorker.
+enum WebSharedWorkerCreationContextType {
+    // The shared worker was created from a nonsecure context.
+    WebSharedWorkerCreationContextTypeNonsecure = 0,
+    // The shared worker was created from a secure context.
+    WebSharedWorkerCreationContextTypeSecure,
+    WebSharedWorkerCreationContextTypeLast = WebSharedWorkerCreationContextTypeSecure
+};
+
+} // namespace blink
+
+#endif // WebSharedWorkerCreationContextType_h
diff --git a/third_party/WebKit/public/web/WebSharedWorkerRepositoryClient.h b/third_party/WebKit/public/web/WebSharedWorkerRepositoryClient.h
index 119d63a0..6f76261 100644
--- a/third_party/WebKit/public/web/WebSharedWorkerRepositoryClient.h
+++ b/third_party/WebKit/public/web/WebSharedWorkerRepositoryClient.h
@@ -32,6 +32,7 @@
 #define WebSharedWorkerRepositoryClient_h
 
 #include "WebSharedWorkerConnector.h"
+#include "WebSharedWorkerCreationContextType.h"
 #include "WebSharedWorkerCreationErrors.h"
 
 namespace blink {
@@ -46,7 +47,7 @@
     typedef unsigned long long DocumentID;
 
     // Creates a new shared worker connector. This may return null.
-    virtual WebSharedWorkerConnector* createSharedWorkerConnector(const WebURL& url, const WebString& name, DocumentID id, const WebString& contentSecurityPolicy, WebContentSecurityPolicyType, WebWorkerCreationError* error) { return 0; }
+    virtual WebSharedWorkerConnector* createSharedWorkerConnector(const WebURL& url, const WebString& name, DocumentID id, const WebString& contentSecurityPolicy, WebContentSecurityPolicyType, WebSharedWorkerCreationContextType, WebWorkerCreationError* error) { return 0; }
 
     // Invoked when a document has been detached. DocumentID can be re-used after documentDetached() is invoked.
     virtual void documentDetached(DocumentID) { }
diff --git a/third_party/cacheinvalidation/overrides/google/cacheinvalidation/deps/random.cc b/third_party/cacheinvalidation/overrides/google/cacheinvalidation/deps/random.cc
index 808baa65..585a6a2 100644
--- a/third_party/cacheinvalidation/overrides/google/cacheinvalidation/deps/random.cc
+++ b/third_party/cacheinvalidation/overrides/google/cacheinvalidation/deps/random.cc
@@ -10,7 +10,7 @@
   return base::RandDouble();
 }
 
-uint64 Random::RandUint64() {
+uint64_t Random::RandUint64() {
   return base::RandUint64();
 }
 
diff --git a/third_party/cacheinvalidation/overrides/google/cacheinvalidation/deps/random.h b/third_party/cacheinvalidation/overrides/google/cacheinvalidation/deps/random.h
index 55b3abc..c1f2317c3 100644
--- a/third_party/cacheinvalidation/overrides/google/cacheinvalidation/deps/random.h
+++ b/third_party/cacheinvalidation/overrides/google/cacheinvalidation/deps/random.h
@@ -5,6 +5,8 @@
 #ifndef GOOGLE_CACHEINVALIDATION_DEPS_RANDOM_H_
 #define GOOGLE_CACHEINVALIDATION_DEPS_RANDOM_H_
 
+#include <stdint.h>
+
 #include "base/rand_util.h"
 
 namespace invalidation {
@@ -12,14 +14,14 @@
 class Random {
  public:
   // We don't actually use the seed.
-  explicit Random(int64 seed) {}
+  explicit Random(int64_t seed) {}
 
   virtual ~Random() {}
 
   // Returns a pseudorandom value between(inclusive) and(exclusive).
   virtual double RandDouble();
 
-  virtual uint64 RandUint64();
+  virtual uint64_t RandUint64();
 };
 
 }  // namespace invalidation
diff --git a/third_party/instrumented_libraries/binaries/msan-chained-origins-precise.tgz.sha1 b/third_party/instrumented_libraries/binaries/msan-chained-origins-precise.tgz.sha1
index 71e2def..20136d13 100644
--- a/third_party/instrumented_libraries/binaries/msan-chained-origins-precise.tgz.sha1
+++ b/third_party/instrumented_libraries/binaries/msan-chained-origins-precise.tgz.sha1
@@ -1 +1 @@
-60669b8a67026d92b365c1a2cab756bfe2fdd90f
\ No newline at end of file
+b222c7d98598d5322e3ef5e114d625b5067db731
\ No newline at end of file
diff --git a/third_party/instrumented_libraries/binaries/msan-chained-origins-trusty.tgz.sha1 b/third_party/instrumented_libraries/binaries/msan-chained-origins-trusty.tgz.sha1
index 193be34..02e2f50 100644
--- a/third_party/instrumented_libraries/binaries/msan-chained-origins-trusty.tgz.sha1
+++ b/third_party/instrumented_libraries/binaries/msan-chained-origins-trusty.tgz.sha1
@@ -1 +1 @@
-348b21c99365227beb378e6f068984b0f6ea9f9f
\ No newline at end of file
+1ec036d6a13816e27b580906924a3f2e02e34f64
\ No newline at end of file
diff --git a/third_party/instrumented_libraries/binaries/msan-no-origins-precise.tgz.sha1 b/third_party/instrumented_libraries/binaries/msan-no-origins-precise.tgz.sha1
index 9f17c0d..988a11e 100644
--- a/third_party/instrumented_libraries/binaries/msan-no-origins-precise.tgz.sha1
+++ b/third_party/instrumented_libraries/binaries/msan-no-origins-precise.tgz.sha1
@@ -1 +1 @@
-2a66a901c3b0acd3e5c5cbf49ddfa442f77bb38e
\ No newline at end of file
+5d414da3a7a4e1341c8c0b45b9c4e08931861b98
\ No newline at end of file
diff --git a/third_party/instrumented_libraries/binaries/msan-no-origins-trusty.tgz.sha1 b/third_party/instrumented_libraries/binaries/msan-no-origins-trusty.tgz.sha1
index bbe66571..8ab5d98 100644
--- a/third_party/instrumented_libraries/binaries/msan-no-origins-trusty.tgz.sha1
+++ b/third_party/instrumented_libraries/binaries/msan-no-origins-trusty.tgz.sha1
@@ -1 +1 @@
-098097aa3f25d94b73014c9249a41bfe37f3242b
\ No newline at end of file
+86fc3acddd6561c11ffdafbc1ab326b14ac45c7b
\ No newline at end of file
diff --git a/third_party/libxml/libxml.gyp b/third_party/libxml/libxml.gyp
index 493ed04..54790f6 100644
--- a/third_party/libxml/libxml.gyp
+++ b/third_party/libxml/libxml.gyp
@@ -260,11 +260,11 @@
             ['OS=="mac" or OS=="android"', {'defines': ['_REENTRANT']}],
             ['OS=="win"', {
               'product_name': 'libxml2',
-              # Disable unimportant 'unused variable' warning, and
-              # signed/unsigned comparison warning. The signed/unsigned (4101)
-              # is fixed upstream and can be removed eventually.
+              # Disable unimportant 'unused variable' warning.
               # TODO(jschuh): http://crbug.com/167187 size_t -> int
-              'msvs_disabled_warnings': [ 4018, 4101, 4267 ],
+              # TODO(brucedawson): http://crbug.com/554200 fix C4311 warnings
+              # C4311 is a VS 2015 64-bit warning for pointer truncation
+              'msvs_disabled_warnings': [ 4018, 4267, 4311, ],
             }, {  # else: OS!="win"
               'product_name': 'xml2',
             }],
diff --git a/third_party/libxslt/libxslt.gyp b/third_party/libxslt/libxslt.gyp
index b543659..19ea0b1 100644
--- a/third_party/libxslt/libxslt.gyp
+++ b/third_party/libxslt/libxslt.gyp
@@ -109,6 +109,9 @@
           'msvs_disabled_warnings': [
             # size_t to int conversion.
             4267,
+            # TODO(brucedawson): http://crbug.com/554200 4311 is a VS
+            # 2015 64-bit warning for pointer truncation
+            4311,
           ],
           'variables': {
             'clang_warning_flags': [
diff --git a/third_party/mesa/mesa.gyp b/third_party/mesa/mesa.gyp
index 37350ab..367e5ec 100644
--- a/third_party/mesa/mesa.gyp
+++ b/third_party/mesa/mesa.gyp
@@ -271,6 +271,9 @@
       # Mesa is ever rolled and the warnings are fixed.
       'msvs_disabled_warnings': [
           4005, 4018, 4090, 4099, 4146, 4291, 4305, 4334, 4748, 4267,
+          # TODO(brucedawson): http://crbug.com/554200 4311 is a VS
+          # 2015 64-bit warning for pointer truncation
+          4311,
       ],
       'variables': {
         'clang_warning_flags': [
diff --git a/third_party/mojo/mojo_edk_tests.gyp b/third_party/mojo/mojo_edk_tests.gyp
index 376a3e4..c02e21d5 100644
--- a/third_party/mojo/mojo_edk_tests.gyp
+++ b/third_party/mojo/mojo_edk_tests.gyp
@@ -24,7 +24,6 @@
         'mojo_public_system_unittests',
         'mojo_public_utility_unittests',
         'mojo_system_unittests',
-        'mojo_js_unittests',
         'mojo_js_integration_tests',
       ],
     },
@@ -256,24 +255,6 @@
       ],
     },
     {
-      # GN version: //mojo/edk/js/test:js_unittests
-      'target_name': 'mojo_js_unittests',
-      'type': 'executable',
-      'dependencies': [
-        '../../gin/gin.gyp:gin_test',
-        'mojo_edk.gyp:mojo_common_test_support',
-        'mojo_edk.gyp:mojo_run_all_unittests',
-        'mojo_edk.gyp:mojo_js_lib',
-        'mojo_public.gyp:mojo_environment_standalone',
-        'mojo_public.gyp:mojo_public_test_interfaces',
-        'mojo_public.gyp:mojo_utility',
-      ],
-      'sources': [
-        'src/mojo/edk/js/handle_unittest.cc',
-        'src/mojo/edk/js/test/run_js_tests.cc',
-      ],
-    },
-    {
       # GN version: //mojo/edk/js/test:js_integration_tests
       'target_name': 'mojo_js_integration_tests',
       'type': 'executable',
diff --git a/third_party/mojo/mojo_public.gyp b/third_party/mojo/mojo_public.gyp
index f21e1760..4f88b85 100644
--- a/third_party/mojo/mojo_public.gyp
+++ b/third_party/mojo/mojo_public.gyp
@@ -69,6 +69,7 @@
         '../../mojo/public/c/system/message_pipe.h',
         '../../mojo/public/c/system/system_export.h',
         '../../mojo/public/c/system/types.h',
+        '../../mojo/public/c/system/wait_set.h',
       ],
     },
     {
diff --git a/third_party/mojo/src/mojo/edk/embedder/entrypoints.cc b/third_party/mojo/src/mojo/edk/embedder/entrypoints.cc
index 024b6d6..f6e7de50 100644
--- a/third_party/mojo/src/mojo/edk/embedder/entrypoints.cc
+++ b/third_party/mojo/src/mojo/edk/embedder/entrypoints.cc
@@ -66,6 +66,40 @@
                           MakeUserPointer(signals_states));
 }
 
+MojoResult MojoCreateWaitSet(MojoHandle* wait_set_handle) {
+  if (UseNewEDK())
+    return MOJO_RESULT_UNIMPLEMENTED;
+  return g_core->CreateWaitSet(MakeUserPointer(wait_set_handle));
+}
+
+MojoResult MojoAddHandle(MojoHandle wait_set_handle,
+                         MojoHandle handle,
+                         MojoHandleSignals signals) {
+  if (UseNewEDK())
+    return MOJO_RESULT_UNIMPLEMENTED;
+  return g_core->AddHandle(wait_set_handle, handle, signals);
+}
+
+MojoResult MojoRemoveHandle(MojoHandle wait_set_handle,
+                            MojoHandle handle) {
+  if (UseNewEDK())
+    return MOJO_RESULT_UNIMPLEMENTED;
+  return g_core->RemoveHandle(wait_set_handle, handle);
+}
+
+MojoResult MojoGetReadyHandles(MojoHandle wait_set_handle,
+                               uint32_t* count,
+                               MojoHandle* handles,
+                               MojoResult* results,
+                               struct MojoHandleSignalsState *signals_states) {
+  if (UseNewEDK())
+    return MOJO_RESULT_UNIMPLEMENTED;
+  return g_core->GetReadyHandles(wait_set_handle, MakeUserPointer(count),
+                                 MakeUserPointer(handles),
+                                 MakeUserPointer(results),
+                                 MakeUserPointer(signals_states));
+}
+
 MojoResult MojoCreateMessagePipe(const MojoCreateMessagePipeOptions* options,
                                  MojoHandle* message_pipe_handle0,
                                  MojoHandle* message_pipe_handle1) {
diff --git a/third_party/mojo/src/mojo/edk/js/BUILD.gn b/third_party/mojo/src/mojo/edk/js/BUILD.gn
index 303514a..2f9ce41 100644
--- a/third_party/mojo/src/mojo/edk/js/BUILD.gn
+++ b/third_party/mojo/src/mojo/edk/js/BUILD.gn
@@ -12,7 +12,6 @@
   testonly = true
   deps = [
     "test:js_integration_tests",
-    "test:js_unittests",
   ]
 }
 
diff --git a/third_party/mojo/src/mojo/edk/js/test/BUILD.gn b/third_party/mojo/src/mojo/edk/js/test/BUILD.gn
index eab19574..c0df82f 100644
--- a/third_party/mojo/src/mojo/edk/js/test/BUILD.gn
+++ b/third_party/mojo/src/mojo/edk/js/test/BUILD.gn
@@ -4,27 +4,6 @@
 
 import("//testing/test.gni")
 
-test("js_unittests") {
-  deps = [
-    "../../js",
-    "../../js:js_unittests",
-    "../../test:run_all_unittests",
-    "../../test:test_support",
-    "//base",
-    "//gin:gin_test",
-    "//mojo/environment:chromium",
-    "//mojo/public/cpp/environment",
-    "//mojo/public/cpp/system",
-    "//mojo/public/cpp/utility",
-    "//mojo/public/interfaces/bindings/tests:test_interfaces",
-    "//mojo/public/interfaces/bindings/tests:test_interfaces_experimental",
-  ]
-
-  sources = [
-    "run_js_tests.cc",
-  ]
-}
-
 test("js_integration_tests") {
   deps = [
     "../../js",
diff --git a/third_party/mojo/src/mojo/edk/system/core.cc b/third_party/mojo/src/mojo/edk/system/core.cc
index e1e6ec9..d82c845 100644
--- a/third_party/mojo/src/mojo/edk/system/core.cc
+++ b/third_party/mojo/src/mojo/edk/system/core.cc
@@ -185,6 +185,56 @@
   return rv;
 }
 
+MojoResult Core::CreateWaitSet(UserPointer<MojoHandle> wait_set_handle) {
+  if (wait_set_handle.IsNull())
+    return MOJO_RESULT_INVALID_ARGUMENT;
+
+  return MOJO_RESULT_UNIMPLEMENTED;
+}
+
+MojoResult Core::AddHandle(MojoHandle wait_set_handle,
+                           MojoHandle handle,
+                           MojoHandleSignals signals) {
+  scoped_refptr<Dispatcher> wait_set_dispatcher(GetDispatcher(wait_set_handle));
+  if (!wait_set_dispatcher)
+    return MOJO_RESULT_INVALID_ARGUMENT;
+
+  scoped_refptr<Dispatcher> dispatcher(GetDispatcher(handle));
+  if (!dispatcher)
+    return MOJO_RESULT_INVALID_ARGUMENT;
+
+  return MOJO_RESULT_UNIMPLEMENTED;
+}
+
+MojoResult Core::RemoveHandle(MojoHandle wait_set_handle,
+                              MojoHandle handle) {
+  scoped_refptr<Dispatcher> wait_set_dispatcher(GetDispatcher(wait_set_handle));
+  if (!wait_set_dispatcher)
+    return MOJO_RESULT_INVALID_ARGUMENT;
+
+  scoped_refptr<Dispatcher> dispatcher(GetDispatcher(handle));
+  if (!dispatcher)
+    return MOJO_RESULT_INVALID_ARGUMENT;
+
+  return MOJO_RESULT_UNIMPLEMENTED;
+}
+
+MojoResult Core::GetReadyHandles(
+    MojoHandle wait_set_handle,
+    UserPointer<uint32_t> count,
+    UserPointer<MojoHandle> handles,
+    UserPointer<MojoResult> results,
+    UserPointer<MojoHandleSignalsState> signals_states) {
+  scoped_refptr<Dispatcher> wait_set_dispatcher(GetDispatcher(wait_set_handle));
+  if (!wait_set_dispatcher)
+    return MOJO_RESULT_INVALID_ARGUMENT;
+
+  if (count.IsNull() || !count.Get() || handles.IsNull() || results.IsNull())
+    return MOJO_RESULT_INVALID_ARGUMENT;
+
+  return MOJO_RESULT_UNIMPLEMENTED;
+}
+
 MojoResult Core::CreateMessagePipe(
     UserPointer<const MojoCreateMessagePipeOptions> options,
     UserPointer<MojoHandle> message_pipe_handle0,
diff --git a/third_party/mojo/src/mojo/edk/system/core.h b/third_party/mojo/src/mojo/edk/system/core.h
index 2dc504b..4d670d31 100644
--- a/third_party/mojo/src/mojo/edk/system/core.h
+++ b/third_party/mojo/src/mojo/edk/system/core.h
@@ -88,6 +88,21 @@
                       UserPointer<MojoHandleSignalsState> signals_states);
 
   // These methods correspond to the API functions defined in
+  // "mojo/public/c/system/wait_set.h":
+  MojoResult CreateWaitSet(UserPointer<MojoHandle> wait_set_handle);
+  MojoResult AddHandle(MojoHandle wait_set_handle,
+                       MojoHandle handle,
+                       MojoHandleSignals signals);
+  MojoResult RemoveHandle(MojoHandle wait_set_handle,
+                          MojoHandle handle);
+  MojoResult GetReadyHandles(
+      MojoHandle wait_set_handle,
+      UserPointer<uint32_t> count,
+      UserPointer<MojoHandle> handles,
+      UserPointer<MojoResult> results,
+      UserPointer<MojoHandleSignalsState> signals_states);
+
+  // These methods correspond to the API functions defined in
   // "mojo/public/c/system/message_pipe.h":
   MojoResult CreateMessagePipe(
       UserPointer<const MojoCreateMessagePipeOptions> options,
diff --git a/third_party/mojo/src/mojo/edk/test/run_all_perftests.cc b/third_party/mojo/src/mojo/edk/test/run_all_perftests.cc
index 41b5ab26..d82df61 100644
--- a/third_party/mojo/src/mojo/edk/test/run_all_perftests.cc
+++ b/third_party/mojo/src/mojo/edk/test/run_all_perftests.cc
@@ -8,7 +8,8 @@
 #include "third_party/mojo/src/mojo/edk/test/test_support_impl.h"
 
 int main(int argc, char** argv) {
+  base::PerfTestSuite test_suite(argc, argv);
   mojo::embedder::Init();
   mojo::test::TestSupport::Init(new mojo::test::TestSupportImpl());
-  return base::PerfTestSuite(argc, argv).Run();
+  return test_suite.Run();
 }
diff --git a/third_party/sqlite/amalgamation/sqlite3.c b/third_party/sqlite/amalgamation/sqlite3.c
index 80d4c22..0767027 100644
--- a/third_party/sqlite/amalgamation/sqlite3.c
+++ b/third_party/sqlite/amalgamation/sqlite3.c
@@ -7566,25 +7566,12 @@
 void chromium_sqlite3_initialize_win_sqlite3_file(sqlite3_file* file, HANDLE handle);
 #else  /* _WIN32 */
 CHROMIUM_SQLITE_API
-void chromium_sqlite3_initialize_unix_sqlite3_file(sqlite3_file* file);
-CHROMIUM_SQLITE_API
-int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* vfs,
+int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs,
                                                int fd,
-                                               int dirfd,
-                                               sqlite3_file* file,
-                                               const char* fileName,
-                                               int noLock);
-CHROMIUM_SQLITE_API
-int chromium_sqlite3_get_reusable_file_handle(sqlite3_file* file,
-                                              const char* fileName,
-                                              int flags,
-                                              int* fd);
-CHROMIUM_SQLITE_API
-void chromium_sqlite3_update_reusable_file_handle(sqlite3_file* file,
-                                                  int fd,
-                                                  int flags);
-CHROMIUM_SQLITE_API
-void chromium_sqlite3_destroy_reusable_file_handle(sqlite3_file* file);
+                                               sqlite3_file* pFile,
+                                               const char* zPath,
+                                               int noLock,
+                                               int flags);
 #endif  /* _WIN32 */
 #endif  /* CHROMIUM_SQLITE_INTERNALS */
 /* End WebDatabase patch for Chromium */
@@ -30494,75 +30481,41 @@
 }
 
 /*
-** Initializes a unixFile structure with zeros.
+** Initialize |unixFile| internals of |file| on behalf of chromiumOpen() in
+** WebDatabase SQLiteFileSystemPosix.cpp.  Function is a subset of unixOpen(),
+** each duplicated piece is marked by "Duplicated in" comment in unixOpen().
 */
 CHROMIUM_SQLITE_API
-void chromium_sqlite3_initialize_unix_sqlite3_file(sqlite3_file* file) {
-  memset(file, 0, sizeof(unixFile));
-}
-
-CHROMIUM_SQLITE_API
-int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* vfs,
+int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs,
                                                int fd,
-                                               int dirfd,
-                                               sqlite3_file* file,
-                                               const char* fileName,
-                                               int noLock) {
-  int ctrlFlags = (noLock ? UNIXFILE_NOLOCK : 0);
-  return fillInUnixFile(vfs, fd, file, fileName, ctrlFlags);
-}
+                                               sqlite3_file* pFile,
+                                               const char* zPath,
+                                               int noLock,
+                                               int flags) {
+  unixFile *p = (unixFile *)pFile;
+  const int eType = flags&0xFFFFFF00;  /* Type of file to open */
+  const int ctrlFlags = (noLock ? UNIXFILE_NOLOCK : 0);
+  int rc;
 
-/*
-** Search for an unused file descriptor that was opened on the database file.
-** If a suitable file descriptor if found, then it is stored in *fd; otherwise,
-** *fd is not modified.
-**
-** If a reusable file descriptor is not found, and a new UnixUnusedFd cannot
-** be allocated, SQLITE_NOMEM is returned. Otherwise, SQLITE_OK is returned.
-*/
-CHROMIUM_SQLITE_API
-int chromium_sqlite3_get_reusable_file_handle(sqlite3_file* file,
-                                              const char* fileName,
-                                              int flags,
-                                              int* fd) {
-  unixFile* unixSQLite3File = (unixFile*)file;
-  int fileType = flags & 0xFFFFFF00;
-  if (fileType == SQLITE_OPEN_MAIN_DB) {
-    UnixUnusedFd *unusedFd = findReusableFd(fileName, flags);
-    if (unusedFd) {
-      *fd = unusedFd->fd;
-    } else {
-      unusedFd = sqlite3_malloc(sizeof(*unusedFd));
-      if (!unusedFd) {
-        return SQLITE_NOMEM;
-      }
+  memset(p, 0, sizeof(unixFile));
+
+  /* osStat() will not work in the sandbox, so findReusableFd() will always
+  ** fail, so directly include the failure-case setup then initialize pUnused.
+  */
+  if( eType==SQLITE_OPEN_MAIN_DB ){
+    p->pUnused = sqlite3_malloc(sizeof(*p->pUnused));
+    if (!p->pUnused) {
+      return SQLITE_NOMEM;
     }
-    unixSQLite3File->pUnused = unusedFd;
+    p->pUnused->fd = fd;
+    p->pUnused->flags = flags;
   }
-  return SQLITE_OK;
-}
 
-/*
-** Marks 'fd' as the unused file descriptor for 'pFile'.
-*/
-CHROMIUM_SQLITE_API
-void chromium_sqlite3_update_reusable_file_handle(sqlite3_file* file,
-                                                  int fd,
-                                                  int flags) {
-  unixFile* unixSQLite3File = (unixFile*)file;
-  if (unixSQLite3File->pUnused) {
-    unixSQLite3File->pUnused->fd = fd;
-    unixSQLite3File->pUnused->flags = flags;
+  rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
+  if( rc!=SQLITE_OK ){
+    sqlite3_free(p->pUnused);
   }
-}
-
-/*
-** Destroys pFile's field that keeps track of the unused file descriptor.
-*/
-CHROMIUM_SQLITE_API
-void chromium_sqlite3_destroy_reusable_file_handle(sqlite3_file* file) {
-  unixFile* unixSQLite3File = (unixFile*)file;
-  sqlite3_free(unixSQLite3File->pUnused);
+  return rc;
 }
 
 /*
@@ -30666,13 +30619,22 @@
     sqlite3_randomness(0,0);
   }
 
-  chromium_sqlite3_initialize_unix_sqlite3_file(pFile);
+  /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
+  memset(p, 0, sizeof(unixFile));
 
   if( eType==SQLITE_OPEN_MAIN_DB ){
-    rc = chromium_sqlite3_get_reusable_file_handle(pFile, zName, flags, &fd);
-    if( rc!=SQLITE_OK ){
-      return rc;
+    UnixUnusedFd *pUnused;
+    pUnused = findReusableFd(zName, flags);
+    if( pUnused ){
+      fd = pUnused->fd;
+    }else{
+      /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
+      pUnused = sqlite3_malloc(sizeof(*pUnused));
+      if( !pUnused ){
+        return SQLITE_NOMEM;
+      }
     }
+    p->pUnused = pUnused;
 
     /* Database filenames are double-zero terminated if they are not
     ** URIs with parameters.  Hence, they can always be passed into
@@ -30742,7 +30704,11 @@
     *pOutFlags = flags;
   }
 
-  chromium_sqlite3_update_reusable_file_handle(pFile, fd, flags);
+  if( p->pUnused ){
+    /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
+    p->pUnused->fd = fd;
+    p->pUnused->flags = flags;
+  }
 
   if( isDelete ){
 #if OS_VXWORKS
@@ -30830,11 +30796,13 @@
   }
 #endif
   
+  /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
   rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
 
 open_finished:
   if( rc!=SQLITE_OK ){
-    chromium_sqlite3_destroy_reusable_file_handle(pFile);
+    /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
+    sqlite3_free(p->pUnused);
   }
   return rc;
 }
diff --git a/third_party/sqlite/amalgamation/sqlite3.h b/third_party/sqlite/amalgamation/sqlite3.h
index dfa538e..78a3ea3c 100644
--- a/third_party/sqlite/amalgamation/sqlite3.h
+++ b/third_party/sqlite/amalgamation/sqlite3.h
@@ -7442,25 +7442,12 @@
 void chromium_sqlite3_initialize_win_sqlite3_file(sqlite3_file* file, HANDLE handle);
 #else  /* _WIN32 */
 CHROMIUM_SQLITE_API
-void chromium_sqlite3_initialize_unix_sqlite3_file(sqlite3_file* file);
-CHROMIUM_SQLITE_API
-int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* vfs,
+int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs,
                                                int fd,
-                                               int dirfd,
-                                               sqlite3_file* file,
-                                               const char* fileName,
-                                               int noLock);
-CHROMIUM_SQLITE_API
-int chromium_sqlite3_get_reusable_file_handle(sqlite3_file* file,
-                                              const char* fileName,
-                                              int flags,
-                                              int* fd);
-CHROMIUM_SQLITE_API
-void chromium_sqlite3_update_reusable_file_handle(sqlite3_file* file,
-                                                  int fd,
-                                                  int flags);
-CHROMIUM_SQLITE_API
-void chromium_sqlite3_destroy_reusable_file_handle(sqlite3_file* file);
+                                               sqlite3_file* pFile,
+                                               const char* zPath,
+                                               int noLock,
+                                               int flags);
 #endif  /* _WIN32 */
 #endif  /* CHROMIUM_SQLITE_INTERNALS */
 /* End WebDatabase patch for Chromium */
diff --git a/third_party/sqlite/patches/0005-Modify-default-VFS-to-support-WebDatabase.patch b/third_party/sqlite/patches/0005-Modify-default-VFS-to-support-WebDatabase.patch
index 81343da..658136b 100644
--- a/third_party/sqlite/patches/0005-Modify-default-VFS-to-support-WebDatabase.patch
+++ b/third_party/sqlite/patches/0005-Modify-default-VFS-to-support-WebDatabase.patch
@@ -1,7 +1,7 @@
-From 4b957c2c198a53498fe18ad9668e2817ace98b1e Mon Sep 17 00:00:00 2001
+From 0125566ec87741be89ba7c4e9c2e4cc3436a6122 Mon Sep 17 00:00:00 2001
 From: dumi <dumi@chromium.org>
 Date: Mon, 20 Jul 2009 23:40:51 +0000
-Subject: [PATCH 05/11] Modify default VFS to support WebDatabase.
+Subject: [PATCH 05/12] Modify default VFS to support WebDatabase.
 
 The renderer WebDatabase implementation needs to broker certain requests
 to the browser.  This modifies SQLite to allow monkey-patching the VFS
@@ -17,13 +17,13 @@
 https://codereview.chromium.org/377039
 [Possibly not a complete list.]
 ---
- third_party/sqlite/src/src/os_unix.c   | 100 +++++++++++++++++++++++++++------
- third_party/sqlite/src/src/os_win.c    |   8 +++
- third_party/sqlite/src/src/sqlite.h.in |  36 ++++++++++++
- 3 files changed, 128 insertions(+), 16 deletions(-)
+ third_party/sqlite/src/src/os_unix.c   | 49 ++++++++++++++++++++++++++++++++++
+ third_party/sqlite/src/src/os_win.c    |  8 ++++++
+ third_party/sqlite/src/src/sqlite.h.in | 23 ++++++++++++++++
+ 3 files changed, 80 insertions(+)
 
 diff --git a/third_party/sqlite/src/src/os_unix.c b/third_party/sqlite/src/src/os_unix.c
-index a9344ee..75b71dc 100644
+index a9344ee..ea52abb 100644
 --- a/third_party/sqlite/src/src/os_unix.c
 +++ b/third_party/sqlite/src/src/os_unix.c
 @@ -1321,6 +1321,12 @@ static int fileHasMoved(unixFile *pFile){
@@ -39,131 +39,88 @@
    return pFile->pInode!=0 &&
        (osStat(pFile->zPath, &buf)!=0 || buf.st_ino!=pFile->pInode->fileId.ino);
  #endif
-@@ -5615,6 +5621,78 @@ static int findCreateFileMode(
+@@ -5615,6 +5621,44 @@ static int findCreateFileMode(
  }
  
  /*
-+** Initializes a unixFile structure with zeros.
++** Initialize |unixFile| internals of |file| on behalf of chromiumOpen() in
++** WebDatabase SQLiteFileSystemPosix.cpp.  Function is a subset of unixOpen(),
++** each duplicated piece is marked by "Duplicated in" comment in unixOpen().
 +*/
 +CHROMIUM_SQLITE_API
-+void chromium_sqlite3_initialize_unix_sqlite3_file(sqlite3_file* file) {
-+  memset(file, 0, sizeof(unixFile));
-+}
-+
-+CHROMIUM_SQLITE_API
-+int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* vfs,
++int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs,
 +                                               int fd,
-+                                               int dirfd,
-+                                               sqlite3_file* file,
-+                                               const char* fileName,
-+                                               int noLock) {
-+  int ctrlFlags = (noLock ? UNIXFILE_NOLOCK : 0);
-+  return fillInUnixFile(vfs, fd, file, fileName, ctrlFlags);
-+}
++                                               sqlite3_file* pFile,
++                                               const char* zPath,
++                                               int noLock,
++                                               int flags) {
++  unixFile *p = (unixFile *)pFile;
++  const int eType = flags&0xFFFFFF00;  /* Type of file to open */
++  const int ctrlFlags = (noLock ? UNIXFILE_NOLOCK : 0);
++  int rc;
 +
-+/*
-+** Search for an unused file descriptor that was opened on the database file.
-+** If a suitable file descriptor if found, then it is stored in *fd; otherwise,
-+** *fd is not modified.
-+**
-+** If a reusable file descriptor is not found, and a new UnixUnusedFd cannot
-+** be allocated, SQLITE_NOMEM is returned. Otherwise, SQLITE_OK is returned.
-+*/
-+CHROMIUM_SQLITE_API
-+int chromium_sqlite3_get_reusable_file_handle(sqlite3_file* file,
-+                                              const char* fileName,
-+                                              int flags,
-+                                              int* fd) {
-+  unixFile* unixSQLite3File = (unixFile*)file;
-+  int fileType = flags & 0xFFFFFF00;
-+  if (fileType == SQLITE_OPEN_MAIN_DB) {
-+    UnixUnusedFd *unusedFd = findReusableFd(fileName, flags);
-+    if (unusedFd) {
-+      *fd = unusedFd->fd;
-+    } else {
-+      unusedFd = sqlite3_malloc(sizeof(*unusedFd));
-+      if (!unusedFd) {
-+        return SQLITE_NOMEM;
-+      }
++  memset(p, 0, sizeof(unixFile));
++
++  /* osStat() will not work in the sandbox, so findReusableFd() will always
++  ** fail, so directly include the failure-case setup then initialize pUnused.
++  */
++  if( eType==SQLITE_OPEN_MAIN_DB ){
++    p->pUnused = sqlite3_malloc(sizeof(*p->pUnused));
++    if (!p->pUnused) {
++      return SQLITE_NOMEM;
 +    }
-+    unixSQLite3File->pUnused = unusedFd;
++    p->pUnused->fd = fd;
++    p->pUnused->flags = flags;
 +  }
-+  return SQLITE_OK;
-+}
 +
-+/*
-+** Marks 'fd' as the unused file descriptor for 'pFile'.
-+*/
-+CHROMIUM_SQLITE_API
-+void chromium_sqlite3_update_reusable_file_handle(sqlite3_file* file,
-+                                                  int fd,
-+                                                  int flags) {
-+  unixFile* unixSQLite3File = (unixFile*)file;
-+  if (unixSQLite3File->pUnused) {
-+    unixSQLite3File->pUnused->fd = fd;
-+    unixSQLite3File->pUnused->flags = flags;
++  rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
++  if( rc!=SQLITE_OK ){
++    sqlite3_free(p->pUnused);
 +  }
-+}
-+
-+/*
-+** Destroys pFile's field that keeps track of the unused file descriptor.
-+*/
-+CHROMIUM_SQLITE_API
-+void chromium_sqlite3_destroy_reusable_file_handle(sqlite3_file* file) {
-+  unixFile* unixSQLite3File = (unixFile*)file;
-+  sqlite3_free(unixSQLite3File->pUnused);
++  return rc;
 +}
 +
 +/*
  ** Open the file zPath.
  ** 
  ** Previously, the SQLite OS layer used three functions in place of this
-@@ -5715,20 +5793,13 @@ static int unixOpen(
+@@ -5715,6 +5759,7 @@ static int unixOpen(
      sqlite3_randomness(0,0);
    }
  
--  memset(p, 0, sizeof(unixFile));
-+  chromium_sqlite3_initialize_unix_sqlite3_file(pFile);
++  /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
+   memset(p, 0, sizeof(unixFile));
  
    if( eType==SQLITE_OPEN_MAIN_DB ){
--    UnixUnusedFd *pUnused;
--    pUnused = findReusableFd(zName, flags);
--    if( pUnused ){
--      fd = pUnused->fd;
--    }else{
--      pUnused = sqlite3_malloc(sizeof(*pUnused));
--      if( !pUnused ){
--        return SQLITE_NOMEM;
--      }
-+    rc = chromium_sqlite3_get_reusable_file_handle(pFile, zName, flags, &fd);
-+    if( rc!=SQLITE_OK ){
-+      return rc;
-     }
--    p->pUnused = pUnused;
- 
-     /* Database filenames are double-zero terminated if they are not
-     ** URIs with parameters.  Hence, they can always be passed into
-@@ -5798,10 +5869,7 @@ static int unixOpen(
-     *pOutFlags = flags;
+@@ -5723,6 +5768,7 @@ static int unixOpen(
+     if( pUnused ){
+       fd = pUnused->fd;
+     }else{
++      /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
+       pUnused = sqlite3_malloc(sizeof(*pUnused));
+       if( !pUnused ){
+         return SQLITE_NOMEM;
+@@ -5799,6 +5845,7 @@ static int unixOpen(
    }
  
--  if( p->pUnused ){
--    p->pUnused->fd = fd;
--    p->pUnused->flags = flags;
--  }
-+  chromium_sqlite3_update_reusable_file_handle(pFile, fd, flags);
- 
-   if( isDelete ){
- #if OS_VXWORKS
-@@ -5893,7 +5961,7 @@ static int unixOpen(
+   if( p->pUnused ){
++    /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
+     p->pUnused->fd = fd;
+     p->pUnused->flags = flags;
+   }
+@@ -5889,10 +5936,12 @@ static int unixOpen(
+   }
+ #endif
+   
++  /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
+   rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
  
  open_finished:
    if( rc!=SQLITE_OK ){
--    sqlite3_free(p->pUnused);
-+    chromium_sqlite3_destroy_reusable_file_handle(pFile);
++    /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
+     sqlite3_free(p->pUnused);
    }
    return rc;
- }
 diff --git a/third_party/sqlite/src/src/os_win.c b/third_party/sqlite/src/src/os_win.c
 index 8ca2107..9320bfc 100644
 --- a/third_party/sqlite/src/src/os_win.c
@@ -182,10 +139,10 @@
 +
  #endif /* SQLITE_OS_WIN */
 diff --git a/third_party/sqlite/src/src/sqlite.h.in b/third_party/sqlite/src/src/sqlite.h.in
-index f1d4e40..36aa999 100644
+index f1d4e40..14c12f2 100644
 --- a/third_party/sqlite/src/src/sqlite.h.in
 +++ b/third_party/sqlite/src/src/sqlite.h.in
-@@ -7408,6 +7408,42 @@ int sqlite3_vtab_on_conflict(sqlite3 *);
+@@ -7408,6 +7408,29 @@ int sqlite3_vtab_on_conflict(sqlite3 *);
  
  
  
@@ -202,25 +159,12 @@
 +void chromium_sqlite3_initialize_win_sqlite3_file(sqlite3_file* file, HANDLE handle);
 +#else  /* _WIN32 */
 +CHROMIUM_SQLITE_API
-+void chromium_sqlite3_initialize_unix_sqlite3_file(sqlite3_file* file);
-+CHROMIUM_SQLITE_API
-+int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* vfs,
++int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs,
 +                                               int fd,
-+                                               int dirfd,
-+                                               sqlite3_file* file,
-+                                               const char* fileName,
-+                                               int noLock);
-+CHROMIUM_SQLITE_API
-+int chromium_sqlite3_get_reusable_file_handle(sqlite3_file* file,
-+                                              const char* fileName,
-+                                              int flags,
-+                                              int* fd);
-+CHROMIUM_SQLITE_API
-+void chromium_sqlite3_update_reusable_file_handle(sqlite3_file* file,
-+                                                  int fd,
-+                                                  int flags);
-+CHROMIUM_SQLITE_API
-+void chromium_sqlite3_destroy_reusable_file_handle(sqlite3_file* file);
++                                               sqlite3_file* pFile,
++                                               const char* zPath,
++                                               int noLock,
++                                               int flags);
 +#endif  /* _WIN32 */
 +#endif  /* CHROMIUM_SQLITE_INTERNALS */
 +/* End WebDatabase patch for Chromium */
@@ -229,5 +173,5 @@
  ** Undo the hack that converts floating point types to integer for
  ** builds on processors without floating point support.
 -- 
-2.4.5
+2.6.3
 
diff --git a/third_party/sqlite/src/src/os_unix.c b/third_party/sqlite/src/src/os_unix.c
index eaa97cf..8472b78f 100644
--- a/third_party/sqlite/src/src/os_unix.c
+++ b/third_party/sqlite/src/src/os_unix.c
@@ -5625,75 +5625,41 @@
 }
 
 /*
-** Initializes a unixFile structure with zeros.
+** Initialize |unixFile| internals of |file| on behalf of chromiumOpen() in
+** WebDatabase SQLiteFileSystemPosix.cpp.  Function is a subset of unixOpen(),
+** each duplicated piece is marked by "Duplicated in" comment in unixOpen().
 */
 CHROMIUM_SQLITE_API
-void chromium_sqlite3_initialize_unix_sqlite3_file(sqlite3_file* file) {
-  memset(file, 0, sizeof(unixFile));
-}
-
-CHROMIUM_SQLITE_API
-int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* vfs,
+int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs,
                                                int fd,
-                                               int dirfd,
-                                               sqlite3_file* file,
-                                               const char* fileName,
-                                               int noLock) {
-  int ctrlFlags = (noLock ? UNIXFILE_NOLOCK : 0);
-  return fillInUnixFile(vfs, fd, file, fileName, ctrlFlags);
-}
+                                               sqlite3_file* pFile,
+                                               const char* zPath,
+                                               int noLock,
+                                               int flags) {
+  unixFile *p = (unixFile *)pFile;
+  const int eType = flags&0xFFFFFF00;  /* Type of file to open */
+  const int ctrlFlags = (noLock ? UNIXFILE_NOLOCK : 0);
+  int rc;
 
-/*
-** Search for an unused file descriptor that was opened on the database file.
-** If a suitable file descriptor if found, then it is stored in *fd; otherwise,
-** *fd is not modified.
-**
-** If a reusable file descriptor is not found, and a new UnixUnusedFd cannot
-** be allocated, SQLITE_NOMEM is returned. Otherwise, SQLITE_OK is returned.
-*/
-CHROMIUM_SQLITE_API
-int chromium_sqlite3_get_reusable_file_handle(sqlite3_file* file,
-                                              const char* fileName,
-                                              int flags,
-                                              int* fd) {
-  unixFile* unixSQLite3File = (unixFile*)file;
-  int fileType = flags & 0xFFFFFF00;
-  if (fileType == SQLITE_OPEN_MAIN_DB) {
-    UnixUnusedFd *unusedFd = findReusableFd(fileName, flags);
-    if (unusedFd) {
-      *fd = unusedFd->fd;
-    } else {
-      unusedFd = sqlite3_malloc(sizeof(*unusedFd));
-      if (!unusedFd) {
-        return SQLITE_NOMEM;
-      }
+  memset(p, 0, sizeof(unixFile));
+
+  /* osStat() will not work in the sandbox, so findReusableFd() will always
+  ** fail, so directly include the failure-case setup then initialize pUnused.
+  */
+  if( eType==SQLITE_OPEN_MAIN_DB ){
+    p->pUnused = sqlite3_malloc(sizeof(*p->pUnused));
+    if (!p->pUnused) {
+      return SQLITE_NOMEM;
     }
-    unixSQLite3File->pUnused = unusedFd;
+    p->pUnused->fd = fd;
+    p->pUnused->flags = flags;
   }
-  return SQLITE_OK;
-}
 
-/*
-** Marks 'fd' as the unused file descriptor for 'pFile'.
-*/
-CHROMIUM_SQLITE_API
-void chromium_sqlite3_update_reusable_file_handle(sqlite3_file* file,
-                                                  int fd,
-                                                  int flags) {
-  unixFile* unixSQLite3File = (unixFile*)file;
-  if (unixSQLite3File->pUnused) {
-    unixSQLite3File->pUnused->fd = fd;
-    unixSQLite3File->pUnused->flags = flags;
+  rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
+  if( rc!=SQLITE_OK ){
+    sqlite3_free(p->pUnused);
   }
-}
-
-/*
-** Destroys pFile's field that keeps track of the unused file descriptor.
-*/
-CHROMIUM_SQLITE_API
-void chromium_sqlite3_destroy_reusable_file_handle(sqlite3_file* file) {
-  unixFile* unixSQLite3File = (unixFile*)file;
-  sqlite3_free(unixSQLite3File->pUnused);
+  return rc;
 }
 
 /*
@@ -5797,13 +5763,22 @@
     sqlite3_randomness(0,0);
   }
 
-  chromium_sqlite3_initialize_unix_sqlite3_file(pFile);
+  /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
+  memset(p, 0, sizeof(unixFile));
 
   if( eType==SQLITE_OPEN_MAIN_DB ){
-    rc = chromium_sqlite3_get_reusable_file_handle(pFile, zName, flags, &fd);
-    if( rc!=SQLITE_OK ){
-      return rc;
+    UnixUnusedFd *pUnused;
+    pUnused = findReusableFd(zName, flags);
+    if( pUnused ){
+      fd = pUnused->fd;
+    }else{
+      /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
+      pUnused = sqlite3_malloc(sizeof(*pUnused));
+      if( !pUnused ){
+        return SQLITE_NOMEM;
+      }
     }
+    p->pUnused = pUnused;
 
     /* Database filenames are double-zero terminated if they are not
     ** URIs with parameters.  Hence, they can always be passed into
@@ -5873,7 +5848,11 @@
     *pOutFlags = flags;
   }
 
-  chromium_sqlite3_update_reusable_file_handle(pFile, fd, flags);
+  if( p->pUnused ){
+    /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
+    p->pUnused->fd = fd;
+    p->pUnused->flags = flags;
+  }
 
   if( isDelete ){
 #if OS_VXWORKS
@@ -5961,11 +5940,13 @@
   }
 #endif
   
+  /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
   rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
 
 open_finished:
   if( rc!=SQLITE_OK ){
-    chromium_sqlite3_destroy_reusable_file_handle(pFile);
+    /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
+    sqlite3_free(p->pUnused);
   }
   return rc;
 }
diff --git a/third_party/sqlite/src/src/sqlite.h.in b/third_party/sqlite/src/src/sqlite.h.in
index 333adfe..f736ca5a 100644
--- a/third_party/sqlite/src/src/sqlite.h.in
+++ b/third_party/sqlite/src/src/sqlite.h.in
@@ -7437,25 +7437,12 @@
 void chromium_sqlite3_initialize_win_sqlite3_file(sqlite3_file* file, HANDLE handle);
 #else  /* _WIN32 */
 CHROMIUM_SQLITE_API
-void chromium_sqlite3_initialize_unix_sqlite3_file(sqlite3_file* file);
-CHROMIUM_SQLITE_API
-int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* vfs,
+int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs,
                                                int fd,
-                                               int dirfd,
-                                               sqlite3_file* file,
-                                               const char* fileName,
-                                               int noLock);
-CHROMIUM_SQLITE_API
-int chromium_sqlite3_get_reusable_file_handle(sqlite3_file* file,
-                                              const char* fileName,
-                                              int flags,
-                                              int* fd);
-CHROMIUM_SQLITE_API
-void chromium_sqlite3_update_reusable_file_handle(sqlite3_file* file,
-                                                  int fd,
-                                                  int flags);
-CHROMIUM_SQLITE_API
-void chromium_sqlite3_destroy_reusable_file_handle(sqlite3_file* file);
+                                               sqlite3_file* pFile,
+                                               const char* zPath,
+                                               int noLock,
+                                               int flags);
 #endif  /* _WIN32 */
 #endif  /* CHROMIUM_SQLITE_INTERNALS */
 /* End WebDatabase patch for Chromium */
diff --git a/tools/OWNERS b/tools/OWNERS
index 2cc99761..868099f 100644
--- a/tools/OWNERS
+++ b/tools/OWNERS
@@ -9,7 +9,7 @@
 thakis@chromium.org
 
 
-per-file bisect*.py=rsesek@chromium.org
+per-file bisect*.py=anantha@chromium.org
 per-file bisect*.py=rmcilroy@chromium.org
 per-file run-bisect*.py=rmcilroy@chromium.org
 per-file prepare-bisect*.py=simonhatch@chromium.org
diff --git a/tools/android/BUILD.gn b/tools/android/BUILD.gn
index 6f2d622..102072f8 100644
--- a/tools/android/BUILD.gn
+++ b/tools/android/BUILD.gn
@@ -33,6 +33,20 @@
   ]
 }
 
+# GYP: //tools/android/android_tools.gyp:memconsumer
+group("memconsumer") {
+  deps = [
+    "//tools/android/memconsumer:memconsumer_apk",
+  ]
+}
+
+# GYP: //tools/android/android_tools.gyp:memtrack_helper
+group("memtrack_helper") {
+  deps = [
+    "//tools/android/memtrack_helper",
+  ]
+}
+
 # GYP: //tools/android/android_tools.gyp:ps_ext
 group("ps_ext") {
   deps = [
@@ -40,6 +54,14 @@
   ]
 }
 
+# GYP: //tools/android/android_tools.gyp:spnego_authenticator
+group("spnego_authenticator") {
+  testonly = true
+  deps = [
+    "//tools/android/kerberos/SpnegoAuthenticator:spnego_authenticator_apk",
+  ]
+}
+
 # GYP: //tools/android/android_tools.gyp:customtabs_benchmark
 group("customtabs_benchmark") {
   deps = [
diff --git a/tools/android/android_tools.gyp b/tools/android/android_tools.gyp
index 92b2b71..152636a5 100644
--- a/tools/android/android_tools.gyp
+++ b/tools/android/android_tools.gyp
@@ -38,6 +38,7 @@
       ],
     },
     {
+      # GN: //tools/android:memconsumer
       'target_name': 'memconsumer',
       'type': 'none',
       'dependencies': [
@@ -61,6 +62,7 @@
       ],
     },
     {
+      # GN: //tools/android:spnego_authenticator
       'target_name': 'spnego_authenticator',
       'type': 'none',
       'dependencies': [
diff --git a/tools/android/memconsumer/BUILD.gn b/tools/android/memconsumer/BUILD.gn
new file mode 100644
index 0000000..af7e045
--- /dev/null
+++ b/tools/android/memconsumer/BUILD.gn
@@ -0,0 +1,35 @@
+# 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/android/rules.gni")
+
+android_resources("memconsumer_apk_resources") {
+  resource_dirs = [ "java/res" ]
+  android_manifest = "java/AndroidManifest.xml"
+}
+
+android_apk("memconsumer_apk") {
+  apk_name = "MemConsumer"
+  android_manifest = "java/AndroidManifest.xml"
+  DEPRECATED_java_in_dir = "java/src"
+  native_libs = [ "libmemconsumer.so" ]
+
+  deps = [
+    ":libmemconsumer",
+    ":memconsumer_apk_resources",
+    "//base:base_java",
+  ]
+}
+
+shared_library("libmemconsumer") {
+  output_name = "memconsumer"
+  sources = [
+    "memconsumer_hook.cc",
+  ]
+  libs = [ "log" ]
+  configs -= [ "//build/config/android:hide_native_jni_exports" ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
+}
diff --git a/tools/checklicenses/checklicenses.py b/tools/checklicenses/checklicenses.py
index 143dedc..8efc2cbd 100755
--- a/tools/checklicenses/checklicenses.py
+++ b/tools/checklicenses/checklicenses.py
@@ -609,10 +609,6 @@
     'tools/telemetry/third_party/altgraph': [
         'UNKNOWN',
     ],
-    # Not shipped, downloaded on trybots sometimes.
-    'tools/telemetry/third_party/gsutil': [
-        'UNKNOWN',
-    ],
     # Not shipped, MIT license but the header files contain no licensing info.
     'tools/telemetry/third_party/modulegraph': [
         'UNKNOWN',
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp b/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp
index 5c1605b..c90510e 100644
--- a/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp
+++ b/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp
@@ -149,10 +149,6 @@
     "[blink-gc] Left-most base class %0 of derived class %1"
     " must define a virtual trace method.";
 
-const char kClassMustDeclareGCMixinTraceMethod[] =
-    "[blink-gc] Class %0 which inherits from GarbageCollectedMixin must"
-    " locally declare and override trace(Visitor*)";
-
 // Use a local RAV implementation to simply collect all FunctionDecls marked for
 // late template parsing. This happens with the flag -fdelayed-template-parsing,
 // which is on by default in MSVC-compatible mode.
@@ -251,9 +247,6 @@
       getErrorLevel(), kLeftMostBaseMustBePolymorphic);
   diag_base_class_must_declare_virtual_trace_ = diagnostic_.getCustomDiagID(
       getErrorLevel(), kBaseClassMustDeclareVirtualTrace);
-  diag_class_must_declare_gc_mixin_trace_method_ =
-      diagnostic_.getCustomDiagID(getErrorLevel(),
-                                  kClassMustDeclareGCMixinTraceMethod);
 
   // Register note messages.
   diag_base_requires_tracing_note_ = diagnostic_.getCustomDiagID(
@@ -444,13 +437,6 @@
       if (CXXMethodDecl* newop = info->DeclaresNewOperator())
         if (!Config::IsIgnoreAnnotated(newop))
           ReportClassOverridesNew(info, newop);
-      if (info->IsGCMixinInstance()) {
-        // Require that declared GCMixin implementations
-        // also provide a trace() override.
-        if (info->DeclaresGCMixinMethods()
-            && !info->DeclaresLocalTraceMethod())
-          ReportClassMustDeclareGCMixinTraceMethod(info);
-      }
     }
 
     {
@@ -1117,13 +1103,6 @@
       << info->record();
 }
 
-void BlinkGCPluginConsumer::ReportClassMustDeclareGCMixinTraceMethod(
-    RecordInfo* info) {
-  ReportDiagnostic(info->record()->getInnerLocStart(),
-                   diag_class_must_declare_gc_mixin_trace_method_)
-      << info->record();
-}
-
 void BlinkGCPluginConsumer::ReportOverriddenNonVirtualTrace(
     RecordInfo* info,
     CXXMethodDecl* trace,
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.h b/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.h
index b2b96b2..b1e35ce 100644
--- a/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.h
+++ b/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.h
@@ -163,7 +163,6 @@
   unsigned diag_class_declares_pure_virtual_trace_;
   unsigned diag_left_most_base_must_be_polymorphic_;
   unsigned diag_base_class_must_declare_virtual_trace_;
-  unsigned diag_class_must_declare_gc_mixin_trace_method_;
 
   unsigned diag_base_requires_tracing_note_;
   unsigned diag_field_requires_tracing_note_;
diff --git a/tools/clang/blink_gc_plugin/RecordInfo.cpp b/tools/clang/blink_gc_plugin/RecordInfo.cpp
index cf7fb8c..3c166dd 100644
--- a/tools/clang/blink_gc_plugin/RecordInfo.cpp
+++ b/tools/clang/blink_gc_plugin/RecordInfo.cpp
@@ -365,26 +365,6 @@
   return is_declaring_local_trace_;
 }
 
-bool RecordInfo::IsGCMixinInstance() {
-  assert(IsGCDerived());
-  if (record_->isAbstract())
-    return false;
-
-  assert(!IsGCMixin());
-
-  // true iff the class derives from GCMixin and
-  // one or more other GC base classes.
-  bool seen_gc_mixin = false;
-  bool seen_gc_derived = false;
-  for (const auto& gc_base : gc_base_names_) {
-    if (Config::IsGCMixinBase(gc_base))
-      seen_gc_mixin = true;
-    else if (Config::IsGCBase(gc_base))
-      seen_gc_derived = true;
-  }
-  return seen_gc_derived && seen_gc_mixin;
-}
-
 // A (non-virtual) class is considered abstract in Blink if it has
 // no public constructors and no create methods.
 bool RecordInfo::IsConsideredAbstract() {
diff --git a/tools/clang/blink_gc_plugin/RecordInfo.h b/tools/clang/blink_gc_plugin/RecordInfo.h
index a274ae13..1a25d83 100644
--- a/tools/clang/blink_gc_plugin/RecordInfo.h
+++ b/tools/clang/blink_gc_plugin/RecordInfo.h
@@ -93,7 +93,6 @@
   bool IsStackAllocated();
   bool IsNonNewable();
   bool IsOnlyPlacementNewable();
-  bool IsGCMixinInstance();
   bool IsEagerlyFinalized();
   bool IsGCRefCounted();
 
diff --git a/tools/clang/blink_gc_plugin/tests/class_multiple_trace_bases.cpp b/tools/clang/blink_gc_plugin/tests/class_multiple_trace_bases.cpp
index 4afc011..5bb87c9 100644
--- a/tools/clang/blink_gc_plugin/tests/class_multiple_trace_bases.cpp
+++ b/tools/clang/blink_gc_plugin/tests/class_multiple_trace_bases.cpp
@@ -8,8 +8,15 @@
 
 void Base::trace(Visitor* visitor) { }
 
-void Mixin::trace(Visitor* visitor) { }
+void Mixin1::trace(Visitor* visitor) { }
 
-// Missing: Derived::trace(visitor)
+void Mixin2::trace(Visitor* visitor) { }
+
+// Missing: void Derived1::trace(Visitor* visitor);
+
+void Derived2::trace(Visitor* visitor) {
+    Base::trace(visitor);
+    Mixin1::trace(visitor);
+}
 
 }
diff --git a/tools/clang/blink_gc_plugin/tests/class_multiple_trace_bases.h b/tools/clang/blink_gc_plugin/tests/class_multiple_trace_bases.h
index b362ec9..133f006 100644
--- a/tools/clang/blink_gc_plugin/tests/class_multiple_trace_bases.h
+++ b/tools/clang/blink_gc_plugin/tests/class_multiple_trace_bases.h
@@ -14,16 +14,26 @@
     virtual void trace(Visitor*);
 };
 
-class Mixin : public GarbageCollectedMixin {
+class Mixin1 : public GarbageCollectedMixin {
 public:
     void trace(Visitor*);
 };
 
-class Derived : public Base, public Mixin {
-    USING_GARBAGE_COLLECTED_MIXIN(HeapObject);
+class Mixin2 : public GarbageCollectedMixin {
+public:
+    void trace(Visitor*);
+};
+
+class Derived1 : public Base, public Mixin1 {
+    USING_GARBAGE_COLLECTED_MIXIN(Derived1);
     // Requires trace method.
 };
 
+class Derived2 : public Base, public Mixin1, public Mixin2 {
+    USING_GARBAGE_COLLECTED_MIXIN(Derived2);
+    void trace(Visitor*) override;
+};
+
 }
 
 #endif
diff --git a/tools/clang/blink_gc_plugin/tests/class_multiple_trace_bases.txt b/tools/clang/blink_gc_plugin/tests/class_multiple_trace_bases.txt
index a8f270b..33ae5f5 100644
--- a/tools/clang/blink_gc_plugin/tests/class_multiple_trace_bases.txt
+++ b/tools/clang/blink_gc_plugin/tests/class_multiple_trace_bases.txt
@@ -1,14 +1,14 @@
 In file included from class_multiple_trace_bases.cpp:5:
-./class_multiple_trace_bases.h:22:1: warning: [blink-gc] Class 'Derived' requires a trace method.
-class Derived : public Base, public Mixin {
+./class_multiple_trace_bases.h:27:1: warning: [blink-gc] Class 'Derived1' requires a trace method.
+class Derived1 : public Base, public Mixin1 {
 ^
-./class_multiple_trace_bases.h:22:17: note: [blink-gc] Untraced base class 'Base' declared here:
-class Derived : public Base, public Mixin {
-                ^
-./class_multiple_trace_bases.h:22:30: note: [blink-gc] Untraced base class 'Mixin' declared here:
-class Derived : public Base, public Mixin {
-                             ^
-./class_multiple_trace_bases.h:22:1: warning: [blink-gc] Class 'Derived' which inherits from GarbageCollectedMixin must locally declare and override trace(Visitor*)
-class Derived : public Base, public Mixin {
+./class_multiple_trace_bases.h:27:18: note: [blink-gc] Untraced base class 'Base' declared here:
+class Derived1 : public Base, public Mixin1 {
+                 ^
+./class_multiple_trace_bases.h:27:31: note: [blink-gc] Untraced base class 'Mixin1' declared here:
+class Derived1 : public Base, public Mixin1 {
+                              ^
+class_multiple_trace_bases.cpp:17:1: warning: [blink-gc] Base class 'Mixin2' of derived class 'Derived2' requires tracing.
+void Derived2::trace(Visitor* visitor) {
 ^
 2 warnings generated.
diff --git a/tools/clang/blink_gc_plugin/tests/class_requires_trace_method.txt b/tools/clang/blink_gc_plugin/tests/class_requires_trace_method.txt
index 15231c1..de6fd94 100644
--- a/tools/clang/blink_gc_plugin/tests/class_requires_trace_method.txt
+++ b/tools/clang/blink_gc_plugin/tests/class_requires_trace_method.txt
@@ -11,10 +11,4 @@
 ./class_requires_trace_method.h:22:5: note: [blink-gc] Untraced field 'm_part' declared here:
     PartObject m_part;
     ^
-./class_requires_trace_method.h:31:1: warning: [blink-gc] Class 'HeapObjectMixin' which inherits from GarbageCollectedMixin must locally declare and override trace(Visitor*)
-class HeapObjectMixin : public GarbageCollected<HeapObjectMixin>, public Mixin {
-^
-./class_requires_trace_method.h:40:1: warning: [blink-gc] Class 'HeapObjectMixin2' which inherits from GarbageCollectedMixin must locally declare and override trace(Visitor*)
-class HeapObjectMixin2
-^
-4 warnings generated.
+2 warnings generated.
diff --git a/tools/clang/plugins/ChromeClassTester.cpp b/tools/clang/plugins/ChromeClassTester.cpp
index b0bc8d5..8d0b22d 100644
--- a/tools/clang/plugins/ChromeClassTester.cpp
+++ b/tools/clang/plugins/ChromeClassTester.cpp
@@ -204,11 +204,6 @@
   banned_namespaces_.emplace("std");
   banned_namespaces_.emplace("__gnu_cxx");
 
-  if (!options_.enforce_overriding_blink) {
-    banned_namespaces_.emplace("blink");
-    banned_namespaces_.emplace("WTF");
-  }
-
   if (options_.enforce_in_thirdparty_webkit) {
     allowed_directories_.emplace("/third_party/WebKit/");
   }
diff --git a/tools/clang/plugins/FindBadConstructsAction.cpp b/tools/clang/plugins/FindBadConstructsAction.cpp
index 074b264..9fe6605 100644
--- a/tools/clang/plugins/FindBadConstructsAction.cpp
+++ b/tools/clang/plugins/FindBadConstructsAction.cpp
@@ -49,11 +49,8 @@
     if (args[i] == "check-base-classes") {
       // TODO(rsleevi): Remove this once http://crbug.com/123295 is fixed.
       options_.check_base_classes = true;
-    } else if (args[i] == "enforce-overriding-blink") {
-      options_.enforce_overriding_blink = true;
     } else if (args[i] == "enforce-in-thirdparty-webkit") {
       options_.enforce_in_thirdparty_webkit = true;
-      options_.enforce_overriding_blink = true;
     } else if (args[i] == "check-enum-last-value") {
       // TODO(tsepez): Enable this by default once http://crbug.com/356815
       // and http://crbug.com/356816 are fixed.
diff --git a/tools/clang/plugins/Options.h b/tools/clang/plugins/Options.h
index 62be64a2..1538298 100644
--- a/tools/clang/plugins/Options.h
+++ b/tools/clang/plugins/Options.h
@@ -10,14 +10,12 @@
 struct Options {
   Options()
       : check_base_classes(false),
-        enforce_overriding_blink(false),
         enforce_in_thirdparty_webkit(false),
         check_enum_last_value(false),
         with_ast_visitor(false),
         check_templates(false) {}
 
   bool check_base_classes;
-  bool enforce_overriding_blink;  // Blink base-class use
   bool enforce_in_thirdparty_webkit;  // Use in Blink code itself
   bool check_enum_last_value;
   bool with_ast_visitor;
diff --git a/tools/clang/plugins/tests/overridden_methods.flags b/tools/clang/plugins/tests/overridden_methods.flags
deleted file mode 100644
index eab5ca0..0000000
--- a/tools/clang/plugins/tests/overridden_methods.flags
+++ /dev/null
@@ -1 +0,0 @@
--Xclang -plugin-arg-find-bad-constructs -Xclang enforce-overriding-blink
diff --git a/tools/clang/scripts/package.py b/tools/clang/scripts/package.py
index a758a7b..0a18d759 100755
--- a/tools/clang/scripts/package.py
+++ b/tools/clang/scripts/package.py
@@ -66,11 +66,6 @@
       return 1
 
   parser = argparse.ArgumentParser(description='build and package clang')
-  parser.add_argument('--gcc-toolchain',
-                      help="the prefix for the GCC version used for building. "
-                           "For /opt/foo/bin/gcc, pass "
-                           "'--gcc-toolchain '/opt/foo'")
-
   args = parser.parse_args()
 
   with open('buildlog.txt', 'w') as log:
@@ -110,8 +105,6 @@
 
     build_cmd = [sys.executable, os.path.join(THIS_DIR, 'update.py'),
                  '--bootstrap', '--force-local-build', '--run-tests']
-    if args.gcc_toolchain is not None:
-      build_cmd.extend(['--gcc-toolchain', args.gcc_toolchain])
     TeeCmd(build_cmd, log)
 
   stamp = open(STAMP_FILE).read().rstrip()
@@ -146,6 +139,8 @@
                  'lib/clang/*/lib/darwin/*profile_osx*',
                  ])
   elif sys.platform.startswith('linux'):
+    # Copy the stdlibc++.so.6 we linked Clang against so it can run.
+    want.append('lib/libstdc++.so.6')
     # Copy only
     # lib/clang/*/lib/linux/libclang_rt.{[atm]san,san,ubsan,profile}-*.a ,
     # but not dfsan.
@@ -160,9 +155,6 @@
                  'lib/clang/*/lib/windows/clang_rt.asan*.lib',
                  'lib/clang/*/include_sanitizer/*',
                  ])
-  if args.gcc_toolchain is not None:
-    # Copy the stdlibc++.so.6 we linked Clang against so it can run.
-    want.append('lib/libstdc++.so.6')
 
   for root, dirs, files in os.walk(LLVM_RELEASE_DIR):
     # root: third_party/llvm-build/Release+Asserts/lib/..., rel_root: lib/...
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index db7df2ac..3f70c6c5 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -8,7 +8,6 @@
 It is also used by package.py to build the prebuilt clang binaries."""
 
 import argparse
-import cStringIO
 import distutils.spawn
 import glob
 import os
@@ -20,14 +19,13 @@
 import sys
 import tarfile
 import tempfile
-import time
 import urllib2
 import zipfile
 
 # Do NOT CHANGE this if you don't know what you're doing -- see
 # https://code.google.com/p/chromium/wiki/UpdatingClang
 # Reverting problematic clang rolls is safe, though.
-CLANG_REVISION = '254049'
+CLANG_REVISION = '254793'
 
 use_head_revision = 'LLVM_FORCE_HEAD_REVISION' in os.environ
 if use_head_revision:
@@ -516,10 +514,6 @@
     cflags += ['-DLLVM_FORCE_HEAD_REVISION']
     cxxflags += ['-DLLVM_FORCE_HEAD_REVISION']
 
-  # Pin MSan to the old ABI.
-  # TODO(eugenis): Remove when MSan migrates to new ABI (crbug.com/560589).
-  cxxflags += [ '-DMSAN_LINUX_X86_64_OLD_MAPPING' ]
-
   CreateChromeToolsShim()
 
   deployment_env = None
diff --git a/tools/gn/bootstrap/bootstrap.py b/tools/gn/bootstrap/bootstrap.py
index 56567aa..8581f71 100755
--- a/tools/gn/bootstrap/bootstrap.py
+++ b/tools/gn/bootstrap/bootstrap.py
@@ -157,6 +157,7 @@
       'base/third_party/superfasthash/superfasthash.c',
   ])
   static_libraries['base']['sources'].extend([
+      'base/allocator/allocator_extension.cc',
       'base/at_exit.cc',
       'base/base_paths.cc',
       'base/base_switches.cc',
diff --git a/tools/ipc_fuzzer/fuzzer/fuzzer.cc b/tools/ipc_fuzzer/fuzzer/fuzzer.cc
index d49c7bc6..0435ead 100644
--- a/tools/ipc_fuzzer/fuzzer/fuzzer.cc
+++ b/tools/ipc_fuzzer/fuzzer/fuzzer.cc
@@ -1204,6 +1204,7 @@
     bool verified_flush = false;
     gpu::CommandBufferNamespace namespace_id =
         gpu::CommandBufferNamespace::INVALID;
+    int32_t extra_data_field = 0;
     uint64_t command_buffer_id = 0;
     uint64_t release_count = 0;
 
@@ -1211,13 +1212,15 @@
       return false;
     if (!FuzzParam(&namespace_id, fuzzer))
       return false;
+    if (!FuzzParam(&extra_data_field, fuzzer))
+      return false;
     if (!FuzzParam(&command_buffer_id, fuzzer))
       return false;
     if (!FuzzParam(&release_count, fuzzer))
       return false;
 
     p->Clear();
-    p->Set(namespace_id, command_buffer_id, release_count);
+    p->Set(namespace_id, extra_data_field, command_buffer_id, release_count);
     if (verified_flush)
       p->SetVerifyFlush();
     return true;
diff --git a/tools/json_schema_compiler/OWNERS b/tools/json_schema_compiler/OWNERS
new file mode 100644
index 0000000..e2b1f64
--- /dev/null
+++ b/tools/json_schema_compiler/OWNERS
@@ -0,0 +1,2 @@
+rdevlin.cronin@chromium.org
+tbreisacher@chromium.org
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 41bab49..ca88a5c3 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -15,12 +15,10 @@
     'android_aura_gn_debug_bot': ['android', 'gn', 'debug_bot', 'aura'],
     'android_gn_release_bot': ['android', 'gn', 'release_bot'],
     'android_gn_release_trybot': ['android', 'gn', 'release_trybot'],
-    'android_gyp_debug_bot': ['android', 'gyp', 'debug_bot'],
     'android_gyp_debug_static_bot': ['android', 'gyp', 'debug_static_bot'],
     'android_gyp_debug_static_bot_arm64': ['android', 'gyp', 'debug_static_bot', 'arm64'],
     'android_gyp_release_bot': ['android', 'gyp', 'release_bot'],
     'android_gyp_release_bot_minimal_symbols': ['android', 'gyp', 'release_bot', 'minimal_symbols'],
-    'android_gyp_release_trybot': ['android', 'gyp', 'release_trybot'],
     'cast_gyp_release_bot': ['cast', 'gyp', 'release_bot'],
     'cast_gyp_release_trybot': ['cast', 'gyp', 'release_trybot'],
     'chromeos_gn_debug_bot': ['chromeos', 'gn', 'debug_bot'],
@@ -61,11 +59,14 @@
     'gyp_official_goma_minimal_symbols_android_arm64': ['gyp', 'official', 'goma', 'minimal_symbols', 'android', 'arm64'],
     'gyp_official_goma_minimal_symbols_x64': ['gyp', 'official', 'goma', 'minimal_symbols', 'x64'],
     'gyp_official_goma_minimal_symbols_x86': ['gyp', 'official', 'goma', 'minimal_symbols', 'x86'],
+    'gyp_release_bot_android': ['gyp', 'release_bot', 'android'],
+    'android_gyp_release_bot_minimal_symbols': ['android', 'gyp', 'release_bot', 'minimal_symbols'],
     'gyp_release_trybot': ['gyp', 'release_trybot'],
     'gyp_release_trybot_x64': ['gyp', 'release_trybot', 'x64'],
     'libfuzzer_upload_bot': ['gn', 'release', 'libfuzzer', 'asan', 'proprietary_codecs'],
 
-    # This is just for completeness; any bot that uses this config should never actually run MB.
+    # This is just for completeness; any bot that uses this config
+    # should never actually run MB.
     'none': ['none'],
 
     'noswarming_gn_release_bot': ['noswarming', 'gn', 'release_bot'],
@@ -80,16 +81,49 @@
     'swarming_gpu_tests_gyp_debug_trybot': ['swarming', 'gpu_tests', 'gyp', 'debug_trybot'],
     'swarming_gpu_tests_gyp_release_trybot': ['swarming', 'gpu_tests', 'gyp', 'release_trybot'],
     'swarming_gn_debug_bot': ['swarming', 'gn', 'debug_bot'],
+    'swarming_gn_debug_bot_minimal_symbols_x64': ['swarming', 'gn', 'debug_bot_minimal_symbols', 'x64'],
+    'swarming_gn_debug_bot_x64': ['swarming', 'gn', 'debug_bot', 'x64'],
     'swarming_gn_debug_trybot': ['swarming', 'gn', 'debug_trybot'],
+    'swarming_gn_oilpan_debug_bot_minimal_symbols_x64': ['swarming', 'gn', 'oilpan', 'debug_bot', 'minimal_symbols', 'x64'],
+    'swarming_gn_oilpan_debug_bot_x64': ['swarming', 'gn', 'oilpan', 'debug_bot', 'minimal_symbols', 'x64'],
+    'swarming_gn_oilpan_release_bot_x64': ['swarming', 'gn', 'oilpan', 'release_bot', 'x64'],
+    'swarming_gn_oilpan_release_trybot_minimal_symbols_x64': ['swarming', 'gn', 'oilpan', 'release_trybot', 'minimal_symbols', 'x64'],
     'swarming_gn_release_bot': ['swarming', 'gn', 'release_bot'],
+    'swarming_gn_release_bot_x64': ['swarming', 'gn', 'release_bot', 'x64'],
     'swarming_gn_release_trybot': ['swarming', 'gn', 'release_bot'],
+    'swarming_gn_release_trybot_minimal_symbols_x64': ['swarming', 'gn', 'release_trybot', 'minimal_symbols', 'x64'],
+    'swarming_gyp_asan_lsan_release_bot_x64': ['swarming', 'gyp', 'asan', 'lsan', 'release_bot', 'x64'],
+    'swarming_gyp_debug_bot_minimal_symbols_x64': ['swarming', 'gyp', 'debug_bot_minimal_symbols', 'x64'],
+    'swarming_gyp_debug_bot_minimal_symbols_x86': ['swarming', 'gyp', 'debug_bot_minimal_symbols', 'x86'],
     'swarming_gyp_debug_bot_no_symbols_x86': ['swarming', 'gyp', 'debug_bot', 'no_symbols', 'x86'],
+    'swarming_gyp_debug_bot_x64': ['swarming', 'gyp', 'debug_bot', 'x64'],
     'swarming_gyp_debug_trybot_x86': ['swarming', 'gyp', 'debug_trybot', 'x86'],
+    'swarming_gyp_msan_release_bot_x64': ['swarming', 'gyp', 'msan', 'release_bot', 'x64'],
+    'swarming_gyp_oilpan_asan_lsan_release_bot_x64': ['swarming', 'gyp', 'oilpan', 'asan', 'lsan', 'release_bot', 'x64'],
+    'swarming_gyp_oilpan_debug_bot_minimal_symbols_x64': ['swarming', 'gyp', 'oilpan', 'debug_bot', 'minimal_symbols', 'x64'],
+    'swarming_gyp_oilpan_debug_bot_minimal_symbols_x86': ['swarming', 'gyp', 'oilpan', 'debug_bot', 'minimal_symbols', 'x86'],
+    'swarming_gyp_oilpan_debug_bot_x64': ['swarming', 'gyp', 'oilpan', 'debug_bot', 'minimal_symbols', 'x64'],
+    'swarming_gyp_oilpan_release_bot_minimal_symbols_x86': ['swarming', 'gyp', 'oilpan', 'release_bot', 'minimal_symbols', 'x86'],
+    'swarming_gyp_oilpan_release_bot_x64': ['swarming', 'gyp', 'oilpan', 'release_bot', 'x64'],
+    'swarming_gyp_oilpan_release_trybot_minimal_symbols_x64': ['swarming', 'gyp', 'oilpan', 'release_trybot', 'minimal_symbols', 'x64'],
+    'swarming_gyp_oilpan_release_trybot_minimal_symbols_x86': ['swarming', 'gyp', 'oilpan', 'release_trybot', 'minimal_symbols', 'x86'],
     'swarming_gyp_release_bot': ['swarming', 'gyp', 'release_bot'],
     'swarming_gyp_release_bot_arm': ['swarming', 'gyp', 'release_bot', 'arm', 'crosscompile'],
+    'swarming_gyp_release_bot_minimal_symbols_x64': ['swarming', 'gyp', 'release_bot_minimal_symbols', 'x64'],
+    'swarming_gyp_release_bot_minimal_symbols_x86': ['swarming', 'gyp', 'release_bot_minimal_symbols', 'x86'],
+    'swarming_gyp_release_bot_x64': ['swarming', 'gyp', 'release_bot', 'x64'],
+    'swarming_gyp_release_bot_x86': ['swarming', 'gyp', 'release_bot', 'x86'],
     'swarming_gyp_release_trybot_arm': ['swarming', 'gyp', 'release_trybot', 'arm', 'crosscompile'],
+    'swarming_gyp_release_trybot_minimal_symbols_x64': ['swarming', 'gyp', 'release_trybot', 'minimal_symbols', 'x64'],
+    'swarming_gyp_release_trybot_minimal_symbols_x86': ['swarming', 'gyp', 'release_trybot', 'minimal_symbols', 'x86'],
     'swarming_tsan_gyp_release_trybot': ['swarming', 'disable_nacl', 'tsan', 'gyp', 'release_trybot'],
 
+    # This indicates that we haven't yet set up this bot w/ MB. This is
+    # different from 'none' in that a bot set to 'none' should never do
+    # compiles; a bot set to 'tbd' should do compiles but we haven't
+    # added the entries yet.
+    # 'tbd': ['none'],
+
     # clang/win doesn't work with goma yet, so this can't use debug_bot:
     'win_clang_debug_bot': ['gn', 'clang', 'debug', 'shared', 'minimal_symbols'],
   },
@@ -243,8 +277,9 @@
     },
 
     'gpu_tests': {
-      'gn_args': '', # not needed in GN builds.
-      'gyp_defines': 'archive_gpu_tests=1',
+      # archive_gpu_tests=true is not needed in GN builds.
+      'gn_args': 'ffmpeg_branding="Chrome" proprietary_codecs=true',
+      'gyp_defines': 'archive_gpu_tests=1 ffmpeg_branding=Chrome proprietary_codecs=1',
     },
 
     'gyp': {'type': 'gyp'},
@@ -276,6 +311,11 @@
       'gyp_defines': 'fastbuild=2',
     },
 
+    'oilpan': {
+      'gn_args': 'enable_oilpan=true',
+      'gyp_defines': 'enable_oilpan=1',
+    },
+
     # This config is used by bots that aren't building Chromium and should
     # never be running MB. It is used for tracking purposes. These values
     # were picked such that if someone did try to run MB, both GN and GYP
@@ -439,10 +479,39 @@
       'Win8 GN (dbg)': 'gn_debug_bot_minimal_symbols_x86',
     },
     'chromium.webkit': {
-      'Android GN': 'android_gn_release_bot',
-      'Android GN (dbg)': 'android_gn_debug_bot',
-      'Linux GN': 'gn_release_bot',
-      'Linux GN (dbg)': 'gn_debug_bot'
+      'WebKit Win Builder': 'swarming_gyp_release_bot_minimal_symbols_x86',
+      'WebKit XP': 'none',
+      'WebKit Win7': 'none',
+      'WebKit Win10': 'none',
+      'WebKit Win x64 Builder': 'swarming_gyp_release_bot_minimal_symbols_x64',
+      'WebKit Win Oilpan': 'swarming_gyp_oilpan_release_bot_minimal_symbols_x86',
+      'WebKit Win Builder (dbg)': 'swarming_gyp_debug_bot_minimal_symbols_x86',
+      'WebKit Win7 (dbg)': 'none',
+      'WebKit Win Oilpan (dbg)': 'swarming_gyp_oilpan_debug_bot_minimal_symbols_x86',
+      'WebKit Win x64 Builder (dbg)': 'swarming_gyp_debug_bot_minimal_symbols_x64',
+      'WebKit Mac Builder': 'swarming_gyp_release_bot_x64',
+      'WebKit Mac10.6': 'none',
+      'WebKit Mac10.7': 'none',
+      'WebKit Mac10.8': 'none',
+      'WebKit Mac10.9 (retina)': 'swarming_gyp_release_bot_x64',
+      'WebKit Mac10.10': 'none',
+      'WebKit Mac Oilpan': 'swarming_gyp_oilpan_release_bot_x64',
+      'WebKit Mac Builder (dbg)': 'swarming_gyp_debug_bot_x64',
+      'WebKit Mac10.7 (dbg)': 'none',
+      'WebKit Mac Oilpan (dbg)': 'swarming_gyp_oilpan_debug_bot_x64',
+      'WebKit Linux': 'swarming_gn_release_bot_x64',
+      'WebKit Linux Trusty': 'swarming_gn_release_bot_x64',
+      'WebKit Linux 32': 'swarming_gyp_release_bot_x86',
+      'WebKit Linux Oilpan': 'swarming_gn_oilpan_release_bot_x64',
+      'WebKit Linux ASAN': 'swarming_gyp_asan_lsan_release_bot_x64',
+      'WebKit Linux Oilpan ASAN': 'swarming_gyp_oilpan_asan_lsan_release_bot_x64',
+      'WebKit Linux MSAN': 'swarming_gyp_msan_release_bot_x64',
+      'WebKit Linux Leak': 'swarming_gn_release_bot_x64',
+      'WebKit Linux Oilpan Leak': 'swarming_gn_oilpan_release_bot_x64',
+      'WebKit Linux (dbg)': 'swarming_gn_debug_bot_x64',
+      'WebKit Linux Oilpan (dbg)': 'swarming_gn_oilpan_debug_bot_x64',
+      'Android Builder': 'gyp_release_bot_android',
+      'WebKit Android (Nexus4)': 'gyp_release_bot_android',
     },
     'chromium.fyi': {
       'CFI Linux': 'gn_cfi_bot',
@@ -455,8 +524,7 @@
     'chromium.webrtc.fyi': {
       'Android GN': 'android_gn_release_bot',
       'Android GN (dbg)': 'android_gn_debug_bot',
-      'Linux GN': 'gn_release_bot',
-      'Linux GN (dbg)': 'gn_debug_bot',
+      'Linux Builder': 'gn_release_bot',
       'Mac GN': 'gn_release_bot',
       'Mac GN (dbg)': 'gn_debug_static_bot',
       'Win x64 GN': 'gn_release_bot_minimal_symbols',
@@ -480,10 +548,29 @@
       'precise64 trunk': 'gn_official',
     },
     'tryserver.blink': {
-      'android_blink_compile_dbg': 'android_gyp_debug_bot',
-      'android_blink_compile_rel': 'android_gyp_release_trybot',
-      'android_chromium_gn_compile_rel': 'android_gn_release_bot',
-      'linux_chromium_gn_rel': 'gn_release_bot',
+      'linux_blink_dbg': 'swarming_gn_debug_bot_minimal_symbols_x64',
+      'linux_blink_compile_dbg': 'swarming_gn_debug_bot_minimal_symbols_x64',
+      'linux_blink_compile_rel': 'swarming_gn_release_trybot_minimal_symbols_x64',
+      'linux_blink_rel': 'swarming_gn_release_trybot_minimal_symbols_x64',
+      'mac_blink_dbg': 'swarming_gyp_debug_bot_minimal_symbols_x64',
+      'mac_blink_compile_dbg': 'swarming_gyp_debug_bot_minimal_symbols_x64',
+      'mac_blink_compile_rel': 'swarming_gyp_release_bot_minimal_symbols_x64',
+      'mac_blink_rel': 'swarming_gyp_release_trybot_minimal_symbols_x64',
+      'win_blink_dbg': 'swarming_gyp_debug_bot_minimal_symbols_x86',
+      'win_blink_compile_dbg': 'swarming_gyp_debug_bot_minimal_symbols_x86',
+      'win_blink_compile_rel': 'swarming_gyp_release_trybot_minimal_symbols_x86',
+      'win_blink_rel': 'swarming_gyp_release_trybot_minimal_symbols_x86',
+      'linux_blink_oilpan_dbg': 'swarming_gn_oilpan_debug_bot_minimal_symbols_x64',
+      'linux_blink_oilpan_rel': 'swarming_gn_oilpan_release_trybot_minimal_symbols_x64',
+      'linux_blink_oilpan_compile_rel': 'swarming_gn_oilpan_release_trybot_minimal_symbols_x64',
+      'mac_blink_oilpan_dbg': 'swarming_gyp_oilpan_debug_bot_minimal_symbols_x64',
+      'mac_blink_oilpan_rel': 'swarming_gyp_oilpan_release_trybot_minimal_symbols_x64',
+      'mac_blink_oilpan_compile_rel': 'swarming_gyp_oilpan_release_trybot_minimal_symbols_x64',
+      'win_blink_oilpan_dbg': 'swarming_gyp_oilpan_debug_bot_minimal_symbols_x86',
+      'win_blink_oilpan_rel': 'swarming_gyp_oilpan_release_trybot_minimal_symbols_x86',
+      'win_blink_oilpan_compile_rel': 'swarming_gyp_oilpan_release_trybot_minimal_symbols_x86',
+      'linux_blink_rel_ng': 'swarming_gn_release_trybot_minimal_symbols_x64',
+      'blink_presubmit': 'none',
     },
     'tryserver.chromium.android': {
       'android_chromium_gn_rel': 'android_gn_release_trybot',
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index c64c1d16..c47beee 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -2054,6 +2054,30 @@
   </summary>
 </histogram>
 
+<histogram name="AutodetectEncoding.Attempted" enum="BooleanAttempted">
+  <owner>jinsukkim@chromium.org</owner>
+  <summary>
+    Whether the text encoding auto detection logic was attempted for a web page.
+    The logic is triggered when the parser fails to find the encoding method
+    from other signals such as http header, meta tag, BOM, etc.
+
+    If the logic successfully detects a new encoding method which is different
+    from the default one, the result is reported through
+    AutodetectEncoding.Detected with the encoding method (see below). Otherwise
+    - i.e. detection logic somehow fails to work for the page or the detected
+    one is same as the default - no result is reported.
+  </summary>
+</histogram>
+
+<histogram name="AutodetectEncoding.Detected" enum="EncodingMethod"
+    units="pages">
+  <owner>jinsukkim@chromium.org</owner>
+  <summary>
+    The number of web pages whose encoding method is found by the auto detection
+    logic. Grouped by the encoding methods defined in EncodingMethod.
+  </summary>
+</histogram>
+
 <histogram name="Autofill.AddressBook.AccessSkipped" enum="BooleanSkipped">
   <obsolete>
     Deprecated as of 8/2015.
@@ -18151,8 +18175,17 @@
 <histogram name="Media.AudioRendererIpcStreams">
   <owner>grunell@chromium.org</owner>
   <summary>
-    The maximum number of simultaneous audio render streams over IPC in a render
-    process. Logged at render process shutdown.
+    The maximum number of simultaneous audio render streams over IPC created in
+    AudioRendererHost for a render process. Logged at render process shutdown.
+  </summary>
+</histogram>
+
+<histogram name="Media.AudioRendererIpcStreamsTotal">
+  <owner>grunell@chromium.org</owner>
+  <summary>
+    The maximum number of simultaneous audio render streams over IPC created in
+    AudioRendererHost for all render processes. Logged at render process
+    shutdown.
   </summary>
 </histogram>
 
@@ -22104,6 +22137,33 @@
   </summary>
 </histogram>
 
+<histogram name="Net.AsyncRevalidation.ReadError" enum="NetErrorCodes">
+  <owner>ricea@chromium.org</owner>
+  <summary>
+    Counts of error codes received while reading the body of an async
+    revalidation before getting a response. Only async revalidations that had a
+    read error are counted.
+  </summary>
+</histogram>
+
+<histogram name="Net.AsyncRevalidation.ResponseError" enum="NetErrorCodes">
+  <owner>ricea@chromium.org</owner>
+  <summary>
+    Counts of error codes received while performing an async revalidation before
+    getting a response. Only async revalidations that had in a response error
+    are counted.
+  </summary>
+</histogram>
+
+<histogram name="Net.AsyncRevalidation.Result" enum="AsyncRevalidationResult">
+  <owner>ricea@chromium.org</owner>
+  <summary>
+    The result of an async revalidation resulting from application of the
+    Cache-Control: stale-while-revalidate directive. All async revalidations are
+    counted.
+  </summary>
+</histogram>
+
 <histogram name="Net.AuthGenerateToken_basic" units="milliseconds">
   <obsolete>
     Deprecated 01/2011 in https://crrev.com/70740
@@ -25531,6 +25591,13 @@
   </summary>
 </histogram>
 
+<histogram name="Net.QuicSession.RejectLength">
+  <owner>rch@chromium.org</owner>
+  <summary>
+    The length in bytes of a QUIC REJ message received from the server.
+  </summary>
+</histogram>
+
 <histogram name="Net.QuicSession.RstStreamErrorCodeClient"
     enum="QuicRstStreamErrorCodes">
   <owner>rch@chromium.org</owner>
@@ -55331,7 +55398,7 @@
   <int value="11" label="SOURCE_KEYBOARD"/>
   <int value="12" label="SOURCE_EXTENSIONS_PAGE"/>
   <int value="13" label="SOURCE_MANAGEMENT_API"/>
-  <int value="14" label="SOURCE_EPHEMERAL_APP_UNUSED"/>
+  <int value="14" label="SOURCE_EPHEMERAL_APP_DEPRECATED"/>
   <int value="15" label="SOURCE_BACKGROUND"/>
   <int value="16" label="SOURCE_KIOSK"/>
   <int value="17" label="SOURCE_CHROME_INTERNAL"/>
@@ -55534,6 +55601,30 @@
   <int value="4" label="FAILED_HOSTS">Failed during watching HOSTS.</int>
 </enum>
 
+<enum name="AsyncRevalidationResult" type="int">
+  <int value="0" label="LOADED">A new entry was stored in the cache.</int>
+  <int value="1" label="REVALIDATED">
+    The existing cache entry was revalidated.
+  </int>
+  <int value="2" label="NET_ERROR">
+    An error occurred before a response was received.
+  </int>
+  <int value="3" label="READ_ERROR">
+    An error occurred while reading the response body.
+  </int>
+  <int value="4" label="GOT_REDIRECT">A redirect response was received.</int>
+  <int value="5" label="AUTH_FAILED">
+    A request for authentication was received, and no cached credentials were
+    available.
+  </int>
+  <int value="6" label="RESPONSE_TIMEOUT">
+    Timed out before a response was received.
+  </int>
+  <int value="7" label="BODY_TIMEOUT">
+    Timed out while reading the response body.
+  </int>
+</enum>
+
 <enum name="AudioCodec" type="int">
   <int value="0" label="kUnknownAudioCodec"/>
   <int value="1" label="kCodecAAC"/>
@@ -58103,6 +58194,8 @@
       label="TPM failed to load a key because of a bad key property"/>
   <int value="14" label="Failed to load a PKCS #11 token"/>
   <int value="15" label="Failed to encrypt with cryptohome TPM key"/>
+  <int value="16" label="TSS communication error"/>
+  <int value="17" label="TSS invalid handle"/>
 </enum>
 
 <enum name="CTRequirementCompliance" type="int">
@@ -58583,6 +58676,7 @@
   <int value="13" label="File system directory content received"/>
   <int value="14" label="Style rule edited"/>
   <int value="15" label="Command evaluated in console panel"/>
+  <int value="16" label="DOM properties expanded"/>
 </enum>
 
 <enum name="DevToolsPanel" type="int">
@@ -59528,6 +59622,46 @@
   <int value="9" label="SCRIPT_READ_FINISHED"/>
 </enum>
 
+<enum name="EncodingMethod" type="int">
+  <int value="0" label="UNKNOWN"/>
+  <int value="1" label="Big5"/>
+  <int value="2" label="EUC-JP"/>
+  <int value="3" label="EUC-KR"/>
+  <int value="4" label="GBK"/>
+  <int value="5" label="IBM866"/>
+  <int value="6" label="ISO-2022-JP"/>
+  <int value="7" label="ISO-8859-10"/>
+  <int value="8" label="ISO-8859-13"/>
+  <int value="9" label="ISO-8859-14"/>
+  <int value="10" label="ISO-8859-15"/>
+  <int value="11" label="ISO-8859-16"/>
+  <int value="12" label="ISO-8859-2"/>
+  <int value="13" label="ISO-8859-3"/>
+  <int value="14" label="ISO-8859-4"/>
+  <int value="15" label="ISO-8859-5"/>
+  <int value="16" label="ISO-8859-6"/>
+  <int value="17" label="ISO-8859-7"/>
+  <int value="18" label="ISO-8859-8"/>
+  <int value="19" label="ISO-8859-8-I"/>
+  <int value="20" label="KOI8-R"/>
+  <int value="21" label="KOI8-U"/>
+  <int value="22" label="Shift_JIS"/>
+  <int value="23" label="UTF-16LE"/>
+  <int value="24" label="UTF-8"/>
+  <int value="25" label="gb18030"/>
+  <int value="26" label="macintosh"/>
+  <int value="27" label="windows-1250"/>
+  <int value="28" label="windows-1251"/>
+  <int value="29" label="windows-1252"/>
+  <int value="30" label="windows-1253"/>
+  <int value="31" label="windows-1254"/>
+  <int value="32" label="windows-1255"/>
+  <int value="33" label="windows-1256"/>
+  <int value="34" label="windows-1257"/>
+  <int value="35" label="windows-1258"/>
+  <int value="36" label="windows-874"/>
+</enum>
+
 <enum name="EnhancedBookmarkViewMode" type="int">
   <obsolete>
     Deprecated 9/2015.
@@ -60555,7 +60689,7 @@
   <int value="6" label="ERROR_ON_PRIVATE_KEY"/>
   <int value="7" label="WAS_INSTALLED_BY_DEFAULT"/>
   <int value="8" label="REQUIRE_PERMISSIONS_CONSENT"/>
-  <int value="9" label="IS_EPHEMERAL"/>
+  <int value="9" label="IS_EPHEMERAL_DEPRECATED"/>
   <int value="10" label="WAS_INSTALLED_BY_OEM"/>
 </enum>
 
@@ -60579,7 +60713,7 @@
   <int value="512" label="GREYLIST"/>
   <int value="1024" label="CORRUPTED"/>
   <int value="2048" label="REMOTE_INSTALL"/>
-  <int value="4096" label="INACTIVE_EPHEMERAL_APP"/>
+  <int value="4096" label="INACTIVE_EPHEMERAL_APP_DEPRECATED"/>
   <int value="8192" label="EXTERNAL_EXTENSION"/>
   <int value="16384" label="UPDATE_REQUIRED_BY_POLICY"/>
 </enum>
@@ -63810,6 +63944,15 @@
   <int value="1063" label="CSSSelectorInternalMediaControlsCastButton"/>
   <int value="1064" label="CSSSelectorInternalMediaControlsOverlayCastButton"/>
   <int value="1065" label="CSSSelectorInternalPseudoSpatialNavigationFocus"/>
+  <int value="1066" label="SameOriginTextScript"/>
+  <int value="1067" label="SameOriginApplicationScript"/>
+  <int value="1068" label="SameOriginOtherScript"/>
+  <int value="1069" label="CrossOriginTextScript"/>
+  <int value="1070" label="CrossOriginApplicationScript"/>
+  <int value="1071" label="CrossOriginOtherScript"/>
+  <int value="1072" label="SVG1DOMSVGTests"/>
+  <int value="1073" label="V8SVGViewElement_ViewTarget_AttributeGetter"/>
+  <int value="1074" label="DisableRemotePlaybackAttribute"/>
 </enum>
 
 <enum name="FetchRequestMode" type="int">
@@ -67911,6 +68054,7 @@
   <int value="-617452890" label="media-router"/>
   <int value="-610411643" label="enable-printer-app-search"/>
   <int value="-604814313" label="enable-pinch"/>
+  <int value="-604068396" label="disable-input-ime-api"/>
   <int value="-601384286" label="disable-contextual-search"/>
   <int value="-589096918" label="ash-enable-fullscreen-app-list"/>
   <int value="-579192400" label="disable-input-view"/>
@@ -67973,6 +68117,7 @@
   <int value="-48920737" label="enable-smooth-scrolling"/>
   <int value="-23090520" label="disable-search-button-in-omnibox"/>
   <int value="-22544408" label="enable-video-player-chromecast-support"/>
+  <int value="-13918890" label="disable-download-notification"/>
   <int value="-5052940" label="enable-simplified-fullscreen"/>
   <int value="-2371418" label="disable-display-list-2d-canvas"/>
   <int value="0" label="BAD_FLAG_FORMAT">
@@ -68113,6 +68258,7 @@
   <int value="1139226452" label="enable-nacl-debug"/>
   <int value="1139363314" label="disable-supervised-user-blacklist"/>
   <int value="1142515376" label="enable-nacl"/>
+  <int value="1149823105" label="enable-input-ime-api"/>
   <int value="1150622273" label="enable-apps-file-associations"/>
   <int value="1163255347" label="ash-enable-touch-view-touch-feedback"/>
   <int value="1166169237" label="disable-delay-agnostic-aec"/>
@@ -81144,6 +81290,8 @@
     </obsolete>
   </suffix>
   <suffix name="Secure" label="for secure QUIC."/>
+  <suffix name="TooMany"
+      label="for secure QUIC when there were too many rejects."/>
   <affected-histogram name="Net.QuicClientHelloRejectReasons"/>
 </histogram_suffixes>
 
diff --git a/tools/perf/benchmarks/benchmark_smoke_unittest.py b/tools/perf/benchmarks/benchmark_smoke_unittest.py
index 333ee0a..7bfc6230 100644
--- a/tools/perf/benchmarks/benchmark_smoke_unittest.py
+++ b/tools/perf/benchmarks/benchmark_smoke_unittest.py
@@ -31,6 +31,7 @@
 from benchmarks import speedometer
 from benchmarks import sunspider
 from benchmarks import text_selection
+from benchmarks import thread_times
 
 
 def SmokeTestGenerator(benchmark):
@@ -48,7 +49,7 @@
 
     class SinglePageBenchmark(benchmark):  # pylint: disable=no-init
       def CreateStorySet(self, options):
-        # pylint: disable=E1002
+        # pylint: disable=super-on-old-class
         story_set = super(SinglePageBenchmark, self).CreateStorySet(options)
         for story in story_set.stories:
           story.skip_waits = True
@@ -87,7 +88,8 @@
     speedometer,  # Takes 101 seconds.
     jetstream,  # Take 206 seconds.
     text_selection, # Always fails on cq bot.
-    memory  # Flaky on bots, crbug.com/513767
+    memory,  # Flaky on bots, crbug.com/513767
+    thread_times, # Flaky on bots, crbug.com/568120
 }
 
 # Some smoke benchmark tests that run quickly on desktop platform can be very
diff --git a/tools/perf/benchmarks/blob_storage.py b/tools/perf/benchmarks/blob_storage.py
index 950b7b6..5e645a6b 100644
--- a/tools/perf/benchmarks/blob_storage.py
+++ b/tools/perf/benchmarks/blob_storage.py
@@ -15,8 +15,7 @@
 TIMELINE_REQUIRED_CATEGORY = 'blink.console'
 
 
-@benchmark.Disabled('reference',  # http://crbug.com/496155
-                    'xp',         # http://crbug.com/545085
+@benchmark.Disabled('xp',         # http://crbug.com/545085
                     'android')    # http://crbug.com/499325
 class BlobStorage(perf_benchmark.PerfBenchmark):
   """Timeline based measurement benchmark for Blob Storage."""
diff --git a/tools/perf/benchmarks/power.py b/tools/perf/benchmarks/power.py
index 677e082..1974cada 100644
--- a/tools/perf/benchmarks/power.py
+++ b/tools/perf/benchmarks/power.py
@@ -103,7 +103,6 @@
 
 
 @benchmark.Enabled('mac')
-@benchmark.Disabled('reference') # crbug.com/547833
 class PowerTop25(perf_benchmark.PerfBenchmark):
   """Top 25 quiescent power test."""
   test = power.QuiescentPower
@@ -126,7 +125,6 @@
     return stories
 
 @benchmark.Enabled('mac')
-@benchmark.Disabled('reference') # crbug.com/549302
 class PowerGpuRasterizationTop25(perf_benchmark.PerfBenchmark):
   """Top 25 quiescent power test with GPU rasterization enabled."""
   tag = 'gpu_rasterization'
diff --git a/tools/perf/benchmarks/session_restore.py b/tools/perf/benchmarks/session_restore.py
index 96beb551..cfd93a81 100644
--- a/tools/perf/benchmarks/session_restore.py
+++ b/tools/perf/benchmarks/session_restore.py
@@ -47,8 +47,7 @@
     return session_restore.SessionRestore(cold=is_cold)
 
 @benchmark.Disabled('android',
-                    'mac',  # crbug.com/563594
-                    'reference')  # crbug.com/539011
+                    'mac')  # crbug.com/563594
 class SessionRestoreColdTypical25(_SessionRestoreTypical25):
   """Test by clearing system cache and profile before repeats."""
   tag = 'cold'
@@ -61,7 +60,7 @@
 
 @benchmark.Disabled('android',
                     'mac',  # crbug.com/563594
-                    'linux', 'xp', 'reference')  # crbug.com/539056
+                    'linux', 'xp')  # crbug.com/539056
 class SessionRestoreWarmTypical25(_SessionRestoreTypical25):
   """Test without clearing system cache or profile before repeats.
 
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py
index 769b679..93e7a10e 100644
--- a/tools/perf/benchmarks/smoothness.py
+++ b/tools/perf/benchmarks/smoothness.py
@@ -103,7 +103,8 @@
     return 'smoothness.maps'
 
 
-@benchmark.Disabled('android')
+@benchmark.Disabled('android',
+                    'mac')     # crbug.com/567802
 class SmoothnessKeyDesktopMoveCases(_Smoothness):
   page_set = page_sets.KeyDesktopMoveCasesPageSet
 
@@ -468,7 +469,6 @@
     return 'smoothness.tough_texture_upload_cases'
 
 
-@benchmark.Disabled('reference')  # http://crbug.com/496684
 class SmoothnessToughAdCases(_Smoothness):
   """Measures rendering statistics while displaying advertisements."""
   page_set = page_sets.ToughAdCasesPageSet
@@ -481,9 +481,8 @@
   def ShouldDisable(cls, possible_browser):
     return cls.IsSvelte(possible_browser)  # http://crbug.com/555089
 
-# http://crbug.com/496684 (reference)
 # http://crbug.com/522619 (mac/win)
-@benchmark.Disabled('reference', 'win', 'mac')
+@benchmark.Disabled('win', 'mac')
 class SmoothnessScrollingToughAdCases(_Smoothness):
   """Measures rendering statistics while scrolling advertisements."""
   page_set = page_sets.ScrollingToughAdCasesPageSet
@@ -493,9 +492,8 @@
     return 'smoothness.scrolling_tough_ad_cases'
 
 
-# http://crbug.com/496684 (reference)
 # http://crbug.com/522619 (mac/win)
-@benchmark.Disabled('reference', 'win', 'mac')
+@benchmark.Disabled('win', 'mac')
 class SmoothnessBidirectionallyScrollingToughAdCases(_Smoothness):
   """Measures rendering statistics while scrolling advertisements."""
   page_set = page_sets.BidirectionallyScrollingToughAdCasesPageSet
@@ -509,7 +507,6 @@
     return 'smoothness.bidirectionally_scrolling_tough_ad_cases'
 
 
-@benchmark.Disabled('reference')  # http://crbug.com/496684
 class SmoothnessToughWebGLAdCases(_Smoothness):
   """Measures rendering statistics while scrolling advertisements."""
   page_set = page_sets.ToughWebglAdCasesPageSet
diff --git a/tools/perf/benchmarks/start_with_url.py b/tools/perf/benchmarks/start_with_url.py
deleted file mode 100644
index 99ed46f..0000000
--- a/tools/perf/benchmarks/start_with_url.py
+++ /dev/null
@@ -1,46 +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.
-
-from core import perf_benchmark
-
-from measurements import startup
-import page_sets
-from telemetry import benchmark
-
-
-class _StartWithUrl(perf_benchmark.PerfBenchmark):
-  page_set = page_sets.StartupPagesPageSet
-  test = startup.StartWithUrl
-
-  @classmethod
-  def Name(cls):
-    return 'start_with_url.startup_pages'
-
-  def CreatePageTest(self, options):
-    is_cold = (self.tag == 'cold')
-    return self.test(cold=is_cold)
-
-
-@benchmark.Enabled('has tabs')
-@benchmark.Disabled('chromeos', 'linux', 'mac', 'win')
-class StartWithUrlCold(_StartWithUrl):
-  """Measure time to start Chrome cold with startup URLs"""
-  tag = 'cold'
-  options = {'pageset_repeat': 5}
-
-  @classmethod
-  def Name(cls):
-    return 'start_with_url.cold.startup_pages'
-
-
-@benchmark.Enabled('has tabs')
-@benchmark.Disabled('chromeos', 'linux', 'mac', 'win')
-class StartWithUrlWarm(_StartWithUrl):
-  """Measure time to start Chrome warm with startup URLs"""
-  tag = 'warm'
-  options = {'pageset_repeat': 10}
-  @classmethod
-  def Name(cls):
-    return 'start_with_url.warm.startup_pages'
-
diff --git a/tools/perf/benchmarks/start_with_url2.py b/tools/perf/benchmarks/start_with_url2.py
index c92c3ce..01606b0 100644
--- a/tools/perf/benchmarks/start_with_url2.py
+++ b/tools/perf/benchmarks/start_with_url2.py
@@ -8,9 +8,6 @@
 from telemetry import benchmark
 
 
-# TODO(gabadie): Replaces start_with_url.* by start_with_url2.* after confirming
-# that both benchmarks produce the same results.
-
 # Disable accessing protected member for startup2._StartupPerfBenchmark. It
 # needs to be protected to not be listed in the list of benchmarks to run, even
 # though its purpose is only to factorise common code between startup
@@ -32,7 +29,7 @@
 
   @classmethod
   def Name(cls):
-    return 'start_with_url2.cold.startup_pages'
+    return 'start_with_url.cold.startup_pages'
 
 
 @benchmark.Enabled('has tabs')
@@ -46,7 +43,7 @@
 
   @classmethod
   def Name(cls):
-    return 'start_with_url2.warm.startup_pages'
+    return 'start_with_url.warm.startup_pages'
 
   @classmethod
   def ValueCanBeAddedPredicate(cls, value, is_first_result):
diff --git a/tools/perf/benchmarks/thread_times.py b/tools/perf/benchmarks/thread_times.py
index af75c7da..20a2ef6 100644
--- a/tools/perf/benchmarks/thread_times.py
+++ b/tools/perf/benchmarks/thread_times.py
@@ -130,6 +130,7 @@
     return 'per_frame' not in value.name and 'mean_frame' not in value.name
 
 
+@benchmark.Disabled('win') # crbug.com/568175
 class ThreadTimesToughScrollingCases(_ThreadTimes):
   """Measure timeline metrics while performing smoothness action on tough
   scrolling cases."""
diff --git a/tools/perf/measurements/thread_times_unittest.py b/tools/perf/measurements/thread_times_unittest.py
index ddf4c38..ae535b1 100644
--- a/tools/perf/measurements/thread_times_unittest.py
+++ b/tools/perf/measurements/thread_times_unittest.py
@@ -41,6 +41,7 @@
         cpu_time = results.FindAllPageSpecificValuesNamed(cpu_time_name)
         self.assertEquals(len(cpu_time), 1)
 
+  @decorators.Disabled('win')       # crbug.com/568120
   @decorators.Disabled('chromeos')  # crbug.com/483212
   def testWithSilkDetails(self):
     ps = self.CreateStorySetFromFileInUnittestDataDir('scrollable_page.html')
diff --git a/tools/perf_expectations/OWNERS b/tools/perf_expectations/OWNERS
new file mode 100644
index 0000000..514cf031
--- /dev/null
+++ b/tools/perf_expectations/OWNERS
@@ -0,0 +1,3 @@
+jochen@chromium.org
+thakis@chromium.org
+thestig@chromium.org
diff --git a/tools/telemetry/catapult_base/bin/run_tests b/tools/telemetry/catapult_base/bin/run_tests
new file mode 100755
index 0000000..56fcbfa
--- /dev/null
+++ b/tools/telemetry/catapult_base/bin/run_tests
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+# 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.
+
+import os
+import sys
+
+_CATAPULT_BASE_PATH = os.path.abspath(
+    os.path.join(os.path.dirname(__file__), '..'))
+_TELEMETRY_BASE_PATH = os.path.abspath(os.path.join(_CATAPULT_BASE_PATH, '..'))
+_CATAPULT_PATH = os.path.abspath(os.path.join(
+    _CATAPULT_BASE_PATH, '..', '..', '..', 'third_party', 'catapult'))
+
+
+def _RunTestsOrDie(top_level_dir):
+  exit_code = run_with_typ.Run(top_level_dir, path=[_TELEMETRY_BASE_PATH])
+  if exit_code:
+    sys.exit(exit_code)
+
+
+def _AddToPathIfNeeded(path):
+  if path not in sys.path:
+    sys.path.insert(0, path)
+
+
+if __name__ == '__main__':
+  _AddToPathIfNeeded(_CATAPULT_PATH)
+
+  from hooks import install
+  if '--no-install-hooks' in sys.argv:
+    sys.argv.remove('--no-install-hooks')
+  else:
+    install.InstallHooks()
+
+  from catapult_build import run_with_typ
+  _RunTestsOrDie(_CATAPULT_BASE_PATH)
+  sys.exit(0)
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 1e1c1d5..867c69b 100644
--- a/tools/telemetry/catapult_base/dependency_manager/cloud_storage_info.py
+++ b/tools/telemetry/catapult_base/dependency_manager/cloud_storage_info.py
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 
 import errno
-import logging
 import os
 import stat
 
@@ -79,7 +78,6 @@
     if not os.path.exists(dependency_path):
       raise exceptions.FileNotFoundError(dependency_path)
 
-    logging.error('has archive_info %s', self._archive_info)
     if self.has_archive_info:
       dependency_path = self._archive_info.GetUnzippedPath()
     else:
diff --git a/tools/telemetry/telemetry/core/cros_interface.py b/tools/telemetry/telemetry/core/cros_interface.py
index ee69f38..73a47e4 100644
--- a/tools/telemetry/telemetry/core/cros_interface.py
+++ b/tools/telemetry/telemetry/core/cros_interface.py
@@ -78,7 +78,6 @@
   pass
 
 class CrOSInterface(object):
-  # pylint: disable=R0923
   def __init__(self, hostname=None, ssh_port=None, ssh_identity=None):
     self._hostname = hostname
     self._ssh_port = ssh_port
@@ -323,7 +322,7 @@
         '-o', 'pid,ppid,args:4096,state'], quiet=True)
     assert stderr == '', stderr
     procs = []
-    for l in stdout.split('\n'): # pylint: disable=E1103
+    for l in stdout.split('\n'):
       if l == '':
         continue
       m = re.match(r'^\s*(\d+)\s+(\d+)\s+(.+)\s+(.+)', l, re.DOTALL)
diff --git a/tools/telemetry/telemetry/core/cros_interface_unittest.py b/tools/telemetry/telemetry/core/cros_interface_unittest.py
index d1aee50..f01a4e4 100644
--- a/tools/telemetry/telemetry/core/cros_interface_unittest.py
+++ b/tools/telemetry/telemetry/core/cros_interface_unittest.py
@@ -49,7 +49,7 @@
       self.assertFalse(cri.FileExistsOnDevice('/etc/sdlfsdjflskfjsflj'))
 
   @decorators.Enabled('cros-chrome')
-  def testGetFileContents(self): # pylint: disable=R0201
+  def testGetFileContents(self): # pylint: disable=no-self-use
     with self._GetCRI() as cri:
       hosts = cri.GetFileContents('/etc/lsb-release')
       self.assertTrue('CHROMEOS' in hosts)
@@ -65,7 +65,7 @@
           lambda: cri.GetFileContents(f.name))
 
   @decorators.Enabled('cros-chrome')
-  def testGetFile(self): # pylint: disable=R0201
+  def testGetFile(self): # pylint: disable=no-self-use
     with self._GetCRI() as cri:
       f = tempfile.NamedTemporaryFile()
       cri.GetFile('/etc/lsb-release', f.name)
diff --git a/tools/telemetry/telemetry/internal/backends/chrome_inspector/inspector_console.py b/tools/telemetry/telemetry/internal/backends/chrome_inspector/inspector_console.py
index ebd8aef1..3304bb3f 100644
--- a/tools/telemetry/telemetry/internal/backends/chrome_inspector/inspector_console.py
+++ b/tools/telemetry/telemetry/internal/backends/chrome_inspector/inspector_console.py
@@ -30,11 +30,11 @@
 
   # False positive in PyLint 0.25.1: http://www.logilab.org/89092
   @property
-  def message_output_stream(self):  # pylint: disable=E0202
+  def message_output_stream(self):  # pylint: disable=method-hidden
     return self._message_output_stream
 
   @message_output_stream.setter
-  def message_output_stream(self, stream):  # pylint: disable=E0202
+  def message_output_stream(self, stream):  # pylint: disable=method-hidden
     self._message_output_stream = stream
     self._UpdateConsoleEnabledState()
 
diff --git a/tools/telemetry/telemetry/internal/backends/form_based_credentials_backend_unittest_base.py b/tools/telemetry/telemetry/internal/backends/form_based_credentials_backend_unittest_base.py
index 1592144..8752c06 100644
--- a/tools/telemetry/telemetry/internal/backends/form_based_credentials_backend_unittest_base.py
+++ b/tools/telemetry/telemetry/internal/backends/form_based_credentials_backend_unittest_base.py
@@ -18,7 +18,7 @@
 
   def _LoginUsingMock(self, backend, login_page_url, email_element_id,
                       password_element_id, form_element_id,
-                      already_logged_in_js): # pylint: disable=R0201
+                      already_logged_in_js): # pylint: disable=no-self-use
     tab = simple_mock.MockObject()
     ar = simple_mock.MockObject()
 
diff --git a/tools/telemetry/telemetry/internal/browser/browser_options.py b/tools/telemetry/telemetry/internal/browser/browser_options.py
index 6043156f..5909975 100644
--- a/tools/telemetry/telemetry/internal/browser/browser_options.py
+++ b/tools/telemetry/telemetry/internal/browser/browser_options.py
@@ -336,14 +336,14 @@
     self.browser_type = finder_options.browser_type
     self._finder_options = finder_options
 
-    if hasattr(self, 'extra_browser_args_as_string'): # pylint: disable=E1101
+    if hasattr(self, 'extra_browser_args_as_string'):
       tmp = shlex.split(
-        self.extra_browser_args_as_string) # pylint: disable=E1101
+        self.extra_browser_args_as_string)
       self.AppendExtraBrowserArgs(tmp)
       delattr(self, 'extra_browser_args_as_string')
-    if hasattr(self, 'extra_wpr_args_as_string'): # pylint: disable=E1101
+    if hasattr(self, 'extra_wpr_args_as_string'):
       tmp = shlex.split(
-        self.extra_wpr_args_as_string) # pylint: disable=E1101
+        self.extra_wpr_args_as_string)
       self.extra_wpr_args.extend(tmp)
       delattr(self, 'extra_wpr_args_as_string')
     if self.profile_type == 'default':
diff --git a/tools/telemetry/telemetry/internal/browser/browser_options_unittest.py b/tools/telemetry/telemetry/internal/browser/browser_options_unittest.py
index 84ecf98..08791a56 100644
--- a/tools/telemetry/telemetry/internal/browser/browser_options_unittest.py
+++ b/tools/telemetry/telemetry/internal/browser/browser_options_unittest.py
@@ -14,14 +14,14 @@
     parser = options.CreateParser()
     parser.add_option('-x', action='store', default=3)
     parser.parse_args(['--browser', 'any'])
-    self.assertEquals(options.x, 3) # pylint: disable=E1101
+    self.assertEquals(options.x, 3) # pylint: disable=no-member
 
   def testDefaultsPlusOverride(self):
     options = browser_options.BrowserFinderOptions()
     parser = options.CreateParser()
     parser.add_option('-x', action='store', default=3)
     parser.parse_args(['--browser', 'any', '-x', 10])
-    self.assertEquals(options.x, 10) # pylint: disable=E1101
+    self.assertEquals(options.x, 10) # pylint: disable=no-member
 
   def testDefaultsDontClobberPresetValue(self):
     options = browser_options.BrowserFinderOptions()
@@ -29,21 +29,21 @@
     parser = options.CreateParser()
     parser.add_option('-x', action='store', default=3)
     parser.parse_args(['--browser', 'any'])
-    self.assertEquals(options.x, 7) # pylint: disable=E1101
+    self.assertEquals(options.x, 7) # pylint: disable=no-member
 
   def testCount0(self):
     options = browser_options.BrowserFinderOptions()
     parser = options.CreateParser()
     parser.add_option('-x', action='count', dest='v')
     parser.parse_args(['--browser', 'any'])
-    self.assertEquals(options.v, None) # pylint: disable=E1101
+    self.assertEquals(options.v, None) # pylint: disable=no-member
 
   def testCount2(self):
     options = browser_options.BrowserFinderOptions()
     parser = options.CreateParser()
     parser.add_option('-x', action='count', dest='v')
     parser.parse_args(['--browser', 'any', '-xx'])
-    self.assertEquals(options.v, 2) # pylint: disable=E1101
+    self.assertEquals(options.v, 2) # pylint: disable=no-member
 
   def testOptparseMutabilityWhenSpecified(self):
     options = browser_options.BrowserFinderOptions()
diff --git a/tools/telemetry/telemetry/internal/platform/android_device.py b/tools/telemetry/telemetry/internal/platform/android_device.py
index 949a9da..b3448b69 100644
--- a/tools/telemetry/telemetry/internal/platform/android_device.py
+++ b/tools/telemetry/telemetry/internal/platform/android_device.py
@@ -7,6 +7,7 @@
 import subprocess
 
 from telemetry.core import util
+from telemetry.internal.platform import cros_device
 from telemetry.internal.platform import device
 from telemetry.internal.platform.profiler import monsoon
 
@@ -127,9 +128,9 @@
   return devices[0]
 
 
-def CanDiscoverDevices():
-  """Returns true if devices are discoverable via adb."""
-  if os.name != 'posix':
+def _HasValidAdb():
+  """Returns true if adb is present."""
+  if os.name != 'posix' or cros_device.IsRunningOnCrOS():
     return False
 
   try:
@@ -140,6 +141,14 @@
   if os.path.isabs(adb_path) and not os.path.exists(adb_path):
     return False
 
+  return True
+
+
+def CanDiscoverDevices():
+  """Returns true if devices are discoverable via adb."""
+  if not _HasValidAdb():
+    return False
+
   try:
     with open(os.devnull, 'w') as devnull:
       adb_process = subprocess.Popen(
@@ -155,35 +164,28 @@
   except OSError:
     pass
   try:
+    adb_path = adb_wrapper.AdbWrapper.GetAdbPath()
     os.environ['PATH'] = os.pathsep.join(
         [os.path.dirname(adb_path), os.environ['PATH']])
     device_utils.DeviceUtils.HealthyDevices(None)
     return True
   except (device_errors.CommandFailedError, device_errors.CommandTimeoutError,
-          OSError):
+          device_errors.NoAdbError, OSError):
     return False
 
 
 def FindAllAvailableDevices(options):
   """Returns a list of available devices.
   """
-  if options.android_blacklist_file:
-    blacklist = device_blacklist.Blacklist(options.android_blacklist_file)
-  else:
-    blacklist = None
-
   devices = []
-
   try:
-    if not CanDiscoverDevices():
-      devices = []
-    else:
+    if CanDiscoverDevices():
+      blacklist = None
+      if options.android_blacklist_file:
+        blacklist = device_blacklist.Blacklist(options.android_blacklist_file)
       devices = AndroidDevice.GetAllConnectedDevices(blacklist)
   finally:
-    if not devices:
-      try:
-        adb_wrapper.AdbWrapper.KillServer()
-      except device_errors.NoAdbError:
-        pass
+    if not devices and _HasValidAdb():
+      adb_wrapper.AdbWrapper.KillServer()
 
   return devices
diff --git a/tools/telemetry/telemetry/internal/platform/win_platform_backend.py b/tools/telemetry/telemetry/internal/platform/win_platform_backend.py
index 145c7c81..edc8cdd7 100644
--- a/tools/telemetry/telemetry/internal/platform/win_platform_backend.py
+++ b/tools/telemetry/telemetry/internal/platform/win_platform_backend.py
@@ -29,8 +29,8 @@
 try:
   import pywintypes  # pylint: disable=import-error
   import win32api  # pylint: disable=import-error
-  from win32com.shell import shell  # pylint: disable=F0401,E0611
-  from win32com.shell import shellcon  # pylint: disable=F0401,E0611
+  from win32com.shell import shell  # pylint: disable=no-name-in-module
+  from win32com.shell import shellcon  # pylint: disable=no-name-in-module
   import win32con  # pylint: disable=import-error
   import win32gui  # pylint: disable=import-error
   import win32process  # pylint: disable=import-error
diff --git a/tools/telemetry/telemetry/record_wpr.py b/tools/telemetry/telemetry/record_wpr.py
index c53f35a..5388965d 100644
--- a/tools/telemetry/telemetry/record_wpr.py
+++ b/tools/telemetry/telemetry/record_wpr.py
@@ -178,6 +178,10 @@
 
   def _ProcessCommandLineArgs(self):
     story_runner.ProcessCommandLineArgs(self._parser, self._options)
+
+    if self._options.use_live_sites:
+      self._parser.error("Can't --use-live-sites while recording")
+
     if self._benchmark is not None:
       self._benchmark.ProcessCommandLineArgs(self._parser, self._options)
 
diff --git a/tools/telemetry/telemetry/record_wpr_unittest.py b/tools/telemetry/telemetry/record_wpr_unittest.py
index 471584f..9760cb07 100644
--- a/tools/telemetry/telemetry/record_wpr_unittest.py
+++ b/tools/telemetry/telemetry/record_wpr_unittest.py
@@ -231,3 +231,8 @@
         'CustomizeBrowserOptions' in record_page_test.page_test.func_calls)
     self.assertTrue('WillStartBrowser' in record_page_test.page_test.func_calls)
     self.assertTrue('DidStartBrowser' in record_page_test.page_test.func_calls)
+
+  def testUseLiveSitesUnsupported(self):
+    flags = ['--use-live-sites']
+    with self.assertRaises(SystemExit):
+      record_wpr.WprRecorder(self._test_data_dir, MockBenchmark(), flags)
diff --git a/tools/telemetry/telemetry/testing/decorators_unittest.py b/tools/telemetry/telemetry/testing/decorators_unittest.py
index a88ce35a..f27d36c6 100644
--- a/tools/telemetry/telemetry/testing/decorators_unittest.py
+++ b/tools/telemetry/telemetry/testing/decorators_unittest.py
@@ -27,7 +27,7 @@
 
 
 class DecoratorsUnitTest(unittest.TestCase):
-  # pylint: disable=C0102
+  # pylint: disable=blacklisted-name
 
   def testCacheDecorator(self):
     self.assertNotEquals(CreateFooUncached(1), CreateFooUncached(2))
diff --git a/tools/telemetry/telemetry/util/color_histogram.py b/tools/telemetry/telemetry/util/color_histogram.py
index 949e9eb..76bb4b9 100644
--- a/tools/telemetry/telemetry/util/color_histogram.py
+++ b/tools/telemetry/telemetry/util/color_histogram.py
@@ -54,7 +54,7 @@
 class ColorHistogram(
     collections.namedtuple('ColorHistogram', ['r', 'g', 'b', 'default_color'])):
   # pylint: disable=no-init
-  # pylint: disable=E1002
+  # pylint: disable=super-on-old-class
 
   def __new__(cls, r, g, b, default_color=None):
     return super(ColorHistogram, cls).__new__(cls, r, g, b, default_color)
diff --git a/tools/telemetry/telemetry/web_perf/metrics/smoothness.py b/tools/telemetry/telemetry/web_perf/metrics/smoothness.py
index 652e2586..fee30ff8 100644
--- a/tools/telemetry/telemetry/web_perf/metrics/smoothness.py
+++ b/tools/telemetry/telemetry/web_perf/metrics/smoothness.py
@@ -276,7 +276,7 @@
             page, 'percentage_smooth', 'score', percentage_smooth,
             description='Percentage of frames that were hitting 60 fps.',
             none_value_reason=none_value_reason,
-            improvement_direction=improvement_direction.DOWN)
+            improvement_direction=improvement_direction.UP)
     )
 
   def _ComputeFrameTimeDiscrepancy(self, page, stats):
diff --git a/tools/telemetry/telemetry/web_perf/metrics/startup_unittest.py b/tools/telemetry/telemetry/web_perf/metrics/startup_unittest.py
index 55404cb..a2aa113 100644
--- a/tools/telemetry/telemetry/web_perf/metrics/startup_unittest.py
+++ b/tools/telemetry/telemetry/web_perf/metrics/startup_unittest.py
@@ -20,7 +20,7 @@
     self.events.append(event)
 
   # Attributes defined outside __init__
-  # pylint: disable=W0201
+  # pylint: disable=attribute-defined-outside-init
   def ComputeStartupMetrics(self):
     results = test_page_test_results.TestPageTestResults(self)
 
diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt
index d1f1d269..79c124a 100644
--- a/tools/valgrind/drmemory/suppressions.txt
+++ b/tools/valgrind/drmemory/suppressions.txt
@@ -425,8 +425,7 @@
 ...
 skia.dll!SkScalerContext::getImage
 skia.dll!SkGlyphCache::findImage
-skia.dll!D1G_RectClip
-skia.dll!SkDraw::draw*
+skia.dll!DrawOneGlyph::getImageData
 
 HANDLE LEAK
 name=http://crbug.com/346842
@@ -436,7 +435,7 @@
 *!SkScalerContext_GDI::generateImage
 *!SkScalerContext::getImage
 *!SkGlyphCache::findImage
-*!D1G*RectClip
+*!DrawOneGlyph::getImageData
 
 HANDLE LEAK
 name=http://crbug.com/346993
@@ -787,10 +786,3 @@
 content.dll!content::BrowserThreadImpl::Run
 base.dll!base::Thread::ThreadMain
 base.dll!base::`anonymous namespace'::ThreadFunc
-
-UNADDRESSABLE ACCESS
-name=bug_563817
-base.dll!base::CommandLine::HasSwitch
-base.dll!base::CommandLine::HasSwitch
-mojo_system_impl.dll!mojo::edk::Init
-mojo_system_impl.dll!mojo::embedder::Init
diff --git a/tools/valgrind/gtest_exclude/unit_tests.gtest.txt b/tools/valgrind/gtest_exclude/unit_tests.gtest.txt
index 0f6b8529..92fce22 100644
--- a/tools/valgrind/gtest_exclude/unit_tests.gtest.txt
+++ b/tools/valgrind/gtest_exclude/unit_tests.gtest.txt
@@ -15,3 +15,9 @@
 
 # Failing on CrOS, see http://crbug.com/408013
 ProxyConfigServiceImplTest.*
+
+# Failing gMock expectations on both Valgrind and Dr. Memory. Possibly timeouts?
+# https://crbug.com/567866
+ExtensionServiceTestSupervised.UpdateWithPermissionIncreaseApprovalMatchingVersion
+ExtensionServiceTestSupervised.UpdateWithPermissionIncreaseApprovalNewVersion
+ExtensionServiceTestSupervised.UpdateWithPermissionIncreaseApprovalOldVersion
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index 65efbdd..471bc44 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -3154,12 +3154,6 @@
    fun:_ZN3net16HostResolverImpl16LoopbackProbeJob7DoProbeEv
 }
 {
-   bug_514439
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN8IOThread34InitSystemRequestContextOnIOThreadEv
-}
-{
    bug_514443
    Memcheck:Leak
    fun:_Znw*
@@ -3213,18 +3207,6 @@
    fun:_ZN3net2ct30CreateLogVerifiersForKnownLogsEv
 }
 {
-   bug_521656
-   Memcheck:Uninitialized
-   fun:_ZN5blink10TraceTraitINS_11WebGLObjectEE5traceEPNS_7VisitorEPv
-   fun:_ZN5blink13CallbackStack4Item4callEPNS_7VisitorE
-   fun:_ZN5blink4Heap25popAndInvokeTraceCallbackEPNS_7VisitorE
-   fun:_ZN5blink4Heap19processMarkingStackEPNS_7VisitorE
-   fun:_ZN5blink4Heap14collectGarbageENS_7BlinkGC10StackStateENS1_6GCTypeENS0_8GCReasonE
-   fun:_ZN5blink14V8GCController10gcEpilogueEN2v86GCTypeENS1_15GCCallbackFlagsE
-   fun:_ZN2v88internal4Heap23CallGCEpilogueCallbacksENS_6GCTypeENS_15GCCallbackFlagsE
-   fun:_ZN2v88internal4Heap24PerformGarbageCollectionENS0_16GarbageCollectorENS_15GCCallbackFlagsE
-}
-{
    bug_522049
    Memcheck:Unaddressable
    ...
@@ -3242,56 +3224,6 @@
    fun:_ZN7content12_GLOBAL__N_135RenderWidgetCompositorOutputSurface20SynchronousCompositeEv
 }
 {
-   bug_522463
-   Memcheck:Leak
-   fun:_Znw*
-   ...
-   fun:_ZN19KeyedServiceFactory20GetServiceForContextEPN4base16SupportsUserDataEb
-}
-{
-   bug_522468
-   Memcheck:Leak
-   fun:_Znw*
-   ...
-   fun:_ZN14TestingProfile4InitEv
-   fun:_ZN14TestingProfileC1Ev
-   fun:_ZN12_GLOBAL__N_131PermissionManagerTestingProfileC2Ev
-   fun:_ZN21PermissionManagerTestC2Ev
-   fun:_ZN*PermissionManagerTest_*
-}
-{
-   bug_522514
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN4base8internal20PostTaskAndReplyImpl16PostTaskAndReplyERKN15tracked_objects8LocationERKNS_8CallbackIFvvEEESA_
-   fun:_ZN4base10WorkerPool16PostTaskAndReplyERKN15tracked_objects8LocationERKNS_8CallbackIFvvEEES9_b
-   fun:_ZN3net15CertVerifierJob5StartERK13scoped_refptrINS_14CertVerifyProcEERKS1_INS_15X509CertificateEERKSsSB_iRKS1_INS_6CRLSetEERKSt6vectorIS7_SaIS7_EE
-   fun:_ZN3net25MultiThreadedCertVerifier6VerifyEPNS_15X509CertificateERKSsS4_iPNS_6CRLSetEPNS_16CertVerifyResultERKN4base8CallbackIFviEEEP10scoped_ptrINS_12CertVerifier7RequestENS9_14DefaultDeleterISH_EEERKNS_11BoundNetLogE
-   fun:_ZN3net56MultiThreadedCertVerifierTest_CancelRequestThenQuit_Test8TestBodyEv
-}
-{
-   bug_522524
-   Memcheck:Leak
-   fun:calloc
-   ...
-   fun:CERT_NewTempCertificate
-   fun:_ZN3net15X509Certificate39CreateOSCertHandleFromBytesWithNicknameEPKciS2_
-   fun:_ZN3net15X509Certificate27CreateOSCertHandleFromBytesEPKci
-   fun:_ZN3net15X509Certificate30CreateCertificateListFromBytesEPKcii
-   fun:_ZN3net18ImportCertFromFileERKN4base8FilePathERKSs
-   fun:_ZN3net59CertVerifyProcTest_IsIssuedByKnownRootIgnoresTestRoots_Test8TestBodyEv
-}
-{
-   bug_522620
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN3IPC11SyncChannel23CreateSyncMessageFilterEv
-   fun:_ZN7content14GpuChannelHost7ConnectERKN3IPC13ChannelHandleEPN4base13WaitableEventE
-   fun:_ZN7content14GpuChannelHost6CreateEPNS_21GpuChannelHostFactoryERKN3gpu7GPUInfoERKN3IPC13ChannelHandleEPN4base13WaitableEventEPNS3_22GpuMemoryBufferManagerE
-   fun:_ZN7content28BrowserGpuChannelHostFactory21GpuChannelEstablishedEv
-   fun:_ZN7content28BrowserGpuChannelHostFactory16EstablishRequest12FinishOnMainEv
-}
-{
    bug_525328
    Memcheck:Leak
    fun:_Znw*
@@ -3329,28 +3261,6 @@
    fun:_ZN4base12_GLOBAL__N_110ThreadFuncEPv
 }
 {
-   bug_542563
-   Memcheck:Leak
-   fun:_Znw*
-   ...
-   fun:_ZN7content21RenderProcessHostImpl4InitEv
-   fun:_ZN7content22RenderFrameHostManager14InitRenderViewEPNS_18RenderViewHostImplEi
-   fun:_ZN7content22RenderFrameHostManager8NavigateERK4GURLRKNS_20FrameNavigationEntryERKNS_19NavigationEntryImplE
-   fun:_ZN7content13NavigatorImpl15NavigateToEntryEPNS_13FrameTreeNodeERKNS_20FrameNavigationEntryERKNS_19NavigationEntryImplENS_20NavigationController10ReloadTypeEb
-   fun:_ZN7content13NavigatorImpl22NavigateToPendingEntryEPNS_13FrameTreeNodeERKNS_20FrameNavigationEntryENS_20NavigationController10ReloadTypeEb
-   fun:_ZN7content24NavigationControllerImpl30NavigateToPendingEntryInternalENS_20NavigationController10ReloadTypeE
-}
-{
-   bug_542875
-   Memcheck:Leak
-   fun:malloc
-   fun:_ZN3WTF10fastMallocEm
-   ...
-   fun:_ZN5blink13DOMTypedArrayIN3WTF17Uint8ClampedArrayEN2v817Uint8ClampedArrayEE12createOrNullEj
-   fun:_ZN5blink9ImageData6createERKNS_7IntSizeE
-   fun:_ZNK5blink17HTMLCanvasElement11toImageDataENS_19SourceDrawingBufferE
-}
-{
    bug_545259a
    Memcheck:Leak
    fun:_Znw*
@@ -3417,6 +3327,7 @@
    Memcheck:Uninitialized
    fun:_ZN5blink10PaintLayer24removeFilterInfoIfNeededEv
    fun:_ZN5blink10PaintLayerD1Ev
+   fun:_ZN5blink10PaintLayerD0Ev
    fun:_ZN3WTF15OwnedPtrDeleterIN5blink10PaintLayerEE9deletePtrEPS2_
    fun:_ZN3WTF6OwnPtrIN5blink10PaintLayerEE5clearEv
    fun:_ZN3WTF6OwnPtrIN5blink10PaintLayerEEaSEDn
diff --git a/ui/aura/test/event_generator_delegate_aura.cc b/ui/aura/test/event_generator_delegate_aura.cc
index f248cb6..9ee54cf 100644
--- a/ui/aura/test/event_generator_delegate_aura.cc
+++ b/ui/aura/test/event_generator_delegate_aura.cc
@@ -8,6 +8,7 @@
 #include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/aura/window_tree_host.h"
+#include "ui/base/ime/input_method.h"
 
 namespace aura {
 namespace test {
@@ -61,7 +62,9 @@
 }  // namespace
 
 void InitializeAuraEventGeneratorDelegate() {
-  DefaultEventGeneratorDelegate::GetInstance();
+  if (!ui::test::EventGenerator::default_delegate) {
+    DefaultEventGeneratorDelegate::GetInstance();
+  }
 }
 
 EventGeneratorDelegateAura::EventGeneratorDelegateAura() {
@@ -126,5 +129,11 @@
   window->GetHost()->ConvertPointFromHost(point);
 }
 
+void EventGeneratorDelegateAura::DispatchKeyEventToIME(ui::EventTarget* target,
+                                                       ui::KeyEvent* event) {
+  Window* window = static_cast<Window*>(target);
+  window->GetHost()->GetInputMethod()->DispatchKeyEvent(event);
+}
+
 }  // namespace test
 }  // namespace aura
diff --git a/ui/aura/test/event_generator_delegate_aura.h b/ui/aura/test/event_generator_delegate_aura.h
index 7cc7f2f9..e235622 100644
--- a/ui/aura/test/event_generator_delegate_aura.h
+++ b/ui/aura/test/event_generator_delegate_aura.h
@@ -45,6 +45,8 @@
                             gfx::Point* point) const override;
   void ConvertPointFromHost(const ui::EventTarget* hosted_target,
                             gfx::Point* point) const override;
+  void DispatchKeyEventToIME(ui::EventTarget* target,
+                             ui::KeyEvent* event) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(EventGeneratorDelegateAura);
diff --git a/ui/base/ime/remote_input_method_win.cc b/ui/base/ime/remote_input_method_win.cc
index e9f7fc2..2fbb8ac7 100644
--- a/ui/base/ime/remote_input_method_win.cc
+++ b/ui/base/ime/remote_input_method_win.cc
@@ -60,7 +60,7 @@
   //|chars_written| includes NUL terminator.
   const int chars_written =
       GetLocaleInfo(Locale_id, locale_type, buffer, arraysize(buffer));
-  if (chars_written <= 1 || arraysize(buffer) < chars_written)
+  if (chars_written <= 1 || static_cast<int>(arraysize(buffer)) < chars_written)
     return std::string();
   std::string result;
   base::WideToUTF8(buffer, chars_written - 1, &result);
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index 4dc4ccfc..a1a65aee 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -86,6 +86,7 @@
     sources += [
       "keycodes/keyboard_code_conversion_xkb.cc",
       "keycodes/keyboard_code_conversion_xkb.h",
+      "keycodes/scoped_xkb.h",
       "keycodes/xkb_keysym.h",
     ]
   }
diff --git a/ui/events/ozone/layout/xkb/scoped_xkb.h b/ui/events/keycodes/scoped_xkb.h
similarity index 80%
rename from ui/events/ozone/layout/xkb/scoped_xkb.h
rename to ui/events/keycodes/scoped_xkb.h
index 66ec295..5eb701f 100644
--- a/ui/events/ozone/layout/xkb/scoped_xkb.h
+++ b/ui/events/keycodes/scoped_xkb.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_EVENTS_OZONE_LAYOUT_XKB_SCOPED_XKB_H_
-#define UI_EVENTS_OZONE_LAYOUT_XKB_SCOPED_XKB_H_
+#ifndef UI_EVENTS_KEYCODES_SCOPED_XKB_H_
+#define UI_EVENTS_KEYCODES_SCOPED_XKB_H_
 
 #include <xkbcommon/xkbcommon.h>
 
@@ -25,4 +25,4 @@
 
 }  // namespace ui
 
-#endif  // UI_EVENTS_OZONE_LAYOUT_XKB_SCOPED_XKB_H_
+#endif  // UI_EVENTS_KEYCODES_SCOPED_XKB_H_
diff --git a/ui/events/ozone/BUILD.gn b/ui/events/ozone/BUILD.gn
index c30ba34..2bef777 100644
--- a/ui/events/ozone/BUILD.gn
+++ b/ui/events/ozone/BUILD.gn
@@ -201,7 +201,6 @@
     configs += [ ":xkbcommon" ]
 
     sources += [
-      "layout/xkb/scoped_xkb.h",
       "layout/xkb/xkb.h",
       "layout/xkb/xkb_evdev_codes.cc",
       "layout/xkb/xkb_evdev_codes.h",
diff --git a/ui/events/ozone/evdev/event_converter_evdev.cc b/ui/events/ozone/evdev/event_converter_evdev.cc
index 98a46f0..de24b953 100644
--- a/ui/events/ozone/evdev/event_converter_evdev.cc
+++ b/ui/events/ozone/evdev/event_converter_evdev.cc
@@ -143,7 +143,8 @@
 
 base::TimeDelta EventConverterEvdev::TimeDeltaFromInputEvent(
     const input_event& event) {
-  return base::TimeDelta::FromMicroseconds(event.time.tv_sec * 1000000 +
-                                           event.time.tv_usec);
+  return base::TimeDelta::FromMicroseconds(
+      static_cast<int64>(event.time.tv_sec) * 1000000L +
+      event.time.tv_usec);
 }
 }  // namespace ui
diff --git a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h
index 6714e57..ea2d4de 100644
--- a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h
+++ b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h
@@ -14,9 +14,9 @@
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
 #include "base/task_runner.h"
+#include "ui/events/keycodes/scoped_xkb.h"
 #include "ui/events/ozone/layout/events_ozone_layout_export.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine.h"
-#include "ui/events/ozone/layout/xkb/scoped_xkb.h"
 #include "ui/events/ozone/layout/xkb/xkb_key_code_converter.h"
 
 namespace ui {
diff --git a/ui/events/test/event_generator.cc b/ui/events/test/event_generator.cc
index 08c8d18..021268b 100644
--- a/ui/events/test/event_generator.cc
+++ b/ui/events/test/event_generator.cc
@@ -665,11 +665,18 @@
     }
     pending_events_.push_back(pending_event);
   } else {
-    ui::EventSource* event_source = delegate()->GetEventSource(current_target_);
-    ui::EventSourceTestApi event_source_test(event_source);
-    ui::EventDispatchDetails details =
-        event_source_test.SendEventToProcessor(event);
-    CHECK(!details.dispatcher_destroyed);
+    if (event->IsKeyEvent()) {
+      delegate()->DispatchKeyEventToIME(current_target_,
+                                        static_cast<ui::KeyEvent*>(event));
+    }
+    if (!event->handled()) {
+      ui::EventSource* event_source =
+          delegate()->GetEventSource(current_target_);
+      ui::EventSourceTestApi event_source_test(event_source);
+      ui::EventDispatchDetails details =
+          event_source_test.SendEventToProcessor(event);
+      CHECK(!details.dispatcher_destroyed);
+    }
   }
 }
 
diff --git a/ui/events/test/event_generator.h b/ui/events/test/event_generator.h
index 9a72695..9261cc8 100644
--- a/ui/events/test/event_generator.h
+++ b/ui/events/test/event_generator.h
@@ -74,6 +74,12 @@
   // |hosted_target| into the root window's coordinate system.
   virtual void ConvertPointFromHost(const EventTarget* hosted_target,
                                     gfx::Point* point) const = 0;
+
+  // Detemines whether the input method should be the first to handle key events
+  // before dispathcing to Views. If it does, the given |event| will be
+  // dispatched and processed by the input method from the host of |target|.
+  virtual void DispatchKeyEventToIME(EventTarget* target,
+                                     ui::KeyEvent* event) = 0;
 };
 
 // ui::test::EventGenerator is a tool that generates and dispatches events.
diff --git a/ui/file_manager/audio_player/elements/track_list.css b/ui/file_manager/audio_player/elements/track_list.css
index c04ad559..e39398a 100644
--- a/ui/file_manager/audio_player/elements/track_list.css
+++ b/ui/file_manager/audio_player/elements/track_list.css
@@ -67,6 +67,7 @@
   justify-content: center;
   margin-left: 0;
   margin-right: 4px;
+  min-width: 0;
 }
 
 .track .data .data-title,
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index bc5b7531..4d200d5 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -281,8 +281,8 @@
       "harfbuzz_font_skia.h",
       "render_text_harfbuzz.cc",
       "render_text_harfbuzz.h",
-      "render_text_mac.cc",
       "render_text_mac.h",
+      "render_text_mac.mm",
       "text_utils_skia.cc",
     ]
 
diff --git a/ui/gfx/font.cc b/ui/gfx/font.cc
index 915db076..2990205 100644
--- a/ui/gfx/font.cc
+++ b/ui/gfx/font.cc
@@ -64,7 +64,7 @@
   return platform_font_->GetStyle();
 }
 
-std::string Font::GetFontName() const {
+const std::string& Font::GetFontName() const {
   return platform_font_->GetFontName();
 }
 
diff --git a/ui/gfx/font.h b/ui/gfx/font.h
index 18f3a96..da26a907 100644
--- a/ui/gfx/font.h
+++ b/ui/gfx/font.h
@@ -88,7 +88,7 @@
   int GetStyle() const;
 
   // Returns the specified font name in UTF-8.
-  std::string GetFontName() const;
+  const std::string& GetFontName() const;
 
   // Returns the actually used font name in UTF-8.
   std::string GetActualFontNameForTesting() const;
diff --git a/ui/gfx/font_fallback.h b/ui/gfx/font_fallback.h
index 05d21cad..d0d838f9 100644
--- a/ui/gfx/font_fallback.h
+++ b/ui/gfx/font_fallback.h
@@ -5,17 +5,17 @@
 #ifndef UI_GFX_FONT_FALLBACK_H_
 #define UI_GFX_FONT_FALLBACK_H_
 
-#include <string>
 #include <vector>
 
+#include "ui/gfx/font.h"
 #include "ui/gfx/gfx_export.h"
 
 namespace gfx {
 
-// Given a font family name, returns the names of font families that are
-// suitable for fallback.
-GFX_EXPORT std::vector<std::string> GetFallbackFontFamilies(
-    const std::string& font_family);
+class Font;
+
+// Given a font, returns the fonts that are suitable for fallback.
+GFX_EXPORT std::vector<Font> GetFallbackFonts(const Font& font);
 
 }  // namespace gfx
 
diff --git a/ui/gfx/font_fallback_android.cc b/ui/gfx/font_fallback_android.cc
index 37f9b69..e41fa9d 100644
--- a/ui/gfx/font_fallback_android.cc
+++ b/ui/gfx/font_fallback_android.cc
@@ -9,9 +9,8 @@
 
 namespace gfx {
 
-std::vector<std::string> GetFallbackFontFamilies(
-    const std::string& font_family) {
-  return std::vector<std::string>();
+std::vector<Font> GetFallbackFonts(const Font& font) {
+  return std::vector<Font>();
 }
 
 }  // namespace gfx
diff --git a/ui/gfx/font_fallback_linux.cc b/ui/gfx/font_fallback_linux.cc
index 5b7e4f1..919ac64 100644
--- a/ui/gfx/font_fallback_linux.cc
+++ b/ui/gfx/font_fallback_linux.cc
@@ -11,20 +11,21 @@
 #include <vector>
 
 #include "base/lazy_instance.h"
+#include "ui/gfx/font.h"
 
 namespace gfx {
 
 namespace {
 
-typedef std::map<std::string, std::vector<std::string> > FallbackCache;
+typedef std::map<std::string, std::vector<Font> > FallbackCache;
 base::LazyInstance<FallbackCache>::Leaky g_fallback_cache =
     LAZY_INSTANCE_INITIALIZER;
 
 }  // namespace
 
-std::vector<std::string> GetFallbackFontFamilies(
-    const std::string& font_family) {
-  std::vector<std::string>* fallback_fonts =
+std::vector<Font> GetFallbackFonts(const Font& font) {
+  std::string font_family = font.GetFontName();
+  std::vector<Font>* fallback_fonts =
       &g_fallback_cache.Get()[font_family];
   if (!fallback_fonts->empty())
     return *fallback_fonts;
@@ -45,8 +46,10 @@
             reinterpret_cast<FcChar8**>(&name));
         // FontConfig returns multiple fonts with the same family name and
         // different configurations. Check to prevent duplicate family names.
-        if (fallback_fonts->empty() || fallback_fonts->back() != name)
-          fallback_fonts->push_back(std::string(name));
+        if (fallback_fonts->empty() ||
+            fallback_fonts->back().GetFontName() != name) {
+          fallback_fonts->push_back(Font(std::string(name), 13));
+        }
       }
       FcFontSetDestroy(fonts);
     }
@@ -54,7 +57,7 @@
   FcPatternDestroy(pattern);
 
   if (fallback_fonts->empty())
-    fallback_fonts->push_back(font_family);
+    fallback_fonts->push_back(Font(font_family, 13));
 
   return *fallback_fonts;
 }
diff --git a/ui/gfx/font_fallback_mac.mm b/ui/gfx/font_fallback_mac.mm
index d312f8b0..aa66729 100644
--- a/ui/gfx/font_fallback_mac.mm
+++ b/ui/gfx/font_fallback_mac.mm
@@ -12,6 +12,7 @@
 #include "base/mac/foundation_util.h"
 #import "base/mac/mac_util.h"
 #import "base/strings/sys_string_conversions.h"
+#include "ui/gfx/font.h"
 
 // CTFontCopyDefaultCascadeListForLanguages() doesn't exist in the 10.6 SDK.
 // There is only the following. It doesn't exist in the public header files,
@@ -42,8 +43,7 @@
 
 namespace gfx {
 
-std::vector<std::string> GetFallbackFontFamilies(
-    const std::string& font_family) {
+std::vector<Font> GetFallbackFonts(const Font& font) {
   // On Mac "There is a system default cascade list (which is polymorphic, based
   // on the user's language setting and current font)" - CoreText Programming
   // Guide.
@@ -51,50 +51,29 @@
   // it requires a text string "hint", and the returned font can't be
   // represented by name for easy retrieval later.
   // In 10.8, CTFontCopyDefaultCascadeListForLanguages(font, language_list)
-  // showed up which is a good fit GetFallbackFontFamilies().
-
-  // Size doesn't matter for querying the cascade list.
-  const CGFloat font_size = 10.0;
-  base::ScopedCFTypeRef<CFStringRef> cfname(
-      base::SysUTF8ToCFStringRef(font_family));
-
-  // Using CTFontCreateWithName here works, but CoreText emits stderr spam along
-  // the lines of `CTFontCreateWithName() using name "Arial" and got font with
-  // PostScript name "ArialMT".` Instead, create a descriptor.
-  const void* attribute_keys[] = {kCTFontFamilyNameAttribute};
-  const void* attribute_values[] = {cfname.get()};
-  base::ScopedCFTypeRef<CFDictionaryRef> attributes(CFDictionaryCreate(
-      kCFAllocatorDefault, attribute_keys, attribute_values, 1,
-      &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
-  base::ScopedCFTypeRef<CTFontDescriptorRef> descriptor(
-      CTFontDescriptorCreateWithAttributes(attributes));
-  base::ScopedCFTypeRef<CTFontRef> base_font(
-      CTFontCreateWithFontDescriptor(descriptor, font_size, nullptr));
-
-  if (!base_font)
-    return std::vector<std::string>(1, font_family);
-
+  // showed up which is a good fit GetFallbackFonts().
   NSArray* languages = [[NSUserDefaults standardUserDefaults]
       stringArrayForKey:@"AppleLanguages"];
   CFArrayRef languages_cf = base::mac::NSToCFCast(languages);
   base::ScopedCFTypeRef<CFArrayRef> cascade_list(
-      CTFontCopyDefaultCascadeListForLanguagesWrapper(base_font, languages_cf));
+      CTFontCopyDefaultCascadeListForLanguagesWrapper(
+          static_cast<CTFontRef>(font.GetNativeFont()), languages_cf));
 
-  std::vector<std::string> fallback_fonts;
+  std::vector<Font> fallback_fonts;
 
   const CFIndex fallback_count = CFArrayGetCount(cascade_list);
   for (CFIndex i = 0; i < fallback_count; ++i) {
     CTFontDescriptorRef descriptor =
         base::mac::CFCastStrict<CTFontDescriptorRef>(
             CFArrayGetValueAtIndex(cascade_list, i));
-    base::ScopedCFTypeRef<CFStringRef> font_name(
-        base::mac::CFCastStrict<CFStringRef>(CTFontDescriptorCopyAttribute(
-            descriptor, kCTFontFamilyNameAttribute)));
-    fallback_fonts.push_back(base::SysCFStringRefToUTF8(font_name));
+    base::ScopedCFTypeRef<CTFontRef> font(
+        CTFontCreateWithFontDescriptor(descriptor, 0.0, nullptr));
+    if (font.get())
+      fallback_fonts.push_back(Font(static_cast<NSFont*>(font.get())));
   }
 
   if (fallback_fonts.empty())
-    return std::vector<std::string>(1, font_family);
+    return std::vector<Font>(1, font);
 
   return fallback_fonts;
 }
diff --git a/ui/gfx/font_fallback_mac_unittest.cc b/ui/gfx/font_fallback_mac_unittest.cc
index 689ec6d..ed0c739 100644
--- a/ui/gfx/font_fallback_mac_unittest.cc
+++ b/ui/gfx/font_fallback_mac_unittest.cc
@@ -5,17 +5,19 @@
 #include "ui/gfx/font_fallback.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/font.h"
 
 namespace gfx {
 
-// A targeted test for GetFallbackFontFamilies on Mac. It uses a system API that
+// A targeted test for GetFallbackFonts on Mac. It uses a system API that
 // only became publicly available in the 10.8 SDK. This test is to ensure it
 // behaves sensibly on all supported OS versions.
-GTEST_TEST(FontFallbackMacTest, GetFallbackFontFamilies) {
-  std::vector<std::string> fallback_families = GetFallbackFontFamilies("Arial");
+GTEST_TEST(FontFallbackMacTest, GetFallbackFonts) {
+  Font font("Arial", 12);
+  std::vector<Font> fallback_fonts = GetFallbackFonts(font);
   // If there is only one fallback, it means the only fallback is the font
   // itself.
-  EXPECT_LT(1u, fallback_families.size());
+  EXPECT_LT(1u, fallback_fonts.size());
 }
 
 }  // namespace gfx
diff --git a/ui/gfx/font_fallback_win.cc b/ui/gfx/font_fallback_win.cc
index c578ba8..058c0d9 100644
--- a/ui/gfx/font_fallback_win.cc
+++ b/ui/gfx/font_fallback_win.cc
@@ -269,14 +269,15 @@
 
 }  // namespace internal
 
-std::vector<std::string> GetFallbackFontFamilies(
-    const std::string& font_family) {
+std::vector<Font> GetFallbackFonts(const Font& font) {
+  std::string font_family = font.GetFontName();
+
   // LinkedFontsIterator doesn't care about the font size, so we always pass 10.
   internal::LinkedFontsIterator linked_fonts(Font(font_family, 10));
-  std::vector<std::string> fallback_fonts;
+  std::vector<Font> fallback_fonts;
   Font current;
   while (linked_fonts.NextFont(&current))
-    fallback_fonts.push_back(current.GetFontName());
+    fallback_fonts.push_back(current);
   return fallback_fonts;
 }
 
diff --git a/ui/gfx/geometry/rect.cc b/ui/gfx/geometry/rect.cc
index 25bc9f5..077e32c1 100644
--- a/ui/gfx/geometry/rect.cc
+++ b/ui/gfx/geometry/rect.cc
@@ -244,6 +244,13 @@
                             size().ToString().c_str());
 }
 
+bool Rect::ApproximatelyEqual(const Rect& rect, int tolerance) const {
+  return std::abs(x() - rect.x()) <= tolerance &&
+         std::abs(y() - rect.y()) <= tolerance &&
+         std::abs(right() - rect.right()) <= tolerance &&
+         std::abs(bottom() - rect.bottom()) <= tolerance;
+}
+
 Rect operator+(const Rect& lhs, const Vector2d& rhs) {
   Rect result(lhs);
   result += rhs;
diff --git a/ui/gfx/geometry/rect.h b/ui/gfx/geometry/rect.h
index 9e0508d5..c778396 100644
--- a/ui/gfx/geometry/rect.h
+++ b/ui/gfx/geometry/rect.h
@@ -179,6 +179,8 @@
 
   std::string ToString() const;
 
+  bool ApproximatelyEqual(const Rect& rect, int tolerance) const;
+
  private:
   gfx::Point origin_;
   gfx::Size size_;
diff --git a/ui/gfx/gfx.gyp b/ui/gfx/gfx.gyp
index 49825cc6..71e2547 100644
--- a/ui/gfx/gfx.gyp
+++ b/ui/gfx/gfx.gyp
@@ -255,8 +255,8 @@
         'render_text.h',
         'render_text_harfbuzz.cc',
         'render_text_harfbuzz.h',
-        'render_text_mac.cc',
         'render_text_mac.h',
+        'render_text_mac.mm',
         'scoped_canvas.h',
         'scoped_cg_context_save_gstate_mac.h',
         'scoped_ns_graphics_context_save_gstate_mac.h',
diff --git a/ui/gfx/platform_font.h b/ui/gfx/platform_font.h
index 6fbaeca..a854743 100644
--- a/ui/gfx/platform_font.h
+++ b/ui/gfx/platform_font.h
@@ -57,7 +57,7 @@
   virtual int GetStyle() const = 0;
 
   // Returns the specified font name in UTF-8.
-  virtual std::string GetFontName() const = 0;
+  virtual const std::string& GetFontName() const = 0;
 
   // Returns the actually used font name in UTF-8.
   virtual std::string GetActualFontNameForTesting() const = 0;
diff --git a/ui/gfx/platform_font_ios.h b/ui/gfx/platform_font_ios.h
index ca3f131d..e42b1f4 100644
--- a/ui/gfx/platform_font_ios.h
+++ b/ui/gfx/platform_font_ios.h
@@ -23,7 +23,7 @@
   int GetCapHeight() const override;
   int GetExpectedTextWidth(int length) const override;
   int GetStyle() const override;
-  std::string GetFontName() const override;
+  const std::string& GetFontName() const override;
   std::string GetActualFontNameForTesting() const override;
   int GetFontSize() const override;
   const FontRenderParams& GetFontRenderParams() override;
diff --git a/ui/gfx/platform_font_ios.mm b/ui/gfx/platform_font_ios.mm
index db5bbc82..676fef0 100644
--- a/ui/gfx/platform_font_ios.mm
+++ b/ui/gfx/platform_font_ios.mm
@@ -67,7 +67,7 @@
   return style_;
 }
 
-std::string PlatformFontIOS::GetFontName() const {
+const std::string& PlatformFontIOS::GetFontName() const {
   return font_name_;
 }
 
diff --git a/ui/gfx/platform_font_linux.cc b/ui/gfx/platform_font_linux.cc
index eb5b7a3..16a8bbc 100644
--- a/ui/gfx/platform_font_linux.cc
+++ b/ui/gfx/platform_font_linux.cc
@@ -176,7 +176,7 @@
   return style_;
 }
 
-std::string PlatformFontLinux::GetFontName() const {
+const std::string& PlatformFontLinux::GetFontName() const {
   return font_family_;
 }
 
diff --git a/ui/gfx/platform_font_linux.h b/ui/gfx/platform_font_linux.h
index c31f2491..dc8cd55 100644
--- a/ui/gfx/platform_font_linux.h
+++ b/ui/gfx/platform_font_linux.h
@@ -45,7 +45,7 @@
   int GetCapHeight() const override;
   int GetExpectedTextWidth(int length) const override;
   int GetStyle() const override;
-  std::string GetFontName() const override;
+  const std::string& GetFontName() const override;
   std::string GetActualFontNameForTesting() const override;
   int GetFontSize() const override;
   const FontRenderParams& GetFontRenderParams() override;
diff --git a/ui/gfx/platform_font_mac.h b/ui/gfx/platform_font_mac.h
index 54c97cd..95c0f50 100644
--- a/ui/gfx/platform_font_mac.h
+++ b/ui/gfx/platform_font_mac.h
@@ -26,7 +26,7 @@
   int GetCapHeight() const override;
   int GetExpectedTextWidth(int length) const override;
   int GetStyle() const override;
-  std::string GetFontName() const override;
+  const std::string& GetFontName() const override;
   std::string GetActualFontNameForTesting() const override;
   int GetFontSize() const override;
   const FontRenderParams& GetFontRenderParams() override;
diff --git a/ui/gfx/platform_font_mac.mm b/ui/gfx/platform_font_mac.mm
index fb65127..185e9b32 100644
--- a/ui/gfx/platform_font_mac.mm
+++ b/ui/gfx/platform_font_mac.mm
@@ -120,7 +120,7 @@
   return font_style_;
 }
 
-std::string PlatformFontMac::GetFontName() const {
+const std::string& PlatformFontMac::GetFontName() const {
   return font_name_;
 }
 
diff --git a/ui/gfx/platform_font_win.cc b/ui/gfx/platform_font_win.cc
index 1f8ca3e..d271f01 100644
--- a/ui/gfx/platform_font_win.cc
+++ b/ui/gfx/platform_font_win.cc
@@ -387,7 +387,7 @@
   return font_ref_->style();
 }
 
-std::string PlatformFontWin::GetFontName() const {
+const std::string& PlatformFontWin::GetFontName() const {
   return font_ref_->font_name();
 }
 
diff --git a/ui/gfx/platform_font_win.h b/ui/gfx/platform_font_win.h
index 91fcb72..825acac 100644
--- a/ui/gfx/platform_font_win.h
+++ b/ui/gfx/platform_font_win.h
@@ -62,7 +62,7 @@
   int GetCapHeight() const override;
   int GetExpectedTextWidth(int length) const override;
   int GetStyle() const override;
-  std::string GetFontName() const override;
+  const std::string& GetFontName() const override;
   std::string GetActualFontNameForTesting() const override;
   int GetFontSize() const override;
   const FontRenderParams& GetFontRenderParams() override;
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc
index 07d0fb3..ffede9e5 100644
--- a/ui/gfx/render_text.cc
+++ b/ui/gfx/render_text.cc
@@ -22,6 +22,7 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/safe_integer_conversions.h"
+#include "ui/gfx/platform_font.h"
 #include "ui/gfx/render_text_harfbuzz.h"
 #include "ui/gfx/scoped_canvas.h"
 #include "ui/gfx/skia_util.h"
@@ -31,6 +32,7 @@
 #include "ui/gfx/utf16_indexing.h"
 
 #if defined(OS_MACOSX)
+#include "third_party/skia/include/ports/SkTypeface_mac.h"
 #include "ui/gfx/render_text_mac.h"
 #endif  // defined(OS_MACOSX)
 
@@ -85,6 +87,7 @@
   return baseline + std::max(min_shift, std::min(max_shift, baseline_shift));
 }
 
+#if !defined(OS_MACOSX)
 // Converts |Font::FontStyle| flags to |SkTypeface::Style| flags.
 SkTypeface::Style ConvertFontStyleToSkiaTypefaceStyle(int font_style) {
   int skia_style = SkTypeface::kNormal;
@@ -92,6 +95,7 @@
   skia_style |= (font_style & Font::ITALIC) ? SkTypeface::kItalic : 0;
   return static_cast<SkTypeface::Style>(skia_style);
 }
+#endif
 
 int round(float value) {
   return static_cast<int>(floor(value + 0.5f));
@@ -246,11 +250,8 @@
   paint_.setTextSize(size);
 }
 
-void SkiaTextRenderer::SetFontFamilyWithStyle(const std::string& family,
-                                              int style) {
-  DCHECK(!family.empty());
-
-  skia::RefPtr<SkTypeface> typeface = CreateSkiaTypeface(family.c_str(), style);
+void SkiaTextRenderer::SetFontWithStyle(const Font& font, int style) {
+  skia::RefPtr<SkTypeface> typeface = CreateSkiaTypeface(font, style);
   if (typeface) {
     // |paint_| adds its own ref. So don't |release()| it from the ref ptr here.
     SetTypeface(typeface.get());
@@ -413,11 +414,13 @@
 
 Line::~Line() {}
 
-skia::RefPtr<SkTypeface> CreateSkiaTypeface(const std::string& family,
-                                            int style) {
+#if !defined(OS_MACOSX)
+skia::RefPtr<SkTypeface> CreateSkiaTypeface(const gfx::Font& font, int style) {
   SkTypeface::Style skia_style = ConvertFontStyleToSkiaTypefaceStyle(style);
-  return skia::AdoptRef(SkTypeface::CreateFromName(family.c_str(), skia_style));
+  return skia::AdoptRef(
+      SkTypeface::CreateFromName(font.GetFontName().c_str(), skia_style));
 }
+#endif
 
 void ApplyRenderParams(const FontRenderParams& params,
                        bool subpixel_rendering_suppressed,
diff --git a/ui/gfx/render_text.h b/ui/gfx/render_text.h
index 4ca9a62..25780a7 100644
--- a/ui/gfx/render_text.h
+++ b/ui/gfx/render_text.h
@@ -58,7 +58,7 @@
                            bool subpixel_rendering_suppressed);
   void SetTypeface(SkTypeface* typeface);
   void SetTextSize(SkScalar size);
-  void SetFontFamilyWithStyle(const std::string& family, int font_style);
+  void SetFontWithStyle(const Font& font, int font_style);
   void SetForegroundColor(SkColor foreground);
   void SetShader(SkShader* shader);
   // Sets underline metrics to use if the text will be drawn with an underline.
@@ -181,10 +181,9 @@
   int baseline;
 };
 
-// Creates an SkTypeface from a font |family| name and a |gfx::Font::FontStyle|.
+// Creates an SkTypeface from a font and a |gfx::Font::FontStyle|.
 // May return NULL.
-skia::RefPtr<SkTypeface> CreateSkiaTypeface(const std::string& family,
-                                            int style);
+skia::RefPtr<SkTypeface> CreateSkiaTypeface(const gfx::Font& font, int style);
 
 // Applies the given FontRenderParams to a Skia |paint|.
 void ApplyRenderParams(const FontRenderParams& params,
diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc
index 1e806c6d..1cac24f 100644
--- a/ui/gfx/render_text_harfbuzz.cc
+++ b/ui/gfx/render_text_harfbuzz.cc
@@ -20,6 +20,7 @@
 #include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkTypeface.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/font.h"
 #include "ui/gfx/font_fallback.h"
 #include "ui/gfx/font_render_params.h"
 #include "ui/gfx/geometry/safe_integer_conversions.h"
@@ -550,8 +551,9 @@
 
 // Function object for case insensitive string comparison.
 struct CaseInsensitiveCompare {
-  bool operator() (const std::string& a, const std::string& b) const {
-    return base::CompareCaseInsensitiveASCII(a, b) < 0;
+  bool operator() (const Font& a, const Font& b) const {
+    return base::CompareCaseInsensitiveASCII(a.GetFontName(), b.GetFontName()) <
+           0;
   }
 };
 
@@ -1303,18 +1305,18 @@
 
 bool RenderTextHarfBuzz::CompareFamily(
     const base::string16& text,
-    const std::string& family,
+    const Font& font,
     const gfx::FontRenderParams& render_params,
     internal::TextRunHarfBuzz* run,
-    std::string* best_family,
+    Font* best_font,
     gfx::FontRenderParams* best_render_params,
     size_t* best_missing_glyphs) {
-  if (!ShapeRunWithFont(text, family, render_params, run))
+  if (!ShapeRunWithFont(text, font, render_params, run))
     return false;
 
   const size_t missing_glyphs = run->CountMissingGlyphs();
   if (missing_glyphs < *best_missing_glyphs) {
-    *best_family = family;
+    *best_font = font;
     *best_render_params = render_params;
     *best_missing_glyphs = missing_glyphs;
   }
@@ -1359,14 +1361,13 @@
     }
   }
 
-  std::string best_family;
+  Font best_font;
   FontRenderParams best_render_params;
   size_t best_missing_glyphs = std::numeric_limits<size_t>::max();
 
   for (const Font& font : font_list().GetFonts()) {
-    if (CompareFamily(text, font.GetFontName(), font.GetFontRenderParams(),
-                      run, &best_family, &best_render_params,
-                      &best_missing_glyphs))
+    if (CompareFamily(text, font, font.GetFontRenderParams(), run, &best_font,
+                      &best_render_params, &best_missing_glyphs))
       return;
   }
 
@@ -1377,22 +1378,20 @@
   if (GetUniscribeFallbackFont(primary_font, run_text, run->range.length(),
                                &uniscribe_font)) {
     uniscribe_family = uniscribe_font.GetFontName();
-    if (CompareFamily(text, uniscribe_family,
+    if (CompareFamily(text, uniscribe_font,
                       uniscribe_font.GetFontRenderParams(), run,
-                      &best_family, &best_render_params, &best_missing_glyphs))
+                      &best_font, &best_render_params, &best_missing_glyphs))
       return;
   }
 #endif
 
-  std::vector<std::string> fallback_families =
-      GetFallbackFontFamilies(primary_family);
+  std::vector<Font> fallback_font_list = GetFallbackFonts(primary_font);
 
 #if defined(OS_WIN)
   // Append fonts in the fallback list of the Uniscribe font.
   if (!uniscribe_family.empty()) {
-    std::vector<std::string> uniscribe_fallbacks =
-        GetFallbackFontFamilies(uniscribe_family);
-    fallback_families.insert(fallback_families.end(),
+    std::vector<Font> uniscribe_fallbacks = GetFallbackFonts(uniscribe_font);
+    fallback_font_list.insert(fallback_font_list.end(),
         uniscribe_fallbacks.begin(), uniscribe_fallbacks.end());
   }
 
@@ -1401,44 +1400,46 @@
   // http://crbug.com/467459. On some Windows configurations the default font
   // could be a raster font like System, which would not give us a reasonable
   // fallback font list.
-  if (!base::LowerCaseEqualsASCII(primary_family, "segoe ui") &&
+  if (!base::LowerCaseEqualsASCII(primary_font.GetFontName(), "segoe ui") &&
       !base::LowerCaseEqualsASCII(uniscribe_family, "segoe ui")) {
-    std::vector<std::string> default_fallback_families =
-        GetFallbackFontFamilies("Segoe UI");
-    fallback_families.insert(fallback_families.end(),
+    std::vector<Font> default_fallback_families =
+        GetFallbackFonts(Font("Segoe UI", 13));
+    fallback_font_list.insert(fallback_font_list.end(),
         default_fallback_families.begin(), default_fallback_families.end());
   }
 #endif
 
   // Use a set to track the fallback fonts and avoid duplicate entries.
-  std::set<std::string, CaseInsensitiveCompare> fallback_fonts;
+  std::set<Font, CaseInsensitiveCompare> fallback_fonts;
 
   // Try shaping with the fallback fonts.
-  for (const auto& family : fallback_families) {
-    if (family == primary_family)
+  for (const auto& font : fallback_font_list) {
+    std::string font_name = font.GetFontName();
+
+    if (font_name == primary_font.GetFontName())
       continue;
 #if defined(OS_WIN)
-    if (family == uniscribe_family)
+    if (font_name == uniscribe_family)
       continue;
 #endif
-    if (fallback_fonts.find(family) != fallback_fonts.end())
+    if (fallback_fonts.find(font) != fallback_fonts.end())
       continue;
 
-    fallback_fonts.insert(family);
+    fallback_fonts.insert(font);
 
     FontRenderParamsQuery query;
-    query.families.push_back(family);
+    query.families.push_back(font_name);
     query.pixel_size = run->font_size;
     query.style = run->font_style;
     FontRenderParams fallback_render_params = GetFontRenderParams(query, NULL);
-    if (CompareFamily(text, family, fallback_render_params, run, &best_family,
+    if (CompareFamily(text, font, fallback_render_params, run, &best_font,
                       &best_render_params, &best_missing_glyphs))
       return;
   }
 
-  if (!best_family.empty() &&
-      (best_family == run->family ||
-       ShapeRunWithFont(text, best_family, best_render_params, run)))
+  if (best_missing_glyphs != std::numeric_limits<size_t>::max() &&
+      (best_font.GetFontName() == run->font.GetFontName() ||
+       ShapeRunWithFont(text, best_font, best_render_params, run)))
     return;
 
   run->glyph_count = 0;
@@ -1446,15 +1447,15 @@
 }
 
 bool RenderTextHarfBuzz::ShapeRunWithFont(const base::string16& text,
-                                          const std::string& font_family,
+                                          const gfx::Font& font,
                                           const FontRenderParams& params,
                                           internal::TextRunHarfBuzz* run) {
   skia::RefPtr<SkTypeface> skia_face =
-      internal::CreateSkiaTypeface(font_family, run->font_style);
+      internal::CreateSkiaTypeface(font, run->font_style);
   if (skia_face == NULL)
     return false;
   run->skia_face = skia_face;
-  run->family = font_family;
+  run->font = font;
   run->render_params = params;
 
   hb_font_t* harfbuzz_font = CreateHarfBuzzFont(
diff --git a/ui/gfx/render_text_harfbuzz.h b/ui/gfx/render_text_harfbuzz.h
index 38411c2..ffcba39 100644
--- a/ui/gfx/render_text_harfbuzz.h
+++ b/ui/gfx/render_text_harfbuzz.h
@@ -68,7 +68,7 @@
   std::vector<uint32> glyph_to_char;
   size_t glyph_count;
 
-  std::string family;
+  Font font;
   skia::RefPtr<SkTypeface> skia_face;
   FontRenderParams render_params;
   int font_size;
@@ -215,15 +215,15 @@
                          internal::TextRunList* run_list_out);
 
   // Helper method for ShapeRun() that calls ShapeRunWithFont() with |text|,
-  // |run|, |family|, and |render_params|, returning true if the family provides
+  // |run|, |font|, and |render_params|, returning true if the font provides
   // all the glyphs needed for |run|, and false otherwise. Additionally updates
-  // |best_family|, |best_render_params|, and |best_missing_glyphs| if |family|
+  // |best_font|, |best_render_params|, and |best_missing_glyphs| if |font|
   // has fewer than |best_missing_glyphs| missing glyphs.
   bool CompareFamily(const base::string16& text,
-                     const std::string& family,
+                     const Font& font,
                      const gfx::FontRenderParams& render_params,
                      internal::TextRunHarfBuzz* run,
-                     std::string* best_family,
+                     Font* best_font,
                      gfx::FontRenderParams* best_render_params,
                      size_t* best_missing_glyphs);
 
@@ -235,7 +235,7 @@
   void ShapeRun(const base::string16& text,
                 internal::TextRunHarfBuzz* run);
   bool ShapeRunWithFont(const base::string16& text,
-                        const std::string& font_family,
+                        const Font& font,
                         const FontRenderParams& params,
                         internal::TextRunHarfBuzz* run);
 
diff --git a/ui/gfx/render_text_mac.h b/ui/gfx/render_text_mac.h
index c7dd086e..f45700f 100644
--- a/ui/gfx/render_text_mac.h
+++ b/ui/gfx/render_text_mac.h
@@ -65,9 +65,7 @@
     std::vector<uint16> glyphs;
     std::vector<SkPoint> glyph_positions;
     SkScalar width;
-    std::string font_name;
-    int font_style;
-    SkScalar text_size;
+    Font font;
     SkColor foreground;
     bool underline;
     bool strike;
diff --git a/ui/gfx/render_text_mac.cc b/ui/gfx/render_text_mac.mm
similarity index 84%
rename from ui/gfx/render_text_mac.cc
rename to ui/gfx/render_text_mac.mm
index 654b7026..4e863a6 100644
--- a/ui/gfx/render_text_mac.cc
+++ b/ui/gfx/render_text_mac.mm
@@ -5,23 +5,33 @@
 #include "ui/gfx/render_text_mac.h"
 
 #include <ApplicationServices/ApplicationServices.h>
+#import <AppKit/AppKit.h>
+#include <CoreText/CoreText.h>
 
 #include <algorithm>
 #include <cmath>
 #include <utility>
 
 #include "base/mac/foundation_util.h"
+#include "base/mac/mac_util.h"
 #include "base/mac/scoped_cftyperef.h"
 #include "base/strings/sys_string_conversions.h"
 #include "skia/ext/skia_utils_mac.h"
+#include "third_party/skia/include/ports/SkTypeface_mac.h"
 
 namespace {
 
-// This function makes a copy of |font| with the given symbolic traits. This
-// function is similar to CTFontCreateCopyWithSymbolicTraits, but this function
-// works on OSX 10.10, unlike CTFontCreateCopyWithSymbolicTraits.
+// This function makes a copy of |font| with the given symbolic traits. On OSX
+// 10.11, CTFontCreateCopyWithSymbolicTraits has the right behavior but
+// CTFontCreateWithFontDescriptor does not. The opposite holds true for OSX
+// 10.10.
 base::ScopedCFTypeRef<CTFontRef> CopyFontWithSymbolicTraits(CTFontRef font,
                                                             int sym_traits) {
+  if (base::mac::IsOSElCapitanOrLater()) {
+    return base::ScopedCFTypeRef<CTFontRef>(CTFontCreateCopyWithSymbolicTraits(
+        font, 0, nullptr, sym_traits, sym_traits));
+  }
+
   base::ScopedCFTypeRef<CTFontDescriptorRef> orig_desc(
       CTFontCopyFontDescriptor(font));
   base::ScopedCFTypeRef<CFDictionaryRef> orig_attributes(
@@ -52,12 +62,21 @@
 
 namespace gfx {
 
-RenderTextMac::RenderTextMac()
-    : common_baseline_(0), runs_valid_(false) {
+namespace internal {
+
+skia::RefPtr<SkTypeface> CreateSkiaTypeface(const gfx::Font& font, int style) {
+  gfx::Font font_with_style = font.Derive(0, style);
+  if (!font_with_style.GetNativeFont())
+    return nullptr;
+  return skia::AdoptRef(SkCreateTypefaceFromCTFont(
+      static_cast<CTFontRef>(font_with_style.GetNativeFont())));
 }
 
-RenderTextMac::~RenderTextMac() {
-}
+}  // namespace internal
+
+RenderTextMac::RenderTextMac() : common_baseline_(0), runs_valid_(false) {}
+
+RenderTextMac::~RenderTextMac() {}
 
 scoped_ptr<RenderText> RenderTextMac::CreateInstanceOfSameType() const {
   return make_scoped_ptr(new RenderTextMac);
@@ -93,10 +112,9 @@
 
   std::vector<RenderText::FontSpan> spans;
   for (size_t i = 0; i < runs_.size(); ++i) {
-    Font font(runs_[i].font_name, runs_[i].text_size);
     const CFRange cf_range = CTRunGetStringRange(runs_[i].ct_run);
     const Range range(cf_range.location, cf_range.location + cf_range.length);
-    spans.push_back(RenderText::FontSpan(font, range));
+    spans.push_back(RenderText::FontSpan(runs_[i].font, range));
   }
 
   return spans;
@@ -149,8 +167,7 @@
 void RenderTextMac::OnLayoutTextAttributeChanged(bool text_changed) {
   DCHECK(!multiline()) << "RenderTextMac does not support multi line";
   if (text_changed) {
-    if (elide_behavior() != NO_ELIDE &&
-        elide_behavior() != FADE_TAIL &&
+    if (elide_behavior() != NO_ELIDE && elide_behavior() != FADE_TAIL &&
         !layout_text().empty()) {
       UpdateDisplayText(std::ceil(GetLayoutTextWidth()));
     } else {
@@ -189,8 +206,18 @@
   for (size_t i = 0; i < runs_.size(); ++i) {
     const TextRun& run = runs_[i];
     renderer->SetForegroundColor(run.foreground);
-    renderer->SetTextSize(run.text_size);
-    renderer->SetFontFamilyWithStyle(run.font_name, run.font_style);
+
+    CTFontRef ct_font = static_cast<CTFontRef>(run.font.GetNativeFont());
+    renderer->SetTextSize(CTFontGetSize(ct_font));
+
+    int font_style = Font::NORMAL;
+    CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ct_font);
+    if (traits & kCTFontBoldTrait)
+      font_style |= Font::BOLD;
+    if (traits & kCTFontItalicTrait)
+      font_style |= Font::ITALIC;
+    renderer->SetFontWithStyle(run.font, font_style);
+
     renderer->DrawPosText(&run.glyph_positions[0], &run.glyphs[0],
                           run.glyphs.size());
     renderer->DrawDecorations(run.origin.x(), run.origin.y(), run.width,
@@ -204,16 +231,12 @@
     : ct_run(NULL),
       origin(SkPoint::Make(0, 0)),
       width(0),
-      font_style(Font::NORMAL),
-      text_size(0),
       foreground(SK_ColorBLACK),
       underline(false),
       strike(false),
-      diagonal_strike(false) {
-}
+      diagonal_strike(false) {}
 
-RenderTextMac::TextRun::~TextRun() {
-}
+RenderTextMac::TextRun::~TextRun() {}
 
 float RenderTextMac::GetLayoutTextWidth() {
   base::ScopedCFTypeRef<CFMutableArrayRef> attributes_owner;
@@ -239,29 +262,23 @@
   ascent = std::max(ascent, font_list_baseline);
   descent = std::max(descent, font_list_height - font_list_baseline);
   *baseline = ascent;
-  return SizeF(
-      width, std::max(ascent + descent + leading,
-                      static_cast<CGFloat>(min_line_height())));
+  return SizeF(width, std::max(ascent + descent + leading,
+                               static_cast<CGFloat>(min_line_height())));
 }
 
 base::ScopedCFTypeRef<CTLineRef> RenderTextMac::EnsureLayoutInternal(
     const base::string16& text,
     base::ScopedCFTypeRef<CFMutableArrayRef>* attributes_owner) {
-  CTFontRef ct_font = base::mac::NSToCFCast(
-      font_list().GetPrimaryFont().GetNativeFont());
+  CTFontRef ct_font =
+      base::mac::NSToCFCast(font_list().GetPrimaryFont().GetNativeFont());
 
-  const void* keys[] = { kCTFontAttributeName };
-  const void* values[] = { ct_font };
+  const void* keys[] = {kCTFontAttributeName};
+  const void* values[] = {ct_font};
   base::ScopedCFTypeRef<CFDictionaryRef> attributes(
-      CFDictionaryCreate(NULL,
-                         keys,
-                         values,
-                         arraysize(keys),
-                         NULL,
+      CFDictionaryCreate(NULL, keys, values, arraysize(keys), NULL,
                          &kCFTypeDictionaryValueCallBacks));
 
-  base::ScopedCFTypeRef<CFStringRef> cf_text(
-      base::SysUTF16ToCFStringRef(text));
+  base::ScopedCFTypeRef<CFStringRef> cf_text(base::SysUTF16ToCFStringRef(text));
   base::ScopedCFTypeRef<CFAttributedStringRef> attr_text(
       CFAttributedStringCreate(NULL, cf_text, attributes));
   base::ScopedCFTypeRef<CFMutableAttributedStringRef> attr_text_mutable(
@@ -298,16 +315,15 @@
     base::ScopedCFTypeRef<CGColorRef> foreground(
         CGColorCreateFromSkColor(style.color()));
     CFAttributedStringSetAttribute(attr_string, range,
-        kCTForegroundColorAttributeName, foreground);
+                                   kCTForegroundColorAttributeName, foreground);
     CFArrayAppendValue(attributes, foreground);
 
     if (style.style(UNDERLINE)) {
       CTUnderlineStyle value = kCTUnderlineStyleSingle;
       base::ScopedCFTypeRef<CFNumberRef> underline_value(
           CFNumberCreate(NULL, kCFNumberSInt32Type, &value));
-      CFAttributedStringSetAttribute(attr_string, range,
-                                     kCTUnderlineStyleAttributeName,
-                                     underline_value);
+      CFAttributedStringSetAttribute(
+          attr_string, range, kCTUnderlineStyleAttributeName, underline_value);
       CFArrayAppendValue(attributes, underline_value);
     }
 
@@ -394,23 +410,12 @@
     // TODO(asvitkine): Style boundaries are not necessarily per-run. Handle
     //                  this better. Also, support strike and diagonal_strike.
     CFDictionaryRef attributes = CTRunGetAttributes(ct_run);
-    CTFontRef ct_font =
-        base::mac::GetValueFromDictionary<CTFontRef>(attributes,
-                                                     kCTFontAttributeName);
-    base::ScopedCFTypeRef<CFStringRef> font_name_ref(
-        CTFontCopyFamilyName(ct_font));
-    run->font_name = base::SysCFStringRefToUTF8(font_name_ref);
-    run->text_size = CTFontGetSize(ct_font);
+    CTFontRef ct_font = base::mac::GetValueFromDictionary<CTFontRef>(
+        attributes, kCTFontAttributeName);
+    run->font = Font(static_cast<NSFont*>(ct_font));
 
-    CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ct_font);
-    if (traits & kCTFontBoldTrait)
-      run->font_style |= Font::BOLD;
-    if (traits & kCTFontItalicTrait)
-      run->font_style |= Font::ITALIC;
-
-    const CGColorRef foreground =
-        base::mac::GetValueFromDictionary<CGColorRef>(
-            attributes, kCTForegroundColorAttributeName);
+    const CGColorRef foreground = base::mac::GetValueFromDictionary<CGColorRef>(
+        attributes, kCTForegroundColorAttributeName);
     if (foreground)
       run->foreground = CGColorRefToSkColor(foreground);
 
diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc
index 019d125..5750f19e 100644
--- a/ui/gfx/render_text_unittest.cc
+++ b/ui/gfx/render_text_unittest.cc
@@ -2871,8 +2871,9 @@
   internal::TextRunList* run_list = render_text.GetRunList();
   ASSERT_EQ(1U, run_list->size());
   internal::TextRunHarfBuzz* run = run_list->runs()[0];
-  render_text.ShapeRunWithFont(
-      render_text.text(), "TheFontThatDoesntExist", FontRenderParams(), run);
+  render_text.ShapeRunWithFont(render_text.text(),
+                               Font("TheFontThatDoesntExist", 13),
+                               FontRenderParams(), run);
 }
 
 // Ensure an empty run returns sane values to queries.
@@ -2972,7 +2973,7 @@
 }
 #endif  // defined(OS_WIN)
 
-// Ensure that the fallback fonts offered by gfx::GetFallbackFontFamilies() are
+// Ensure that the fallback fonts offered by gfx::GetFallbackFonts() are
 // tried. Note this test assumes the font "Arial" doesn't provide a unicode
 // glyph for a particular character, and that there exists a system fallback
 // font which does.
diff --git a/ui/gfx/transform.cc b/ui/gfx/transform.cc
index a7cf86e..a0445e4 100644
--- a/ui/gfx/transform.cc
+++ b/ui/gfx/transform.cc
@@ -533,6 +533,27 @@
   point->SetPoint(ToRoundedInt(p[0]), ToRoundedInt(p[1]));
 }
 
+bool Transform::ApproximatelyEqual(const gfx::Transform& transform) const {
+  static const float component_tolerance = 0.1f;
+
+  // We may have a larger discrepancy in the scroll components due to snapping
+  // (floating point error might round the other way).
+  static const float translation_tolerance = 1.f;
+
+  for (int row = 0; row < 4; row++) {
+    for (int col = 0; col < 4; col++) {
+      const float delta =
+          std::abs(matrix().get(row, col) - transform.matrix().get(row, col));
+      const float tolerance =
+          col == 3 && row < 3 ? translation_tolerance : component_tolerance;
+      if (delta > tolerance)
+        return false;
+    }
+  }
+
+  return true;
+}
+
 std::string Transform::ToString() const {
   return base::StringPrintf(
       "[ %+0.4f %+0.4f %+0.4f %+0.4f  \n"
diff --git a/ui/gfx/transform.h b/ui/gfx/transform.h
index 20740ad7..26f7b9d2 100644
--- a/ui/gfx/transform.h
+++ b/ui/gfx/transform.h
@@ -254,6 +254,7 @@
   // Returns the underlying matrix.
   const SkMatrix44& matrix() const { return matrix_; }
   SkMatrix44& matrix() { return matrix_; }
+  bool ApproximatelyEqual(const gfx::Transform& transform) const;
 
   std::string ToString() const;
 
diff --git a/ui/native_theme/native_theme_base.cc b/ui/native_theme/native_theme_base.cc
index a5784e27..6bb0591 100644
--- a/ui/native_theme/native_theme_base.cc
+++ b/ui/native_theme/native_theme_base.cc
@@ -16,6 +16,7 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/color_palette.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
@@ -43,6 +44,10 @@
 
 const SkColor kTextBorderColor = SkColorSetRGB(0xa9, 0xa9, 0xa9);
 
+const SkColor kProgressBorderColor = kTextBorderColor;
+const SkColor kProgressTickColor = SkColorSetRGB(0xED, 0xED, 0xED);
+const SkColor kProgressValueColor = gfx::kGoogleBlue300;
+
 const SkColor kMenuPopupBackgroundColor = SkColorSetRGB(210, 225, 246);
 
 const unsigned int kDefaultScrollbarWidth = 15;
@@ -889,90 +894,43 @@
   PaintArrowButton(canvas, half, kScrollbarDownArrow, south_state);
 }
 
-void NativeThemeBase::PaintProgressBar(SkCanvas* canvas,
+void NativeThemeBase::PaintProgressBar(
+    SkCanvas* canvas,
     State state,
     const gfx::Rect& rect,
     const ProgressBarExtraParams& progress_bar) const {
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  gfx::ImageSkia* bar_image = rb.GetImageSkiaNamed(IDR_PROGRESS_BAR);
-  gfx::ImageSkia* left_border_image = rb.GetImageSkiaNamed(
-      IDR_PROGRESS_BORDER_LEFT);
-  gfx::ImageSkia* right_border_image = rb.GetImageSkiaNamed(
-      IDR_PROGRESS_BORDER_RIGHT);
+  DCHECK(!rect.IsEmpty());
+  canvas->drawColor(SK_ColorWHITE);
 
-  DCHECK(bar_image->width() > 0);
-  DCHECK(rect.width() > 0);
-
-  float tile_scale_y = static_cast<float>(rect.height()) / bar_image->height();
-
-  int dest_left_border_width = left_border_image->width();
-  int dest_right_border_width = right_border_image->width();
-
-  // Since an implicit float -> int conversion will truncate, we want to make
-  // sure that if a border is desired, it gets at least one pixel.
-  if (dest_left_border_width > 0) {
-    dest_left_border_width = dest_left_border_width * tile_scale_y;
-    dest_left_border_width = std::max(dest_left_border_width, 1);
+  // Draw the tick marks. The spacing between the tick marks is adjusted to
+  // evenly divide into the width.
+  SkPath path;
+  int stroke_width = std::max(1, rect.height() / 18);
+  int tick_width = 16 * stroke_width;
+  int ticks = rect.width() / tick_width + (rect.width() % tick_width ? 1 : 0);
+  SkScalar tick_spacing = SkIntToScalar(rect.width()) / ticks;
+  for (int i = 1; i < ticks; ++i) {
+    path.moveTo(rect.x() + i * tick_spacing, rect.y());
+    path.rLineTo(0, rect.height());
   }
-  if (dest_right_border_width > 0) {
-    dest_right_border_width = dest_right_border_width * tile_scale_y;
-    dest_right_border_width = std::max(dest_right_border_width, 1);
-  }
+  SkPaint stroke_paint;
+  stroke_paint.setColor(kProgressTickColor);
+  stroke_paint.setStyle(SkPaint::kStroke_Style);
+  stroke_paint.setStrokeWidth(stroke_width);
+  canvas->drawPath(path, stroke_paint);
 
-  // Since the width of the progress bar may not be evenly divisible by the
-  // tile size, in order to make it look right we may need to draw some of the
-  // with a width of 1 pixel smaller than the rest of the tiles.
-  int new_tile_width = static_cast<int>(bar_image->width() * tile_scale_y);
-  new_tile_width = std::max(new_tile_width, 1);
+  // Draw progress.
+  gfx::Rect progress_rect(progress_bar.value_rect_x, progress_bar.value_rect_y,
+                          progress_bar.value_rect_width,
+                          progress_bar.value_rect_height);
+  SkPaint progress_paint;
+  progress_paint.setColor(kProgressValueColor);
+  progress_paint.setStyle(SkPaint::kFill_Style);
+  canvas->drawRect(gfx::RectToSkRect(progress_rect), progress_paint);
 
-  float tile_scale_x = static_cast<float>(new_tile_width) / bar_image->width();
-  if (rect.width() % new_tile_width == 0) {
-    DrawTiledImage(canvas, *bar_image, 0, 0, tile_scale_x, tile_scale_y,
-        rect.x(), rect.y(),
-        rect.width(), rect.height());
-  } else {
-    int num_tiles = 1 + rect.width() / new_tile_width;
-    int overshoot = num_tiles * new_tile_width - rect.width();
-    // Since |overshoot| represents the number of tiles that were too big, draw
-    // |overshoot| tiles with their width reduced by 1.
-    int num_big_tiles = num_tiles - overshoot;
-    int num_small_tiles = overshoot;
-    int small_width = new_tile_width - 1;
-    float small_scale_x = static_cast<float>(small_width) / bar_image->width();
-    float big_scale_x = tile_scale_x;
-
-    gfx::Rect big_rect = rect;
-    gfx::Rect small_rect = rect;
-    big_rect.Inset(0, 0, num_small_tiles*small_width, 0);
-    small_rect.Inset(num_big_tiles*new_tile_width, 0, 0, 0);
-
-    DrawTiledImage(canvas, *bar_image, 0, 0, big_scale_x, tile_scale_y,
-      big_rect.x(), big_rect.y(), big_rect.width(), big_rect.height());
-    DrawTiledImage(canvas, *bar_image, 0, 0, small_scale_x, tile_scale_y,
-      small_rect.x(), small_rect.y(), small_rect.width(), small_rect.height());
-  }
-  if (progress_bar.value_rect_width) {
-    gfx::ImageSkia* value_image = rb.GetImageSkiaNamed(IDR_PROGRESS_VALUE);
-
-    new_tile_width = static_cast<int>(value_image->width() * tile_scale_y);
-    tile_scale_x = static_cast<float>(new_tile_width) /
-        value_image->width();
-
-    DrawTiledImage(canvas, *value_image, 0, 0, tile_scale_x, tile_scale_y,
-        progress_bar.value_rect_x,
-        progress_bar.value_rect_y,
-        progress_bar.value_rect_width,
-        progress_bar.value_rect_height);
-  }
-
-  DrawImageInt(canvas, *left_border_image, 0, 0, left_border_image->width(),
-      left_border_image->height(), rect.x(), rect.y(), dest_left_border_width,
-      rect.height());
-
-  int dest_x = rect.right() - dest_right_border_width;
-  DrawImageInt(canvas, *right_border_image, 0, 0, right_border_image->width(),
-               right_border_image->height(), dest_x, rect.y(),
-               dest_right_border_width, rect.height());
+  // Draw the border.
+  stroke_paint.setColor(kProgressBorderColor);
+  canvas->drawRect(gfx::RectToSkRect(rect), stroke_paint);
 }
 
 void NativeThemeBase::AdjustCheckboxRadioRectForPadding(SkRect* rect) const {
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc
index cf05c89..91834768 100644
--- a/ui/native_theme/native_theme_win.cc
+++ b/ui/native_theme/native_theme_win.cc
@@ -356,10 +356,8 @@
 }
 
 void NativeThemeWin::UpdateSystemColors() {
-  for (int i = 0; i < arraysize(kSystemColors); ++i) {
-    system_colors_[kSystemColors[i]] =
-        color_utils::GetSysSkColor(kSystemColors[i]);
-  }
+  for (int kSystemColor : kSystemColors)
+    system_colors_[kSystemColor] = color_utils::GetSysSkColor(kSystemColor);
 }
 
 void NativeThemeWin::PaintDirect(SkCanvas* canvas,
diff --git a/ui/ozone/platform/cast/ozone_platform_cast.cc b/ui/ozone/platform/cast/ozone_platform_cast.cc
index bd4053e..338fac22 100644
--- a/ui/ozone/platform/cast/ozone_platform_cast.cc
+++ b/ui/ozone/platform/cast/ozone_platform_cast.cc
@@ -80,6 +80,11 @@
     cursor_factory_.reset(new CursorFactoryOzone());
     input_controller_ = CreateStubInputController();
     gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
+
+    // Enable dummy software rendering support if GPU process disabled
+    // Note: switch is kDisableGpu from content/public/common/content_switches.h
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch("disable-gpu"))
+      surface_factory_.reset(new SurfaceFactoryCast());
   }
   void InitializeGPU() override {
     surface_factory_.reset(new SurfaceFactoryCast(egl_platform_.Pass()));
diff --git a/ui/ozone/platform/cast/surface_factory_cast.cc b/ui/ozone/platform/cast/surface_factory_cast.cc
index 4d5c57e0..f92e1c9 100644
--- a/ui/ozone/platform/cast/surface_factory_cast.cc
+++ b/ui/ozone/platform/cast/surface_factory_cast.cc
@@ -10,9 +10,12 @@
 #include "base/callback_helpers.h"
 #include "chromecast/public/cast_egl_platform.h"
 #include "chromecast/public/graphics_types.h"
+#include "third_party/skia/include/core/SkSurface.h"
 #include "ui/gfx/geometry/quad_f.h"
+#include "ui/gfx/vsync_provider.h"
 #include "ui/ozone/platform/cast/surface_ozone_egl_cast.h"
 #include "ui/ozone/public/native_pixmap.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
 
 using chromecast::CastEglPlatform;
 
@@ -37,8 +40,35 @@
   return gfx::Size(1280, 720);
 }
 
+class DummySurface : public SurfaceOzoneCanvas {
+ public:
+  DummySurface() {}
+  ~DummySurface() override {}
+
+  // SurfaceOzoneCanvas implementation:
+  skia::RefPtr<SkSurface> GetSurface() override { return surface_; }
+
+  void ResizeCanvas(const gfx::Size& viewport_size) override {
+    surface_ = skia::AdoptRef(SkSurface::NewRaster(SkImageInfo::MakeN32Premul(
+        viewport_size.width(), viewport_size.height())));
+  }
+
+  void PresentCanvas(const gfx::Rect& damage) override {}
+
+  scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override {
+    return nullptr;
+  }
+
+ private:
+  skia::RefPtr<SkSurface> surface_;
+
+  DISALLOW_COPY_AND_ASSIGN(DummySurface);
+};
+
 }  // namespace
 
+SurfaceFactoryCast::SurfaceFactoryCast() : SurfaceFactoryCast(nullptr) {}
+
 SurfaceFactoryCast::SurfaceFactoryCast(scoped_ptr<CastEglPlatform> egl_platform)
     : state_(kUninitialized),
       display_type_(0),
@@ -97,6 +127,14 @@
   state_ = kUninitialized;
 }
 
+scoped_ptr<SurfaceOzoneCanvas> SurfaceFactoryCast::CreateCanvasForWidget(
+    gfx::AcceleratedWidget widget) {
+  // Software canvas support only in headless mode
+  if (egl_platform_)
+    return nullptr;
+  return make_scoped_ptr<SurfaceOzoneCanvas>(new DummySurface());
+}
+
 intptr_t SurfaceFactoryCast::GetNativeDisplay() {
   CreateDisplayTypeAndWindowIfNeeded();
   return reinterpret_cast<intptr_t>(display_type_);
@@ -177,7 +215,7 @@
 }
 
 scoped_refptr<NativePixmap> SurfaceFactoryCast::CreateNativePixmap(
-    gfx::AcceleratedWidget w,
+    gfx::AcceleratedWidget widget,
     gfx::Size size,
     gfx::BufferFormat format,
     gfx::BufferUsage usage) {
diff --git a/ui/ozone/platform/cast/surface_factory_cast.h b/ui/ozone/platform/cast/surface_factory_cast.h
index c0bc8f9..ec77974 100644
--- a/ui/ozone/platform/cast/surface_factory_cast.h
+++ b/ui/ozone/platform/cast/surface_factory_cast.h
@@ -18,17 +18,20 @@
 // SurfaceFactoryOzone implementation for OzonePlatformCast.
 class SurfaceFactoryCast : public SurfaceFactoryOzone {
  public:
+  SurfaceFactoryCast();
   explicit SurfaceFactoryCast(
       scoped_ptr<chromecast::CastEglPlatform> egl_platform);
   ~SurfaceFactoryCast() override;
 
   // SurfaceFactoryOzone implementation:
+  scoped_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
+      gfx::AcceleratedWidget widget) override;
   intptr_t GetNativeDisplay() override;
   scoped_ptr<SurfaceOzoneEGL> CreateEGLSurfaceForWidget(
       gfx::AcceleratedWidget widget) override;
   const int32* GetEGLSurfaceProperties(const int32* desired_list) override;
   scoped_refptr<NativePixmap> CreateNativePixmap(
-      gfx::AcceleratedWidget w,
+      gfx::AcceleratedWidget widget,
       gfx::Size size,
       gfx::BufferFormat format,
       gfx::BufferUsage usage) override;
diff --git a/ui/platform_window/x11/x11_window.cc b/ui/platform_window/x11/x11_window.cc
index c84135fa..6900a448 100644
--- a/ui/platform_window/x11/x11_window.cc
+++ b/ui/platform_window/x11/x11_window.cc
@@ -9,6 +9,7 @@
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 
+#include "base/strings/utf_string_conversions.h"
 #include "ui/events/devices/x11/touch_factory_x11.h"
 #include "ui/events/event.h"
 #include "ui/events/event_utils.h"
@@ -25,9 +26,11 @@
 namespace {
 
 const char* kAtomsToCache[] = {
+  "UTF8_STRING",
   "WM_DELETE_WINDOW",
-  "_NET_WM_PING",
+  "_NET_WM_NAME",
   "_NET_WM_PID",
+  "_NET_WM_PING",
   NULL
 };
 
@@ -243,7 +246,27 @@
   return confirmed_bounds_;
 }
 
-void X11Window::SetTitle(const base::string16& title) {}
+void X11Window::SetTitle(const base::string16& title) {
+  if (window_title_ == title)
+    return;
+  window_title_ = title;
+  std::string utf8str = base::UTF16ToUTF8(title);
+  XChangeProperty(xdisplay_,
+                  xwindow_,
+                  atom_cache_.GetAtom("_NET_WM_NAME"),
+                  atom_cache_.GetAtom("UTF8_STRING"),
+                  8,
+                  PropModeReplace,
+                  reinterpret_cast<const unsigned char*>(utf8str.c_str()),
+                  utf8str.size());
+  XTextProperty xtp;
+  char *c_utf8_str = const_cast<char *>(utf8str.c_str());
+  if (Xutf8TextListToTextProperty(xdisplay_, &c_utf8_str, 1,
+                                  XUTF8StringStyle, &xtp) == Success) {
+    XSetWMName(xdisplay_, xwindow_, &xtp);
+    XFree(xtp.value);
+  }
+}
 
 void X11Window::SetCapture() {}
 
diff --git a/ui/platform_window/x11/x11_window.h b/ui/platform_window/x11/x11_window.h
index bceb8ad3..84a4899 100644
--- a/ui/platform_window/x11/x11_window.h
+++ b/ui/platform_window/x11/x11_window.h
@@ -57,6 +57,8 @@
   XID xroot_window_;
   X11AtomCache atom_cache_;
 
+  base::string16 window_title_;
+
   // Setting the bounds is an asynchronous operation in X11. |requested_bounds_|
   // is the bounds requested using XConfigureWindow, and |confirmed_bounds_| is
   // the bounds the X11 server has set on the window.
diff --git a/ui/resources/default_100_percent/linux/linux-progress-bar.png b/ui/resources/default_100_percent/linux/linux-progress-bar.png
deleted file mode 100644
index fc0e47d..0000000
--- a/ui/resources/default_100_percent/linux/linux-progress-bar.png
+++ /dev/null
Binary files differ
diff --git a/ui/resources/default_100_percent/linux/linux-progress-border-left.png b/ui/resources/default_100_percent/linux/linux-progress-border-left.png
deleted file mode 100644
index 8aa1840f..0000000
--- a/ui/resources/default_100_percent/linux/linux-progress-border-left.png
+++ /dev/null
Binary files differ
diff --git a/ui/resources/default_100_percent/linux/linux-progress-border-right.png b/ui/resources/default_100_percent/linux/linux-progress-border-right.png
deleted file mode 100644
index 8aa1840f..0000000
--- a/ui/resources/default_100_percent/linux/linux-progress-border-right.png
+++ /dev/null
Binary files differ
diff --git a/ui/resources/default_100_percent/linux/linux-progress-value.png b/ui/resources/default_100_percent/linux/linux-progress-value.png
deleted file mode 100644
index 1e0211f2..0000000
--- a/ui/resources/default_100_percent/linux/linux-progress-value.png
+++ /dev/null
Binary files differ
diff --git a/ui/resources/ui_resources.grd b/ui/resources/ui_resources.grd
index 66a18806..8098218 100644
--- a/ui/resources/ui_resources.grd
+++ b/ui/resources/ui_resources.grd
@@ -182,12 +182,6 @@
         <structure type="chrome_scaled_image" name="IDR_PANEL_BOTTOM_LEFT_CORNER" file="panel_bottom_left_corner.png" />
         <structure type="chrome_scaled_image" name="IDR_PANEL_BOTTOM_RIGHT_CORNER" file="panel_bottom_right_corner.png" />
       </if>
-      <if expr="use_aura or toolkit_views or (is_posix and not is_macosx and not is_ios)">
-        <structure type="chrome_scaled_image" name="IDR_PROGRESS_BAR" file="linux/linux-progress-bar.png" />
-        <structure type="chrome_scaled_image" name="IDR_PROGRESS_BORDER_LEFT" file="linux/linux-progress-border-left.png" />
-        <structure type="chrome_scaled_image" name="IDR_PROGRESS_BORDER_RIGHT" file="linux/linux-progress-border-right.png" />
-        <structure type="chrome_scaled_image" name="IDR_PROGRESS_VALUE" file="linux/linux-progress-value.png" />
-      </if>
       <if expr="use_aura">
         <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_HOVER_BOTTOM" file="common/aura_scrollbar_arrow_button_base_hover_bottom.png" />
         <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_HOVER_BOTTOM_LEFT" file="common/aura_scrollbar_arrow_button_base_hover_bottom_left.png" />
diff --git a/ui/resources/ui_resources.gyp b/ui/resources/ui_resources.gyp
index 71e3e64..60a93dbd 100644
--- a/ui/resources/ui_resources.gyp
+++ b/ui/resources/ui_resources.gyp
@@ -15,7 +15,6 @@
         {
           'action_name': 'ui_resources',
           'variables': {
-            'grit_whitelist': '',
             'grit_grd_file': 'ui_resources.grd',
           },
           'includes': [ '../../build/grit_action.gypi' ],
@@ -23,7 +22,6 @@
         {
           'action_name': 'webui_resources',
           'variables': {
-            'grit_whitelist': '',
             'grit_grd_file': '../webui/resources/webui_resources.grd',
           },
           'includes': [ '../../build/grit_action.gypi' ],
@@ -31,7 +29,6 @@
         {
           'action_name': 'ui_unscaled_resources',
           'variables': {
-            'grit_whitelist': '',
             'grit_grd_file': 'ui_unscaled_resources.grd',
           },
           'includes': [ '../../build/grit_action.gypi' ],
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index b411f18..21015b5 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -72,6 +72,7 @@
 
   if (is_chromeos) {
     sources -= [
+      "controls/menu/menu_config_linux.cc",
       "linux_ui/status_icon_linux.cc",
       "linux_ui/status_icon_linux.h",
     ]
diff --git a/ui/views/animation/ink_drop_delegate_unittest.cc b/ui/views/animation/ink_drop_delegate_unittest.cc
new file mode 100644
index 0000000..0691a86
--- /dev/null
+++ b/ui/views/animation/ink_drop_delegate_unittest.cc
@@ -0,0 +1,113 @@
+// 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/views/animation/ink_drop_delegate.h"
+
+#include "ui/views/animation/ink_drop_host.h"
+#include "ui/views/controls/button/custom_button.h"
+#include "ui/views/test/views_test_base.h"
+
+namespace views {
+
+namespace {
+
+// An InkDropDelegate that keeps track of order of deletions.
+class TestInkDropDelegate : public InkDropDelegate {
+ public:
+  TestInkDropDelegate(InkDropHost* ink_drop_host,
+                      bool* button_deleted,
+                      bool* delegate_deleted)
+      : ink_drop_host_(ink_drop_host),
+        button_deleted_(button_deleted),
+        delegate_deleted_(delegate_deleted) {
+    ink_drop_host_->AddInkDropLayer(nullptr);
+  }
+  ~TestInkDropDelegate() override {
+    EXPECT_FALSE(*button_deleted_);
+    ink_drop_host_->RemoveInkDropLayer(nullptr);
+    *delegate_deleted_ = true;
+  }
+
+  // InkDropDelegate:
+  void SetInkDropSize(int large_size,
+                      int large_corner_radius,
+                      int small_size,
+                      int small_corner_radius) override {}
+  void OnLayout() override {}
+  void OnAction(InkDropState state) override {}
+
+ private:
+  InkDropHost* ink_drop_host_;
+  bool* button_deleted_;
+  bool* delegate_deleted_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestInkDropDelegate);
+};
+
+// A test Button class that owns a TestInkDropDelegate.
+class TestButton : public views::CustomButton, public views::InkDropHost {
+ public:
+  TestButton(bool* layer_added,
+             bool* layer_removed,
+             bool* button_deleted,
+             bool* delegate_deleted)
+      : CustomButton(nullptr),
+        layer_added_(layer_added),
+        layer_removed_(layer_removed),
+        button_deleted_(button_deleted),
+        ink_drop_delegate_(
+            new TestInkDropDelegate(this, button_deleted, delegate_deleted)) {
+    set_ink_drop_delegate(ink_drop_delegate_.get());
+    EXPECT_TRUE(*layer_added_);
+  }
+  ~TestButton() override {
+    ink_drop_delegate_.reset();
+    set_ink_drop_delegate(nullptr);
+    EXPECT_TRUE(*layer_removed_);
+    *button_deleted_ = true;
+  }
+
+  // views::InkDropHost:
+  void AddInkDropLayer(ui::Layer* ink_drop_layer) override {
+    *layer_added_ = true;
+  }
+  void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override {
+    *layer_removed_ = true;
+  }
+  gfx::Point CalculateInkDropCenter() const override { return gfx::Point(); }
+
+ private:
+  bool* layer_added_;
+  bool* layer_removed_;
+  bool* button_deleted_;
+  scoped_ptr<views::InkDropDelegate> ink_drop_delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestButton);
+};
+
+}  // namespace
+
+// Test that an InkDropDelegate gets safely deleted when a CustomButton is
+// destroyed.
+TEST(InkDropDelegateTest, CanBeDeleted) {
+  bool layer_added = false;
+  bool layer_removed = false;
+  bool button_deleted = false;
+  bool delegate_deleted = false;
+
+  TestButton* button = new TestButton(&layer_added, &layer_removed,
+                                      &button_deleted, &delegate_deleted);
+  EXPECT_TRUE(layer_added);
+  EXPECT_FALSE(layer_removed);
+  EXPECT_FALSE(button_deleted);
+  EXPECT_FALSE(delegate_deleted);
+
+  delete button;
+  EXPECT_TRUE(layer_added);
+  EXPECT_TRUE(layer_removed);
+  EXPECT_TRUE(button_deleted);
+  EXPECT_TRUE(delegate_deleted);
+}
+
+}  // namespace views
diff --git a/ui/views/cocoa/bridged_content_view.mm b/ui/views/cocoa/bridged_content_view.mm
index c30e7c7..82c40dd1 100644
--- a/ui/views/cocoa/bridged_content_view.mm
+++ b/ui/views/cocoa/bridged_content_view.mm
@@ -312,7 +312,7 @@
     return;
 
   if (drawMenuBackgroundForBlur_) {
-    const CGFloat radius = views::MenuConfig::instance(nullptr).corner_radius;
+    const CGFloat radius = views::MenuConfig::instance().corner_radius;
     [gfx::SkColorToSRGBNSColor(0x01000000) set];
     [[NSBezierPath bezierPathWithRoundedRect:[self bounds]
                                      xRadius:radius
diff --git a/ui/views/controls/button/custom_button.cc b/ui/views/controls/button/custom_button.cc
index bb455009..e8ce4a0 100644
--- a/ui/views/controls/button/custom_button.cc
+++ b/ui/views/controls/button/custom_button.cc
@@ -56,6 +56,9 @@
 }
 
 CustomButton::~CustomButton() {
+  // InkDropDelegate needs to be destroyed by now since it may need to call
+  // methods on |this| via InkDropHost.
+  DCHECK(!ink_drop_delegate_);
 }
 
 void CustomButton::SetState(ButtonState state) {
@@ -338,6 +341,7 @@
       is_throbbing_(false),
       triggerable_event_flags_(ui::EF_LEFT_MOUSE_BUTTON),
       request_focus_on_press_(true),
+      ink_drop_delegate_(nullptr),
       notify_action_(NOTIFY_ON_RELEASE) {
   hover_animation_.reset(new gfx::ThrobAnimation(this));
   hover_animation_->SetSlideDuration(kHoverFadeDurationMs);
@@ -381,11 +385,6 @@
   return check_mouse_position && IsMouseHovered();
 }
 
-void CustomButton::SetInkDropDelegate(
-    scoped_ptr<InkDropDelegate> ink_drop_delegate) {
-  ink_drop_delegate_ = ink_drop_delegate.Pass();
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // CustomButton, View overrides (protected):
 
diff --git a/ui/views/controls/button/custom_button.h b/ui/views/controls/button/custom_button.h
index ef250c0b..2f3508f 100644
--- a/ui/views/controls/button/custom_button.h
+++ b/ui/views/controls/button/custom_button.h
@@ -126,9 +126,9 @@
   // state). This does not take into account enabled state.
   bool ShouldEnterHoveredState();
 
-  void SetInkDropDelegate(scoped_ptr<InkDropDelegate> ink_drop_delegate);
-  InkDropDelegate* ink_drop_delegate() const {
-    return ink_drop_delegate_.get();
+  InkDropDelegate* ink_drop_delegate() const { return ink_drop_delegate_; }
+  void set_ink_drop_delegate(InkDropDelegate* ink_drop_delegate) {
+    ink_drop_delegate_ = ink_drop_delegate;
   }
 
   // Overridden from View:
@@ -161,8 +161,10 @@
   // See description above setter.
   bool request_focus_on_press_;
 
-  // Animation delegate for the ink drop ripple effect.
-  scoped_ptr<InkDropDelegate> ink_drop_delegate_;
+  // Animation delegate for the ink drop ripple effect. It is owned by a
+  // descendant class and needs to be reset before an instance of the concrete
+  // CustomButton is destroyed.
+  InkDropDelegate* ink_drop_delegate_;
 
   // The event on which the button should notify its listener.
   NotifyAction notify_action_;
diff --git a/ui/views/controls/combobox/combobox.cc b/ui/views/controls/combobox/combobox.cc
index 51b17e53..2074b0e 100644
--- a/ui/views/controls/combobox/combobox.cc
+++ b/ui/views/controls/combobox/combobox.cc
@@ -233,8 +233,7 @@
  private:
   bool UseCheckmarks() const {
     return owner_->style_ != STYLE_ACTION &&
-           MenuConfig::instance(owner_->GetNativeTheme())
-               .check_selected_combobox_item;
+           MenuConfig::instance().check_selected_combobox_item;
   }
 
   // Overridden from MenuModel:
diff --git a/ui/views/controls/menu/menu_2.cc b/ui/views/controls/menu/menu_2.cc
deleted file mode 100644
index 21bf3238..0000000
--- a/ui/views/controls/menu/menu_2.cc
+++ /dev/null
@@ -1,60 +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 "ui/views/controls/menu/menu_2.h"
-
-#include "ui/base/models/menu_model.h"
-#include "ui/views/controls/menu/menu_listener.h"
-
-namespace views {
-
-Menu2::Menu2(ui::MenuModel* model)
-    : model_(model),
-      wrapper_(MenuWrapper::CreateWrapper(model)) {
-  Rebuild();
-}
-
-Menu2::~Menu2() {}
-
-HMENU Menu2::GetNativeMenu() const {
-  return wrapper_->GetNativeMenu();
-}
-
-void Menu2::RunMenuAt(const gfx::Point& point, Alignment alignment) {
-  wrapper_->RunMenuAt(point, alignment);
-}
-
-void Menu2::RunContextMenuAt(const gfx::Point& point) {
-  RunMenuAt(point, ALIGN_TOPLEFT);
-}
-
-void Menu2::CancelMenu() {
-  wrapper_->CancelMenu();
-}
-
-void Menu2::Rebuild() {
-  wrapper_->Rebuild(NULL);
-}
-
-void Menu2::UpdateStates() {
-  wrapper_->UpdateStates();
-}
-
-MenuWrapper::MenuAction Menu2::GetMenuAction() const {
-  return wrapper_->GetMenuAction();
-}
-
-void Menu2::AddMenuListener(MenuListener* listener) {
-  wrapper_->AddMenuListener(listener);
-}
-
-void Menu2::RemoveMenuListener(MenuListener* listener) {
-  wrapper_->RemoveMenuListener(listener);
-}
-
-void Menu2::SetMinimumWidth(int width) {
-  wrapper_->SetMinimumWidth(width);
-}
-
-}  // namespace
diff --git a/ui/views/controls/menu/menu_2.h b/ui/views/controls/menu/menu_2.h
deleted file mode 100644
index 9c857b28..0000000
--- a/ui/views/controls/menu/menu_2.h
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_MENU_MENU_2_H_
-#define UI_VIEWS_CONTROLS_MENU_MENU_2_H_
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/views/controls/menu/menu_wrapper.h"
-#include "ui/views/views_export.h"
-
-namespace gfx {
-class Point;
-}
-
-namespace ui {
-class MenuModel;
-}
-
-namespace views {
-
-// A menu. Populated from a model, and relies on a delegate to execute commands.
-//
-// WARNING: do NOT create and use Menu2 on the stack. Menu2 notifies the model
-// of selection AFTER a delay. This means that if use a Menu2 on the stack
-// ActivatedAt is never invoked.
-class VIEWS_EXPORT Menu2 {
- public:
-  // How the menu is aligned relative to the point it is shown at.
-  // The alignment is reversed by menu if text direction is right to left.
-  enum Alignment {
-    ALIGN_TOPLEFT,
-    ALIGN_TOPRIGHT
-  };
-
-  // Creates a new menu populated with the contents of |model|.
-  // WARNING: this populates the menu on construction by invoking methods on
-  // the model. As such, it is typically not safe to use this as the model
-  // from the constructor. EG:
-  //   MyClass : menu_(this) {}
-  // is likely to have problems.
-  explicit Menu2(ui::MenuModel* model);
-  virtual ~Menu2();
-
-  // Runs the menu at the specified point. This method blocks until done.
-  // RunContextMenuAt is the same, but the alignment is the default for a
-  // context menu.
-  void RunMenuAt(const gfx::Point& point, Alignment alignment);
-  void RunContextMenuAt(const gfx::Point& point);
-
-  // Cancels the active menu.
-  void CancelMenu();
-
-  // Called when the model supplying data to this menu has changed, and the menu
-  // must be rebuilt.
-  void Rebuild();
-
-  // Called when the states of the menu items in the menu should be refreshed
-  // from the model.
-  void UpdateStates();
-
-  // For submenus.
-  HMENU GetNativeMenu() const;
-
-  // Get the result of the last call to RunMenuAt to determine whether an
-  // item was selected, the user navigated to a next or previous menu, or
-  // nothing.
-  MenuWrapper::MenuAction GetMenuAction() const;
-
-  // Add a listener to receive a callback when the menu opens.
-  void AddMenuListener(MenuListener* listener);
-
-  // Remove a menu listener.
-  void RemoveMenuListener(MenuListener* listener);
-
-  // Accessors.
-  ui::MenuModel* model() const { return model_; }
-
-  // Sets the minimum width of the menu.
-  void SetMinimumWidth(int width);
-
- private:
-
-  ui::MenuModel* model_;
-
-  // The object that actually implements the menu.
-  scoped_ptr<MenuWrapper> wrapper_;
-
-  DISALLOW_COPY_AND_ASSIGN(Menu2);
-};
-
-}  // namespace views
-
-#endif  // UI_VIEWS_CONTROLS_MENU_MENU_2_H_
diff --git a/ui/views/controls/menu/menu_config.cc b/ui/views/controls/menu/menu_config.cc
index 0d726c54..52c39e4d 100644
--- a/ui/views/controls/menu/menu_config.cc
+++ b/ui/views/controls/menu/menu_config.cc
@@ -4,11 +4,11 @@
 
 #include "ui/views/controls/menu/menu_config.h"
 
-#include "build/build_config.h"
+#include "base/macros.h"
 
 namespace views {
 
-MenuConfig::MenuConfig(const ui::NativeTheme* theme)
+MenuConfig::MenuConfig()
     : arrow_color(SK_ColorBLACK),
       menu_vertical_border_size(3),
       menu_horizontal_border_size(0),
@@ -42,9 +42,15 @@
       check_selected_combobox_item(false),
       show_delay(400),
       corner_radius(0) {
-  Init(theme);
+  Init();
 }
 
 MenuConfig::~MenuConfig() {}
 
+// static
+const MenuConfig& MenuConfig::instance() {
+  CR_DEFINE_STATIC_LOCAL(MenuConfig, instance, ());
+  return instance;
+}
+
 }  // namespace views
diff --git a/ui/views/controls/menu/menu_config.h b/ui/views/controls/menu/menu_config.h
index 2a43aca..6bbf4e8 100644
--- a/ui/views/controls/menu/menu_config.h
+++ b/ui/views/controls/menu/menu_config.h
@@ -9,19 +9,15 @@
 #include "ui/gfx/font_list.h"
 #include "ui/views/views_export.h"
 
-namespace ui {
-class NativeTheme;
-}
-
 namespace views {
 
 // Layout type information for menu items. Use the instance() method to obtain
 // the MenuConfig for the current platform.
 struct VIEWS_EXPORT MenuConfig {
-  explicit MenuConfig(const ui::NativeTheme* theme);
+  MenuConfig();
   ~MenuConfig();
 
-  static const MenuConfig& instance(const ui::NativeTheme* theme);
+  static const MenuConfig& instance();
 
   // Font list used by menus.
   gfx::FontList font_list;
@@ -125,10 +121,7 @@
 
  private:
   // Configures a MenuConfig as appropriate for the current platform.
-  void Init(const ui::NativeTheme* theme);
-
-  // TODO: temporary until we standardize.
-  void InitAura(const ui::NativeTheme* theme);
+  void Init();
 };
 
 }  // namespace views
diff --git a/ui/views/controls/menu/menu_config_aura.cc b/ui/views/controls/menu/menu_config_aura.cc
deleted file mode 100644
index a49d447..0000000
--- a/ui/views/controls/menu/menu_config_aura.cc
+++ /dev/null
@@ -1,64 +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 "ui/views/controls/menu/menu_config.h"
-
-#include "ui/base/layout.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/native_theme/native_theme_aura.h"
-#include "ui/resources/grit/ui_resources.h"
-#include "ui/views/controls/menu/menu_image_util.h"
-#include "ui/views/resources/grit/views_resources.h"
-
-namespace views {
-
-namespace {
-#if defined(OS_CHROMEOS)
-static const int kMenuCornerRadiusForAura = 2;
-#else
-static const int kMenuCornerRadiusForAura = 0;
-#endif
-}  // namespace
-
-#if !defined(OS_WIN)
-void MenuConfig::Init(const ui::NativeTheme* theme) {
-  if (theme == ui::NativeThemeAura::instance())
-    InitAura(theme);
-}
-#endif
-
-void MenuConfig::InitAura(const ui::NativeTheme* theme) {
-  submenu_horizontal_inset = 1;
-  arrow_to_edge_padding = 20;
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  arrow_width = rb.GetImageNamed(IDR_MENU_HIERARCHY_ARROW).Width();
-  gfx::ImageSkia check = GetMenuCheckImage(false);
-  check_height = check.height();
-  item_min_height = 29;
-  separator_spacing_height = 7;
-  separator_lower_height = 8;
-  separator_upper_height = 8;
-  label_to_arrow_padding = 20;
-  label_to_minor_text_padding = 20;
-  always_use_icon_to_label_padding = true;
-  align_arrow_and_shortcut = true;
-  offset_context_menus = true;
-  corner_radius = kMenuCornerRadiusForAura;
-
-  // In Ash, the border is provided by the shadow.
-  use_outer_border = false;
-}
-
-#if !defined(OS_WIN)
-// static
-const MenuConfig& MenuConfig::instance(const ui::NativeTheme* theme) {
-  CR_DEFINE_STATIC_LOCAL(MenuConfig, instance,
-                         (theme ? theme : ui::NativeThemeAura::instance()));
-  return instance;
-}
-#endif
-
-}  // namespace views
diff --git a/ui/views/controls/menu/menu_config_chromeos.cc b/ui/views/controls/menu/menu_config_chromeos.cc
new file mode 100644
index 0000000..428b1fdd
--- /dev/null
+++ b/ui/views/controls/menu/menu_config_chromeos.cc
@@ -0,0 +1,37 @@
+// 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 "ui/views/controls/menu/menu_config.h"
+
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/resources/grit/ui_resources.h"
+#include "ui/views/controls/menu/menu_image_util.h"
+
+namespace views {
+
+void MenuConfig::Init() {
+  submenu_horizontal_inset = 1;
+  arrow_to_edge_padding = 20;
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+  arrow_width = rb.GetImageNamed(IDR_MENU_HIERARCHY_ARROW).Width();
+  gfx::ImageSkia check = GetMenuCheckImage(false);
+  check_height = check.height();
+  item_min_height = 29;
+  separator_spacing_height = 7;
+  separator_lower_height = 8;
+  separator_upper_height = 8;
+  label_to_arrow_padding = 20;
+  label_to_minor_text_padding = 20;
+  always_use_icon_to_label_padding = true;
+  align_arrow_and_shortcut = true;
+  offset_context_menus = true;
+  corner_radius = 2;
+
+  // In Ash, the border is provided by the shadow.
+  use_outer_border = false;
+}
+
+}  // namespace views
diff --git a/ui/views/controls/menu/menu_config_linux.cc b/ui/views/controls/menu/menu_config_linux.cc
new file mode 100644
index 0000000..c76ac686
--- /dev/null
+++ b/ui/views/controls/menu/menu_config_linux.cc
@@ -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.
+
+#include "ui/views/controls/menu/menu_config.h"
+
+namespace views {
+
+void MenuConfig::Init() {
+  // Desktop Linux uses the config provided by data member initializers.
+  // Note this causes --open-ash on Linux to use the Desktop Linux style as
+  // well.
+}
+
+}  // namespace views
diff --git a/ui/views/controls/menu/menu_config_mac.mm b/ui/views/controls/menu/menu_config_mac.mm
index 78d6a2cc..9c73a1f2 100644
--- a/ui/views/controls/menu/menu_config_mac.mm
+++ b/ui/views/controls/menu/menu_config_mac.mm
@@ -6,14 +6,9 @@
 
 #import <AppKit/AppKit.h>
 
-#include "ui/gfx/image/image_skia.h"
-#include "ui/native_theme/native_theme_mac.h"
-#include "ui/views/controls/menu/menu_image_util.h"
-
 namespace views {
 
-void MenuConfig::Init(const ui::NativeTheme* theme) {
-  DCHECK_EQ(theme, ui::NativeThemeMac::instance());
+void MenuConfig::Init() {
   font_list = gfx::FontList(gfx::Font([NSFont menuFontOfSize:0.0]));
   menu_vertical_border_size = 4;
   item_top_margin = item_no_icon_top_margin = 1;
@@ -33,10 +28,4 @@
   use_outer_border = false;
 }
 
-// static
-const MenuConfig& MenuConfig::instance(const ui::NativeTheme* theme) {
-  CR_DEFINE_STATIC_LOCAL(MenuConfig, mac_instance, (theme));
-  return mac_instance;
-}
-
 }  // namespace views
diff --git a/ui/views/controls/menu/menu_config_win.cc b/ui/views/controls/menu/menu_config_win.cc
index 3f17f582..0b695674 100644
--- a/ui/views/controls/menu/menu_config_win.cc
+++ b/ui/views/controls/menu/menu_config_win.cc
@@ -13,7 +13,6 @@
 #include "base/win/win_util.h"
 #include "ui/base/l10n/l10n_util_win.h"
 #include "ui/gfx/color_utils.h"
-#include "ui/native_theme/native_theme_aura.h"
 #include "ui/native_theme/native_theme_win.h"
 
 using ui::NativeTheme;
@@ -21,12 +20,7 @@
 
 namespace views {
 
-void MenuConfig::Init(const NativeTheme* theme) {
-  if (theme == ui::NativeThemeAura::instance()) {
-    InitAura(theme);
-    return;
-  }
-
+void MenuConfig::Init() {
   arrow_color = color_utils::GetSysSkColor(COLOR_MENUTEXT);
 
   NONCLIENTMETRICS_XP metrics;
@@ -78,19 +72,4 @@
   separator_lower_height = 7;
 }
 
-// static
-const MenuConfig& MenuConfig::instance(const ui::NativeTheme* theme) {
-  // NOTE: |theme| may be NULL if used before the menu is running.
-  if (!theme || theme == NativeThemeWin::instance()) {
-    static MenuConfig* win_instance = NULL;
-    if (!win_instance)
-      win_instance = new MenuConfig(NativeThemeWin::instance());
-    return *win_instance;
-  }
-  static MenuConfig* views_instance = NULL;
-  if (!views_instance)
-    views_instance = new MenuConfig(theme);
-  return *views_instance;
-}
-
 }  // namespace views
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index b8b202b9..43f167e 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -417,12 +417,24 @@
     return;
   }
   if (async_run_) {
+    internal::MenuControllerDelegate* delegate = delegate_;
     MenuItemView* result = ExitMenuRun();
-    delegate_->OnMenuClosed(internal::MenuControllerDelegate::NOTIFY_DELEGATE,
-                            result, accept_event_flags_);
+    delegate->OnMenuClosed(internal::MenuControllerDelegate::NOTIFY_DELEGATE,
+                           result, accept_event_flags_);
   }
 }
 
+void MenuController::AddNestedDelegate(
+    internal::MenuControllerDelegate* delegate) {
+  delegate_stack_.push_back(std::make_pair(delegate, async_run_));
+  delegate_ = delegate;
+}
+
+void MenuController::SetAsyncRun(bool is_async) {
+  delegate_stack_.back().second = is_async;
+  async_run_ = is_async;
+}
+
 bool MenuController::OnMousePressed(SubmenuView* source,
                                     const ui::MouseEvent& event) {
   // We should either have no current_mouse_event_target_, or should have a
@@ -1186,6 +1198,7 @@
       current_mouse_event_target_(nullptr),
       current_mouse_pressed_state_(0),
       message_loop_(MenuMessageLoop::Create()) {
+  delegate_stack_.push_back(std::make_pair(delegate_, async_run_));
   active_instance_ = this;
 }
 
@@ -1262,9 +1275,10 @@
   }
   accept_event_flags_ = event_flags;
   if (async_run_) {
+    internal::MenuControllerDelegate* delegate = delegate_;
     MenuItemView* result = ExitMenuRun();
-    delegate_->OnMenuClosed(internal::MenuControllerDelegate::NOTIFY_DELEGATE,
-                            result, accept_event_flags_);
+    delegate->OnMenuClosed(internal::MenuControllerDelegate::NOTIFY_DELEGATE,
+                           result, accept_event_flags_);
   }
 }
 
@@ -1678,9 +1692,8 @@
 }
 
 void MenuController::StartShowTimer() {
-  MenuItemView* item = pending_state_.item ? pending_state_.item : state_.item;
   show_timer_.Start(
-      FROM_HERE, TimeDelta::FromMilliseconds(item->GetMenuConfig().show_delay),
+      FROM_HERE, TimeDelta::FromMilliseconds(MenuConfig::instance().show_delay),
       this, &MenuController::CommitPendingSelection);
 }
 
@@ -1723,7 +1736,7 @@
 
   int x, y;
 
-  const MenuConfig& menu_config = item->GetMenuConfig();
+  const MenuConfig& menu_config = MenuConfig::instance();
 
   if (!item->GetParentMenuItem()) {
     // First item, position relative to initial location.
@@ -2442,6 +2455,12 @@
     pending_state_ = menu_stack_.back().first;
     nested_pressed_lock = menu_stack_.back().second;
     menu_stack_.pop_back();
+    // Even though the menus are nested, there may not be nested delegates.
+    if (delegate_stack_.size() > 1) {
+      delegate_stack_.pop_back();
+      delegate_ = delegate_stack_.back().first;
+      async_run_ = delegate_stack_.back().second;
+    }
   } else {
     showing_ = false;
     did_capture_ = false;
diff --git a/ui/views/controls/menu/menu_controller.h b/ui/views/controls/menu/menu_controller.h
index 09381979..a28c4cc 100644
--- a/ui/views/controls/menu/menu_controller.h
+++ b/ui/views/controls/menu/menu_controller.h
@@ -118,6 +118,16 @@
   // An alternative to Cancel(EXIT_ALL) that can be used with a OneShotTimer.
   void CancelAll() { Cancel(EXIT_ALL); }
 
+  // When is_nested_run() this will add a delegate to the stack. The most recent
+  // delegate will be notified. It will be removed upon the exiting of the
+  // nested menu. Ownership is not taken.
+  void AddNestedDelegate(internal::MenuControllerDelegate* delegate);
+
+  // Sets whether the subsequent call to Run is asynchronous. When nesting calls
+  // to Run, if a new MenuControllerDelegate has been nested, the previous
+  // asynchronous state will be reapplied once nesting has ended.
+  void SetAsyncRun(bool is_async);
+
   // Returns the current exit type. This returns a value other than EXIT_NONE if
   // the menu is being canceled.
   ExitType exit_type() const { return exit_type_; }
@@ -125,8 +135,6 @@
   // Returns the time from the event which closed the menu - or 0.
   base::TimeDelta closing_event_time() const { return closing_event_time_; }
 
-  void set_async_run(bool is_async) { async_run_ = is_async; }
-
   void set_is_combobox(bool is_combobox) { is_combobox_ = is_combobox; }
 
   // Various events, forwarded from the submenu.
@@ -582,6 +590,12 @@
   typedef std::pair<State, linked_ptr<MenuButton::PressedLock> > NestedState;
   std::list<NestedState> menu_stack_;
 
+  // When Run is invoked during an active Run, it may be called from a separate
+  // MenuControllerDelegate. If not empty is means we are nested, and the
+  // stacked delegates should be notified instead of |delegate_|.
+  typedef std::pair<internal::MenuControllerDelegate*, bool> NestedDelegate;
+  std::list<NestedDelegate> delegate_stack_;
+
   // As the mouse moves around submenus are not opened immediately. Instead
   // they open after this timer fires.
   base::OneShotTimer show_timer_;
diff --git a/ui/views/controls/menu/menu_controller_unittest.cc b/ui/views/controls/menu/menu_controller_unittest.cc
index d425a6e..6cff8555 100644
--- a/ui/views/controls/menu/menu_controller_unittest.cc
+++ b/ui/views/controls/menu/menu_controller_unittest.cc
@@ -235,6 +235,12 @@
         parent, index, MenuController::INCREMENT_SELECTION_UP);
   }
 
+  internal::MenuControllerDelegate* GetCurrentDelegate() {
+    return menu_controller_->delegate_;
+  }
+
+  bool IsAsyncRun() { return menu_controller_->async_run_; }
+
   void SelectByChar(base::char16 character) {
     menu_controller_->SelectByChar(character);
   }
@@ -517,7 +523,7 @@
 // MenuControllerDelegate when Accept is called.
 TEST_F(MenuControllerTest, AsynchronousAccept) {
   MenuController* controller = menu_controller();
-  controller->set_async_run(true);
+  controller->SetAsyncRun(true);
 
   int mouse_event_flags = 0;
   MenuItemView* run_result =
@@ -542,7 +548,7 @@
 // MenuControllerDelegate when CancelAll is called.
 TEST_F(MenuControllerTest, AsynchronousCancelAll) {
   MenuController* controller = menu_controller();
-  controller->set_async_run(true);
+  controller->SetAsyncRun(true);
 
   int mouse_event_flags = 0;
   MenuItemView* run_result =
@@ -561,5 +567,38 @@
   EXPECT_EQ(MenuController::EXIT_ALL, controller->exit_type());
 }
 
+// Tests that an asynchrnous menu nested within a synchronous menu restores the
+// previous MenuControllerDelegate and synchronous settings.
+TEST_F(MenuControllerTest, AsynchronousNestedDelegate) {
+  MenuController* controller = menu_controller();
+  TestMenuControllerDelegate* delegate = menu_controller_delegate();
+  scoped_ptr<TestMenuControllerDelegate> nested_delegate(
+      new TestMenuControllerDelegate());
+
+  ASSERT_FALSE(IsAsyncRun());
+  controller->AddNestedDelegate(nested_delegate.get());
+  controller->SetAsyncRun(true);
+
+  EXPECT_TRUE(IsAsyncRun());
+  EXPECT_EQ(nested_delegate.get(), GetCurrentDelegate());
+
+  int mouse_event_flags = 0;
+  MenuItemView* run_result =
+      controller->Run(owner(), nullptr, menu_item(), gfx::Rect(),
+                      MENU_ANCHOR_TOPLEFT, false, false, &mouse_event_flags);
+  EXPECT_EQ(run_result, nullptr);
+
+  controller->CancelAll();
+  EXPECT_FALSE(IsAsyncRun());
+  EXPECT_EQ(delegate, GetCurrentDelegate());
+  EXPECT_EQ(0, delegate->on_menu_closed_called());
+  EXPECT_EQ(1, nested_delegate->on_menu_closed_called());
+  EXPECT_EQ(nullptr, nested_delegate->on_menu_closed_menu());
+  EXPECT_EQ(0, nested_delegate->on_menu_closed_mouse_event_flags());
+  EXPECT_EQ(internal::MenuControllerDelegate::NOTIFY_DELEGATE,
+            nested_delegate->on_menu_closed_notify_type());
+  EXPECT_EQ(MenuController::EXIT_ALL, controller->exit_type());
+}
+
 }  // namespace test
 }  // namespace views
diff --git a/ui/views/controls/menu/menu_host.cc b/ui/views/controls/menu/menu_host.cc
index da2f127f..06e14e341 100644
--- a/ui/views/controls/menu/menu_host.cc
+++ b/ui/views/controls/menu/menu_host.cc
@@ -41,7 +41,7 @@
   Widget::InitParams params(Widget::InitParams::TYPE_MENU);
   const MenuController* menu_controller =
       submenu_->GetMenuItem()->GetMenuController();
-  const MenuConfig& menu_config = submenu_->GetMenuItem()->GetMenuConfig();
+  const MenuConfig& menu_config = MenuConfig::instance();
   bool rounded_border = menu_controller && menu_config.corner_radius > 0;
   bool bubble_border = submenu_->GetScrollViewContainer() &&
                        submenu_->GetScrollViewContainer()->HasBubbleBorder();
diff --git a/ui/views/controls/menu/menu_item_view.cc b/ui/views/controls/menu/menu_item_view.cc
index ff2737e..a1a4b15 100644
--- a/ui/views/controls/menu/menu_item_view.cc
+++ b/ui/views/controls/menu/menu_item_view.cc
@@ -240,7 +240,7 @@
     CreateSubmenu();
   DCHECK_GE(submenu_->child_count(), index);
   if (type == SEPARATOR) {
-    submenu_->AddChildViewAt(new MenuSeparator(this, separator_style), index);
+    submenu_->AddChildViewAt(new MenuSeparator(separator_style), index);
     return NULL;
   }
   MenuItemView* item = new MenuItemView(this, item_id, type);
@@ -418,7 +418,7 @@
 
   int height = child_at(0)->GetHeightForWidth(width);
   if (!icon_view_ && GetRootMenuItem()->has_icons())
-    height = std::max(height, GetMenuConfig().check_height);
+    height = std::max(height, MenuConfig::instance().check_height);
   height += GetBottomMargin() + GetTopMargin();
 
   return height;
@@ -545,7 +545,7 @@
       x -= width - kChildXPadding;
     }
     // Position |icon_view|.
-    const MenuConfig& config = GetMenuConfig();
+    const MenuConfig& config = MenuConfig::instance();
     if (icon_view_) {
       icon_view_->SizeToPreferredSize();
       gfx::Size size = icon_view_->GetPreferredSize();
@@ -567,10 +567,6 @@
   invalidate_dimensions();
 }
 
-const MenuConfig& MenuItemView::GetMenuConfig() const {
-  return MenuConfig::instance(GetNativeTheme());
-}
-
 MenuItemView::MenuItemView(MenuItemView* parent,
                            int command,
                            MenuItemView::Type type)
@@ -609,7 +605,7 @@
 //
 // This is invoked prior to Running a menu.
 void MenuItemView::UpdateMenuPartSizes() {
-  const MenuConfig& config = GetMenuConfig();
+  const MenuConfig& config = MenuConfig::instance();
 
   item_right_margin_ = config.label_to_arrow_padding + config.arrow_width +
                        config.arrow_to_edge_padding;
@@ -687,7 +683,8 @@
     flags |= gfx::Canvas::TEXT_ALIGN_LEFT;
 
   if (GetRootMenuItem()->has_mnemonics_) {
-    if (GetMenuConfig().show_mnemonics || GetRootMenuItem()->show_mnemonics_) {
+    if (MenuConfig::instance().show_mnemonics ||
+        GetRootMenuItem()->show_mnemonics_) {
       flags |= gfx::Canvas::SHOW_PREFIX;
     } else {
       flags |= gfx::Canvas::HIDE_PREFIX;
@@ -703,7 +700,7 @@
     if (font_list)
       return *font_list;
   }
-  return GetMenuConfig().font_list;
+  return MenuConfig::instance().font_list;
 }
 
 void MenuItemView::AddEmptyMenus() {
@@ -743,7 +740,7 @@
 }
 
 void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
-  const MenuConfig& config = GetMenuConfig();
+  const MenuConfig& config = MenuConfig::instance();
   bool render_selection =
       (mode == PB_NORMAL && IsSelected() &&
        parent_menu_item_->GetSubmenu()->GetShowSelection(this) &&
@@ -869,7 +866,7 @@
   int available_height = height() - GetTopMargin() - GetBottomMargin();
   int max_accel_width =
       parent_menu_item_->GetSubmenu()->max_minor_text_width();
-  const MenuConfig& config = GetMenuConfig();
+  const MenuConfig& config = MenuConfig::instance();
   int accel_right_margin = config.align_arrow_and_shortcut ?
                            config.arrow_to_edge_padding :  item_right_margin_;
   gfx::Rect accel_bounds(width() - accel_right_margin - max_accel_width,
@@ -908,8 +905,8 @@
 
   const MenuItemView* root = GetRootMenuItem();
   return root && root->has_icons_
-      ? GetMenuConfig().item_top_margin :
-        GetMenuConfig().item_no_icon_top_margin;
+             ? MenuConfig::instance().item_top_margin
+             : MenuConfig::instance().item_no_icon_top_margin;
 }
 
 int MenuItemView::GetBottomMargin() const {
@@ -918,8 +915,8 @@
 
   const MenuItemView* root = GetRootMenuItem();
   return root && root->has_icons_
-      ? GetMenuConfig().item_bottom_margin :
-        GetMenuConfig().item_no_icon_bottom_margin;
+             ? MenuConfig::instance().item_bottom_margin
+             : MenuConfig::instance().item_no_icon_bottom_margin;
 }
 
 gfx::Size MenuItemView::GetChildPreferredSize() const {
@@ -957,8 +954,8 @@
   // Adjust item content height if menu has both items with and without icons.
   // This way all menu items will have the same height.
   if (!icon_view_ && GetRootMenuItem()->has_icons()) {
-    dimensions.height = std::max(dimensions.height,
-                                 GetMenuConfig().check_height);
+    dimensions.height =
+        std::max(dimensions.height, MenuConfig::instance().check_height);
   }
   dimensions.height += GetBottomMargin() + GetTopMargin();
 
@@ -1000,13 +997,13 @@
       std::max(dimensions.height,
                (subtitle_.empty() ? 0 : font_list.GetHeight()) +
                font_list.GetHeight() + GetBottomMargin() + GetTopMargin());
-  dimensions.height = std::max(dimensions.height,
-                               GetMenuConfig().item_min_height);
+  dimensions.height =
+      std::max(dimensions.height, MenuConfig::instance().item_min_height);
   return dimensions;
 }
 
 int MenuItemView::GetLabelStartForThisItem() const {
-  const MenuConfig& config = GetMenuConfig();
+  const MenuConfig& config = MenuConfig::instance();
   int label_start = label_start_ + left_icon_margin_ + right_icon_margin_;
   if ((config.icons_in_label || type_ == CHECKBOX || type_ == RADIO) &&
       icon_view_)
@@ -1022,8 +1019,9 @@
   }
 
   ui::Accelerator accelerator;
-  if (GetMenuConfig().show_accelerators && GetDelegate() && GetCommand() &&
-          GetDelegate()->GetAccelerator(GetCommand(), &accelerator)) {
+  if (MenuConfig::instance().show_accelerators && GetDelegate() &&
+      GetCommand() &&
+      GetDelegate()->GetAccelerator(GetCommand(), &accelerator)) {
     return accelerator.GetShortcutText();
   }
 
@@ -1054,7 +1052,8 @@
       continue;
     } else if (menu_item->HasSubmenu()) {
       temp_width = menu_item->GetMaxIconViewWidth();
-    } else if (menu_item->icon_view() && !GetMenuConfig().icons_in_label) {
+    } else if (menu_item->icon_view() &&
+               !MenuConfig::instance().icons_in_label) {
       temp_width = menu_item->icon_view()->GetPreferredSize().width();
     }
     width = std::max(width, temp_width);
diff --git a/ui/views/controls/menu/menu_item_view.h b/ui/views/controls/menu/menu_item_view.h
index 8348320d..b6a9010 100644
--- a/ui/views/controls/menu/menu_item_view.h
+++ b/ui/views/controls/menu/menu_item_view.h
@@ -324,9 +324,6 @@
     use_right_margin_ = use_right_margin;
   }
 
-  // Returns a reference to MenuConfig to be used with this menu.
-  const MenuConfig& GetMenuConfig() const;
-
  protected:
   // Creates a MenuItemView. This is used by the various AddXXX methods.
   MenuItemView(MenuItemView* parent, int command, Type type);
diff --git a/ui/views/controls/menu/menu_runner_impl.cc b/ui/views/controls/menu/menu_runner_impl.cc
index dc3f0d21..1cb6aea 100644
--- a/ui/views/controls/menu/menu_runner_impl.cc
+++ b/ui/views/controls/menu/menu_runner_impl.cc
@@ -88,6 +88,7 @@
         controller->CancelAll();
         controller = NULL;
       }
+      controller->AddNestedDelegate(this);
     } else {
       // There's some other menu open and we're not nested. Cancel the menu.
       controller->CancelAll();
@@ -113,7 +114,7 @@
     controller = new MenuController(!for_drop_, this);
     owns_controller_ = true;
   }
-  controller->set_async_run(async_);
+  controller->SetAsyncRun(async_);
   controller->set_is_combobox((run_types & MenuRunner::COMBOBOX) != 0);
   controller_ = controller;
   menu_->set_controller(controller_);
diff --git a/ui/views/controls/menu/menu_scroll_view_container.cc b/ui/views/controls/menu/menu_scroll_view_container.cc
index 4412a330..80a63af 100644
--- a/ui/views/controls/menu/menu_scroll_view_container.cc
+++ b/ui/views/controls/menu/menu_scroll_view_container.cc
@@ -41,9 +41,8 @@
   }
 
   gfx::Size GetPreferredSize() const override {
-    return gfx::Size(
-        host_->GetMenuItem()->GetMenuConfig().scroll_arrow_height * 2 - 1,
-        pref_height_);
+    return gfx::Size(MenuConfig::instance().scroll_arrow_height * 2 - 1,
+                     pref_height_);
   }
 
   bool CanDrop(const OSExchangeData& data) override {
@@ -71,7 +70,7 @@
   }
 
   void OnPaint(gfx::Canvas* canvas) override {
-    const MenuConfig& config = host_->GetMenuItem()->GetMenuConfig();
+    const MenuConfig& config = MenuConfig::instance();
 
     // The background.
     gfx::Rect item_bounds(0, 0, width(), height());
@@ -250,7 +249,7 @@
 
   gfx::Rect bounds(0, 0, width(), height());
   NativeTheme::ExtraParams extra;
-  const MenuConfig& menu_config = content_view_->GetMenuItem()->GetMenuConfig();
+  const MenuConfig& menu_config = MenuConfig::instance();
   extra.menu_background.corner_radius = menu_config.corner_radius;
   GetNativeTheme()->Paint(canvas->sk_canvas(),
       NativeTheme::kMenuPopupBackground, NativeTheme::kNormal, bounds, extra);
@@ -280,8 +279,7 @@
   DCHECK_EQ(arrow_, BubbleBorder::NONE);
   bubble_border_ = nullptr;
 
-  const MenuConfig& menu_config =
-      content_view_->GetMenuItem()->GetMenuConfig();
+  const MenuConfig& menu_config = MenuConfig::instance();
 
   int padding = menu_config.use_outer_border && menu_config.corner_radius > 0
                     ? kBorderPaddingDueToRoundedCorners
diff --git a/ui/views/controls/menu/menu_separator.h b/ui/views/controls/menu/menu_separator.h
index a0fd2c81..966e03f 100644
--- a/ui/views/controls/menu/menu_separator.h
+++ b/ui/views/controls/menu/menu_separator.h
@@ -15,9 +15,7 @@
 
 class MenuSeparator : public View {
  public:
-  MenuSeparator(MenuItemView* parent, ui::MenuSeparatorType type)
-      : type_(type),
-        parent_menu_item_(parent) {}
+  explicit MenuSeparator(ui::MenuSeparatorType type) : type_(type) {}
 
   // View overrides.
   void OnPaint(gfx::Canvas* canvas) override;
@@ -32,9 +30,6 @@
   // The type of the separator.
   const ui::MenuSeparatorType type_;
 
-  // Our parent.
-  MenuItemView* parent_menu_item_;
-
   DISALLOW_COPY_AND_ASSIGN(MenuSeparator);
 };
 
diff --git a/ui/views/controls/menu/menu_separator_views.cc b/ui/views/controls/menu/menu_separator_views.cc
index c61cc59..6194136 100644
--- a/ui/views/controls/menu/menu_separator_views.cc
+++ b/ui/views/controls/menu/menu_separator_views.cc
@@ -8,7 +8,6 @@
 #include "ui/gfx/canvas.h"
 #include "ui/native_theme/native_theme.h"
 #include "ui/views/controls/menu/menu_config.h"
-#include "ui/views/controls/menu/menu_item_view.h"
 
 namespace {
 
@@ -25,7 +24,7 @@
 #endif
 
 gfx::Size MenuSeparator::GetPreferredSize() const {
-  const MenuConfig& menu_config = parent_menu_item_->GetMenuConfig();
+  const MenuConfig& menu_config = MenuConfig::instance();
   int height = menu_config.separator_height;
   switch(type_) {
     case ui::SPACING_SEPARATOR:
@@ -61,7 +60,7 @@
   }
 
   gfx::Rect paint_rect(0, pos, width(), kSeparatorHeight);
-  if (parent_menu_item_->GetMenuConfig().use_outer_border)
+  if (MenuConfig::instance().use_outer_border)
     paint_rect.Inset(1, 0);
   return paint_rect;
 }
diff --git a/ui/views/controls/menu/menu_wrapper.h b/ui/views/controls/menu/menu_wrapper.h
deleted file mode 100644
index 39a6fc5c..0000000
--- a/ui/views/controls/menu/menu_wrapper.h
+++ /dev/null
@@ -1,74 +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 UI_VIEWS_CONTROLS_MENU_MENU_WRAPPER_H_
-#define UI_VIEWS_CONTROLS_MENU_MENU_WRAPPER_H_
-
-#include "ui/gfx/native_widget_types.h"
-#include "ui/views/views_export.h"
-
-namespace gfx {
-class Point;
-}
-
-namespace ui {
-class MenuModel;
-}
-
-namespace views {
-
-class MenuInsertionDelegateWin;
-class MenuListener;
-
-// An interface that wraps an object that implements a menu.
-class VIEWS_EXPORT MenuWrapper {
- public:
-  // All of the possible actions that can result from RunMenuAt.
-  enum MenuAction {
-    MENU_ACTION_NONE,      // Menu cancelled, or never opened.
-    MENU_ACTION_SELECTED,  // An item was selected.
-    MENU_ACTION_PREVIOUS,  // User wants to navigate to the previous menu.
-    MENU_ACTION_NEXT,      // User wants to navigate to the next menu.
-  };
-
-  virtual ~MenuWrapper() {}
-
-  // Creates the appropriate instance of this wrapper for the current platform.
-  static MenuWrapper* CreateWrapper(ui::MenuModel* model);
-
-  // Runs the menu at the specified point. This blocks until done.
-  virtual void RunMenuAt(const gfx::Point& point, int alignment) = 0;
-
-  // Cancels the active menu.
-  virtual void CancelMenu() = 0;
-
-  // Called when the model supplying data to this menu has changed, and the menu
-  // must be rebuilt.
-  virtual void Rebuild(MenuInsertionDelegateWin* delegate) = 0;
-
-  // Called when the states of the items in the menu must be updated from the
-  // model.
-  virtual void UpdateStates() = 0;
-
-  // Retrieve a native menu handle.
-  virtual HMENU GetNativeMenu() const = 0;
-
-  // Get the result of the last call to RunMenuAt to determine whether an
-  // item was selected, the user navigated to a next or previous menu, or
-  // nothing.
-  virtual MenuAction GetMenuAction() const = 0;
-
-  // Add a listener to receive a callback when the menu opens.
-  virtual void AddMenuListener(MenuListener* listener) = 0;
-
-  // Remove a menu listener.
-  virtual void RemoveMenuListener(MenuListener* listener) = 0;
-
-  // Sets the minimum width of the menu.
-  virtual void SetMinimumWidth(int width) = 0;
-};
-
-}  // namespace views
-
-#endif  // UI_VIEWS_CONTROLS_MENU_MENU_WRAPPER_H_
diff --git a/ui/views/controls/menu/native_menu_win.cc b/ui/views/controls/menu/native_menu_win.cc
index 3c656f1..8b66b10 100644
--- a/ui/views/controls/menu/native_menu_win.cc
+++ b/ui/views/controls/menu/native_menu_win.cc
@@ -4,48 +4,17 @@
 
 #include "ui/views/controls/menu/native_menu_win.h"
 
-#include "base/bind.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
-#include "base/win/wrapped_window_proc.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_win.h"
 #include "ui/base/models/menu_model.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/font_list.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/text_utils.h"
-#include "ui/gfx/win/hwnd_util.h"
-#include "ui/native_theme/native_theme.h"
-#include "ui/native_theme/native_theme_win.h"
-#include "ui/views/controls/menu/menu_2.h"
-#include "ui/views/controls/menu/menu_config.h"
 #include "ui/views/controls/menu/menu_insertion_delegate_win.h"
-#include "ui/views/controls/menu/menu_listener.h"
-#include "ui/views/layout/layout_constants.h"
-
-using ui::NativeTheme;
 
 namespace views {
 
-// The width of an icon, including the pixels between the icon and
-// the item label.
-static const int kIconWidth = 23;
-// Margins between the top of the item and the label.
-static const int kItemTopMargin = 3;
-// Margins between the bottom of the item and the label.
-static const int kItemBottomMargin = 4;
-// Margins between the left of the item and the icon.
-static const int kItemLeftMargin = 4;
-// The width for displaying the sub-menu arrow.
-static const int kArrowWidth = 10;
-
 struct NativeMenuWin::ItemData {
   // The Windows API requires that whoever creates the menus must own the
   // strings used for labels, and keep them around for the lifetime of the
@@ -53,7 +22,7 @@
   base::string16 label;
 
   // Someone needs to own submenus, it may as well be us.
-  scoped_ptr<Menu2> submenu;
+  scoped_ptr<NativeMenuWin> submenu;
 
   // We need a pointer back to the containing menu in various circumstances.
   NativeMenuWin* native_menu_win;
@@ -71,315 +40,6 @@
   return reinterpret_cast<NativeMenuWin*>(mi.dwMenuData);
 }
 
-// A window that receives messages from Windows relevant to the native menu
-// structure we have constructed in NativeMenuWin.
-class NativeMenuWin::MenuHostWindow {
- public:
-  explicit MenuHostWindow(NativeMenuWin* parent) : parent_(parent) {
-    RegisterClass();
-    hwnd_ = CreateWindowEx(l10n_util::GetExtendedStyles(), kWindowClassName,
-                           L"", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
-    gfx::CheckWindowCreated(hwnd_);
-    gfx::SetWindowUserData(hwnd_, this);
-  }
-
-  ~MenuHostWindow() {
-    DestroyWindow(hwnd_);
-  }
-
-  HWND hwnd() const { return hwnd_; }
-
- private:
-  static const wchar_t* kWindowClassName;
-
-  void RegisterClass() {
-    static bool registered = false;
-    if (registered)
-      return;
-
-    WNDCLASSEX window_class;
-    base::win::InitializeWindowClass(
-        kWindowClassName,
-        &base::win::WrappedWindowProc<MenuHostWindowProc>,
-        CS_DBLCLKS,
-        0,
-        0,
-        NULL,
-        reinterpret_cast<HBRUSH>(COLOR_WINDOW+1),
-        NULL,
-        NULL,
-        NULL,
-        &window_class);
-    ATOM clazz = RegisterClassEx(&window_class);
-    CHECK(clazz);
-    registered = true;
-  }
-
-  // Converts the WPARAM value passed to WM_MENUSELECT into an index
-  // corresponding to the menu item that was selected.
-  int GetMenuItemIndexFromWPARAM(HMENU menu, WPARAM w_param) const {
-    int count = GetMenuItemCount(menu);
-    // For normal command menu items, Windows passes a command id as the LOWORD
-    // of WPARAM for WM_MENUSELECT. We need to walk forward through the menu
-    // items to find an item with a matching ID. Ugh!
-    for (int i = 0; i < count; ++i) {
-      MENUITEMINFO mii = {0};
-      mii.cbSize = sizeof(mii);
-      mii.fMask = MIIM_ID;
-      GetMenuItemInfo(menu, i, MF_BYPOSITION, &mii);
-      if (mii.wID == w_param)
-        return i;
-    }
-    // If we didn't find a matching command ID, this means a submenu has been
-    // selected instead, and rather than passing a command ID in
-    // LOWORD(w_param), Windows has actually passed us a position, so we just
-    // return it.
-    return w_param;
-  }
-
-  NativeMenuWin::ItemData* GetItemData(ULONG_PTR item_data) {
-    return reinterpret_cast<NativeMenuWin::ItemData*>(item_data);
-  }
-
-  // Called when the user selects a specific item.
-  void OnMenuCommand(int position, HMENU menu) {
-    NativeMenuWin* menu_win = GetNativeMenuWinFromHMENU(menu);
-    ui::MenuModel* model = menu_win->model_;
-    NativeMenuWin* root_menu = menu_win;
-    while (root_menu->parent_)
-      root_menu = root_menu->parent_;
-
-    // Only notify the model if it didn't already send out notification.
-    // See comment in MenuMessageHook for details.
-    if (root_menu->menu_action_ == MenuWrapper::MENU_ACTION_NONE)
-      model->ActivatedAt(position);
-  }
-
-  // Called as the user moves their mouse or arrows through the contents of the
-  // menu.
-  void OnMenuSelect(WPARAM w_param, HMENU menu) {
-    if (!menu)
-      return;  // menu is null when closing on XP.
-
-    int position = GetMenuItemIndexFromWPARAM(menu, w_param);
-    if (position >= 0)
-      GetNativeMenuWinFromHMENU(menu)->model_->HighlightChangedTo(position);
-  }
-
-  // Called by Windows to measure the size of an owner-drawn menu item.
-  void OnMeasureItem(WPARAM w_param, MEASUREITEMSTRUCT* measure_item_struct) {
-    NativeMenuWin::ItemData* data = GetItemData(measure_item_struct->itemData);
-    if (data) {
-      gfx::FontList font_list;
-      measure_item_struct->itemWidth =
-          gfx::GetStringWidth(data->label, font_list) +
-          kIconWidth + kItemLeftMargin + views::kItemLabelSpacing -
-          GetSystemMetrics(SM_CXMENUCHECK);
-      if (data->submenu.get())
-        measure_item_struct->itemWidth += kArrowWidth;
-      // If the label contains an accelerator, make room for tab.
-      if (data->label.find(L'\t') != base::string16::npos)
-        measure_item_struct->itemWidth += gfx::GetStringWidth(L" ", font_list);
-      measure_item_struct->itemHeight =
-          font_list.GetHeight() + kItemBottomMargin + kItemTopMargin;
-    } else {
-      // Measure separator size.
-      measure_item_struct->itemHeight = GetSystemMetrics(SM_CYMENU) / 2;
-      measure_item_struct->itemWidth = 0;
-    }
-  }
-
-  // Called by Windows to paint an owner-drawn menu item.
-  void OnDrawItem(UINT w_param, DRAWITEMSTRUCT* draw_item_struct) {
-    HDC dc = draw_item_struct->hDC;
-    COLORREF prev_bg_color, prev_text_color;
-
-    // Set background color and text color
-    if (draw_item_struct->itemState & ODS_SELECTED) {
-      prev_bg_color = SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));
-      prev_text_color = SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
-    } else {
-      prev_bg_color = SetBkColor(dc, GetSysColor(COLOR_MENU));
-      if (draw_item_struct->itemState & ODS_DISABLED)
-        prev_text_color = SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
-      else
-        prev_text_color = SetTextColor(dc, GetSysColor(COLOR_MENUTEXT));
-    }
-
-    if (draw_item_struct->itemData) {
-      NativeMenuWin::ItemData* data = GetItemData(draw_item_struct->itemData);
-      // Draw the background.
-      HBRUSH hbr = CreateSolidBrush(GetBkColor(dc));
-      FillRect(dc, &draw_item_struct->rcItem, hbr);
-      DeleteObject(hbr);
-
-      // Draw the label.
-      RECT rect = draw_item_struct->rcItem;
-      rect.top += kItemTopMargin;
-      // Should we add kIconWidth only when icon.width() != 0 ?
-      rect.left += kItemLeftMargin + kIconWidth;
-      rect.right -= views::kItemLabelSpacing;
-      UINT format = DT_TOP | DT_SINGLELINE;
-      // Check whether the mnemonics should be underlined.
-      BOOL underline_mnemonics;
-      SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &underline_mnemonics, 0);
-      if (!underline_mnemonics)
-        format |= DT_HIDEPREFIX;
-      gfx::FontList font_list;
-      HGDIOBJ old_font = static_cast<HFONT>(
-          SelectObject(dc, font_list.GetPrimaryFont().GetNativeFont()));
-
-      // If an accelerator is specified (with a tab delimiting the rest of the
-      // label from the accelerator), we have to justify the fist part on the
-      // left and the accelerator on the right.
-      // TODO(jungshik): This will break in RTL UI. Currently, he/ar use the
-      //                 window system UI font and will not hit here.
-      base::string16 label = data->label;
-      base::string16 accel;
-      base::string16::size_type tab_pos = label.find(L'\t');
-      if (tab_pos != base::string16::npos) {
-        accel = label.substr(tab_pos);
-        label = label.substr(0, tab_pos);
-      }
-      DrawTextEx(dc, const_cast<wchar_t*>(label.data()),
-                 static_cast<int>(label.size()), &rect, format | DT_LEFT, NULL);
-      if (!accel.empty())
-        DrawTextEx(dc, const_cast<wchar_t*>(accel.data()),
-                   static_cast<int>(accel.size()), &rect,
-                   format | DT_RIGHT, NULL);
-      SelectObject(dc, old_font);
-
-      ui::MenuModel::ItemType type =
-          data->native_menu_win->model_->GetTypeAt(data->model_index);
-
-      // Draw the icon after the label, otherwise it would be covered
-      // by the label.
-      gfx::Image icon;
-      if (data->native_menu_win->model_->GetIconAt(data->model_index, &icon)) {
-        // We currently don't support items with both icons and checkboxes.
-        const gfx::ImageSkia* skia_icon = icon.ToImageSkia();
-        DCHECK(type != ui::MenuModel::TYPE_CHECK);
-        gfx::Canvas canvas(
-            skia_icon->GetRepresentation(1.0f),
-            false);
-        skia::DrawToNativeContext(
-            canvas.sk_canvas(), dc,
-            draw_item_struct->rcItem.left + kItemLeftMargin,
-            draw_item_struct->rcItem.top + (draw_item_struct->rcItem.bottom -
-                draw_item_struct->rcItem.top - skia_icon->height()) / 2, NULL);
-      } else if (type == ui::MenuModel::TYPE_CHECK &&
-                 data->native_menu_win->model_->IsItemCheckedAt(
-                     data->model_index)) {
-        // Manually render a checkbox.
-        ui::NativeThemeWin* native_theme = ui::NativeThemeWin::instance();
-        const MenuConfig& config = MenuConfig::instance(native_theme);
-        NativeTheme::State state;
-        if (draw_item_struct->itemState & ODS_DISABLED) {
-          state = NativeTheme::kDisabled;
-        } else {
-          state = draw_item_struct->itemState & ODS_SELECTED ?
-              NativeTheme::kHovered : NativeTheme::kNormal;
-        }
-        gfx::Canvas canvas(gfx::Size(config.check_width, config.check_height),
-                           1.0f,
-                           false);
-        NativeTheme::ExtraParams extra;
-        extra.menu_check.is_radio = false;
-        gfx::Rect bounds(0, 0, config.check_width, config.check_height);
-
-        // Draw the background and the check.
-        native_theme->Paint(
-            canvas.sk_canvas(), NativeTheme::kMenuCheckBackground,
-            state, bounds, extra);
-        native_theme->Paint(
-            canvas.sk_canvas(), NativeTheme::kMenuCheck, state, bounds, extra);
-
-        // Draw checkbox to menu.
-        skia::DrawToNativeContext(canvas.sk_canvas(), dc,
-            draw_item_struct->rcItem.left + kItemLeftMargin,
-            draw_item_struct->rcItem.top + (draw_item_struct->rcItem.bottom -
-                draw_item_struct->rcItem.top - config.check_height) / 2, NULL);
-      }
-
-    } else {
-      // Draw the separator
-      draw_item_struct->rcItem.top +=
-          (draw_item_struct->rcItem.bottom - draw_item_struct->rcItem.top) / 3;
-      DrawEdge(dc, &draw_item_struct->rcItem, EDGE_ETCHED, BF_TOP);
-    }
-
-    SetBkColor(dc, prev_bg_color);
-    SetTextColor(dc, prev_text_color);
-  }
-
-  bool ProcessWindowMessage(HWND window,
-                            UINT message,
-                            WPARAM w_param,
-                            LPARAM l_param,
-                            LRESULT* l_result) {
-    switch (message) {
-      case WM_MENUCOMMAND:
-        OnMenuCommand(w_param, reinterpret_cast<HMENU>(l_param));
-        *l_result = 0;
-        return true;
-      case WM_MENUSELECT:
-        OnMenuSelect(LOWORD(w_param), reinterpret_cast<HMENU>(l_param));
-        *l_result = 0;
-        return true;
-      case WM_MEASUREITEM:
-        OnMeasureItem(w_param, reinterpret_cast<MEASUREITEMSTRUCT*>(l_param));
-        *l_result = 0;
-        return true;
-      case WM_DRAWITEM:
-        OnDrawItem(w_param, reinterpret_cast<DRAWITEMSTRUCT*>(l_param));
-        *l_result = 0;
-        return true;
-      // TODO(beng): bring over owner draw from old menu system.
-    }
-    return false;
-  }
-
-  static LRESULT CALLBACK MenuHostWindowProc(HWND window,
-                                             UINT message,
-                                             WPARAM w_param,
-                                             LPARAM l_param) {
-    MenuHostWindow* host =
-        reinterpret_cast<MenuHostWindow*>(gfx::GetWindowUserData(window));
-    // host is null during initial construction.
-    LRESULT l_result = 0;
-    if (!host || !host->ProcessWindowMessage(window, message, w_param, l_param,
-                                             &l_result)) {
-      return DefWindowProc(window, message, w_param, l_param);
-    }
-    return l_result;
-  }
-
-  HWND hwnd_;
-  NativeMenuWin* parent_;
-
-  DISALLOW_COPY_AND_ASSIGN(MenuHostWindow);
-};
-
-struct NativeMenuWin::HighlightedMenuItemInfo {
-  HighlightedMenuItemInfo()
-      : has_parent(false),
-        has_submenu(false),
-        menu(NULL),
-        position(-1) {
-  }
-
-  bool has_parent;
-  bool has_submenu;
-
-  // The menu and position. These are only set for non-disabled menu items.
-  NativeMenuWin* menu;
-  int position;
-};
-
-// static
-const wchar_t* NativeMenuWin::MenuHostWindow::kWindowClassName =
-    L"ViewsMenuHostWindow";
-
 ////////////////////////////////////////////////////////////////////////////////
 // NativeMenuWin, public:
 
@@ -390,12 +50,8 @@
                   !system_menu_for),
       system_menu_for_(system_menu_for),
       first_item_index_(0),
-      menu_action_(MENU_ACTION_NONE),
-      menu_to_select_(NULL),
-      position_to_select_(-1),
       parent_(NULL),
-      destroyed_flag_(NULL),
-      menu_to_select_factory_(this) {
+      destroyed_flag_(NULL) {
 }
 
 NativeMenuWin::~NativeMenuWin() {
@@ -408,61 +64,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // NativeMenuWin, MenuWrapper implementation:
 
-void NativeMenuWin::RunMenuAt(const gfx::Point& point, int alignment) {
-  CreateHostWindow();
-  UpdateStates();
-  UINT flags = TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RECURSE;
-  flags |= GetAlignmentFlags(alignment);
-  menu_action_ = MENU_ACTION_NONE;
-
-  // Set a hook function so we can listen for keyboard events while the
-  // menu is open, and store a pointer to this object in a static
-  // variable so the hook has access to it (ugly, but it's the
-  // only way).
-  open_native_menu_win_ = this;
-  HHOOK hhook = SetWindowsHookEx(WH_MSGFILTER, MenuMessageHook,
-                                 GetModuleHandle(NULL), ::GetCurrentThreadId());
-
-  // Mark that any registered listeners have not been called for this particular
-  // opening of the menu.
-  listeners_called_ = false;
-
-  // Command dispatch is done through WM_MENUCOMMAND, handled by the host
-  // window.
-  menu_to_select_ = NULL;
-  position_to_select_ = -1;
-  menu_to_select_factory_.InvalidateWeakPtrs();
-  bool destroyed = false;
-  destroyed_flag_ = &destroyed;
-  model_->MenuWillShow();
-  TrackPopupMenu(menu_, flags, point.x(), point.y(), 0, host_window_->hwnd(),
-                 NULL);
-  UnhookWindowsHookEx(hhook);
-  open_native_menu_win_ = NULL;
-  if (destroyed)
-    return;
-  destroyed_flag_ = NULL;
-  if (menu_to_select_) {
-    // Folks aren't too happy if we notify immediately. In particular, notifying
-    // the delegate can cause destruction leaving the stack in a weird
-    // state. Instead post a task, then notify. This mirrors what WM_MENUCOMMAND
-    // does.
-    menu_to_select_factory_.InvalidateWeakPtrs();
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&NativeMenuWin::DelayedSelect,
-                   menu_to_select_factory_.GetWeakPtr()));
-    menu_action_ = MENU_ACTION_SELECTED;
-  }
-  // Send MenuClosed after we schedule the select, otherwise MenuClosed is
-  // processed after the select (MenuClosed posts a delayed task too).
-  model_->MenuClosed();
-}
-
-void NativeMenuWin::CancelMenu() {
-  EndMenu();
-}
-
 void NativeMenuWin::Rebuild(MenuInsertionDelegateWin* delegate) {
   ResetNativeMenu();
   items_.clear();
@@ -492,116 +93,15 @@
       SetMenuItemLabel(menu_index, model_index,
                        model_->GetLabelAt(model_index));
     }
-    Menu2* submenu = (*it)->submenu.get();
+    NativeMenuWin* submenu = (*it)->submenu.get();
     if (submenu)
       submenu->UpdateStates();
   }
 }
 
-HMENU NativeMenuWin::GetNativeMenu() const {
-  return menu_;
-}
-
-NativeMenuWin::MenuAction NativeMenuWin::GetMenuAction() const {
-  return menu_action_;
-}
-
-void NativeMenuWin::AddMenuListener(MenuListener* listener) {
-  listeners_.AddObserver(listener);
-}
-
-void NativeMenuWin::RemoveMenuListener(MenuListener* listener) {
-  listeners_.RemoveObserver(listener);
-}
-
-void NativeMenuWin::SetMinimumWidth(int width) {
-  NOTIMPLEMENTED();
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // NativeMenuWin, private:
 
-// static
-NativeMenuWin* NativeMenuWin::open_native_menu_win_ = NULL;
-
-void NativeMenuWin::DelayedSelect() {
-  if (menu_to_select_)
-    menu_to_select_->model_->ActivatedAt(position_to_select_);
-}
-
-// static
-bool NativeMenuWin::GetHighlightedMenuItemInfo(
-    HMENU menu,
-    HighlightedMenuItemInfo* info) {
-  for (int i = 0; i < ::GetMenuItemCount(menu); i++) {
-    UINT state = ::GetMenuState(menu, i, MF_BYPOSITION);
-    if (state & MF_HILITE) {
-      if (state & MF_POPUP) {
-        HMENU submenu = GetSubMenu(menu, i);
-        if (GetHighlightedMenuItemInfo(submenu, info))
-          info->has_parent = true;
-        else
-          info->has_submenu = true;
-      } else if (!(state & MF_SEPARATOR) && !(state & MF_DISABLED)) {
-        info->menu = GetNativeMenuWinFromHMENU(menu);
-        info->position = i;
-      }
-      return true;
-    }
-  }
-  return false;
-}
-
-// static
-LRESULT CALLBACK NativeMenuWin::MenuMessageHook(
-    int n_code, WPARAM w_param, LPARAM l_param) {
-  LRESULT result = CallNextHookEx(NULL, n_code, w_param, l_param);
-
-  NativeMenuWin* this_ptr = open_native_menu_win_;
-  if (!this_ptr)
-    return result;
-
-  // The first time this hook is called, that means the menu has successfully
-  // opened, so call the callback function on all of our listeners.
-  if (!this_ptr->listeners_called_) {
-    FOR_EACH_OBSERVER(MenuListener, this_ptr->listeners_, OnMenuOpened());
-    this_ptr->listeners_called_ = true;
-  }
-
-  MSG* msg = reinterpret_cast<MSG*>(l_param);
-  if (msg->message == WM_LBUTTONUP || msg->message == WM_RBUTTONUP) {
-    HighlightedMenuItemInfo info;
-    if (GetHighlightedMenuItemInfo(this_ptr->menu_, &info) && info.menu) {
-      // It appears that when running a menu by way of TrackPopupMenu(Ex) win32
-      // gets confused if the underlying window paints itself. As its very easy
-      // for the underlying window to repaint itself (especially since some menu
-      // items trigger painting of the tabstrip on mouse over) we have this
-      // workaround. When the mouse is released on a menu item we remember the
-      // menu item and end the menu. When the nested message loop returns we
-      // schedule a task to notify the model. It's still possible to get a
-      // WM_MENUCOMMAND, so we have to be careful that we don't notify the model
-      // twice.
-      this_ptr->menu_to_select_ = info.menu;
-      this_ptr->position_to_select_ = info.position;
-      EndMenu();
-    }
-  } else if (msg->message == WM_KEYDOWN) {
-    HighlightedMenuItemInfo info;
-    if (GetHighlightedMenuItemInfo(this_ptr->menu_, &info)) {
-      if (msg->wParam == VK_LEFT && !info.has_parent) {
-        this_ptr->menu_action_ = MENU_ACTION_PREVIOUS;
-        ::EndMenu();
-      } else if (msg->wParam == VK_RIGHT && !info.has_parent &&
-                 !info.has_submenu) {
-        this_ptr->menu_action_ = MENU_ACTION_NEXT;
-        ::EndMenu();
-      }
-    }
-  }
-
-  return result;
-}
-
 bool NativeMenuWin::IsSeparatorItemAt(int menu_index) const {
   MENUITEMINFO mii = {0};
   mii.cbSize = sizeof(mii);
@@ -623,9 +123,11 @@
   item_data->label = base::string16();
   ui::MenuModel::ItemType type = model_->GetTypeAt(model_index);
   if (type == ui::MenuModel::TYPE_SUBMENU) {
-    item_data->submenu.reset(new Menu2(model_->GetSubmenuModelAt(model_index)));
+    item_data->submenu.reset(
+        new NativeMenuWin(model_->GetSubmenuModelAt(model_index), nullptr));
+    item_data->submenu->Rebuild(nullptr);
     mii.fMask |= MIIM_SUBMENU;
-    mii.hSubMenu = item_data->submenu->GetNativeMenu();
+    mii.hSubMenu = item_data->submenu->menu_;
     GetNativeMenuWinFromHMENU(mii.hSubMenu)->parent_ = this;
   } else {
     if (type == ui::MenuModel::TYPE_RADIO)
@@ -709,15 +211,6 @@
       const_cast<wchar_t*>(items_[model_index]->label.c_str());
 }
 
-UINT NativeMenuWin::GetAlignmentFlags(int alignment) const {
-  UINT alignment_flags = TPM_TOPALIGN;
-  if (alignment == Menu2::ALIGN_TOPLEFT)
-    alignment_flags |= TPM_LEFTALIGN;
-  else if (alignment == Menu2::ALIGN_TOPRIGHT)
-    alignment_flags |= TPM_RIGHTALIGN;
-  return alignment_flags;
-}
-
 void NativeMenuWin::ResetNativeMenu() {
   if (IsWindow(system_menu_for_)) {
     if (menu_)
@@ -739,20 +232,4 @@
   }
 }
 
-void NativeMenuWin::CreateHostWindow() {
-  // This only gets called from RunMenuAt, and as such there is only ever one
-  // host window per menu hierarchy, no matter how many NativeMenuWin objects
-  // exist wrapping submenus.
-  if (!host_window_.get())
-    host_window_.reset(new MenuHostWindow(this));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// MenuWrapper, public:
-
-// static
-MenuWrapper* MenuWrapper::CreateWrapper(ui::MenuModel* model) {
-  return new NativeMenuWin(model, NULL);
-}
-
 }  // namespace views
diff --git a/ui/views/controls/menu/native_menu_win.h b/ui/views/controls/menu/native_menu_win.h
index 3d4dcd1..406599c0 100644
--- a/ui/views/controls/menu/native_menu_win.h
+++ b/ui/views/controls/menu/native_menu_win.h
@@ -7,13 +7,9 @@
 
 #include <vector>
 
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
+#include "base/macros.h"
 #include "base/strings/string16.h"
-#include "ui/views/controls/menu/menu_wrapper.h"
+#include "ui/gfx/native_widget_types.h"
 #include "ui/views/views_export.h"
 
 namespace ui {
@@ -22,26 +18,19 @@
 
 namespace views {
 
-// A Windows implementation of MenuWrapper.
-// TODO(beng): rename to MenuWin once the old class is dead.
-class VIEWS_EXPORT NativeMenuWin : public MenuWrapper {
+class MenuInsertionDelegateWin;
+
+// A wrapper around a native Windows menu.
+class VIEWS_EXPORT NativeMenuWin {
  public:
   // Construct a NativeMenuWin, with a model and delegate. If |system_menu_for|
   // is non-NULL, the NativeMenuWin wraps the system menu for that window.
   // The caller owns the model and the delegate.
   NativeMenuWin(ui::MenuModel* model, HWND system_menu_for);
-  ~NativeMenuWin() override;
+  ~NativeMenuWin();
 
-  // Overridden from MenuWrapper:
-  void RunMenuAt(const gfx::Point& point, int alignment) override;
-  void CancelMenu() override;
-  void Rebuild(MenuInsertionDelegateWin* delegate) override;
-  void UpdateStates() override;
-  HMENU GetNativeMenu() const override;
-  MenuAction GetMenuAction() const override;
-  void AddMenuListener(MenuListener* listener) override;
-  void RemoveMenuListener(MenuListener* listener) override;
-  void SetMinimumWidth(int width) override;
+  void Rebuild(MenuInsertionDelegateWin* delegate);
+  void UpdateStates();
 
  private:
   // IMPORTANT: Note about indices.
@@ -56,8 +45,6 @@
   //            It is important to take this into consideration when editing the
   //            code in the functions in this class.
 
-  struct HighlightedMenuItemInfo;
-
   // Returns true if the item at the specified index is a separator.
   bool IsSeparatorItemAt(int menu_index) const;
 
@@ -84,29 +71,10 @@
                                    int model_index,
                                    const base::string16& label);
 
-  // Returns the alignment flags to be passed to TrackPopupMenuEx, based on the
-  // supplied alignment and the UI text direction.
-  UINT GetAlignmentFlags(int alignment) const;
-
   // Resets the native menu stored in |menu_| by destroying any old menu then
   // creating a new empty one.
   void ResetNativeMenu();
 
-  // Creates the host window that receives notifications from the menu.
-  void CreateHostWindow();
-
-  // Callback from task to notify menu it was selected.
-  void DelayedSelect();
-
-  // Given a menu that's currently popped-up, find the currently highlighted
-  // item. Returns true if a highlighted item was found.
-  static bool GetHighlightedMenuItemInfo(HMENU menu,
-                                         HighlightedMenuItemInfo* info);
-
-  // Hook to receive keyboard events while the menu is open.
-  static LRESULT CALLBACK MenuMessageHook(
-      int n_code, WPARAM w_param, LPARAM l_param);
-
   // Our attached model and delegate.
   ui::MenuModel* model_;
 
@@ -121,11 +89,6 @@
   struct ItemData;
   std::vector<ItemData*> items_;
 
-  // The window that receives notifications from the menu.
-  class MenuHostWindow;
-  friend MenuHostWindow;
-  scoped_ptr<MenuHostWindow> host_window_;
-
   // The HWND this menu is the system menu for, or NULL if the menu is not a
   // system menu.
   HWND system_menu_for_;
@@ -133,20 +96,6 @@
   // The index of the first item in the model in the menu.
   int first_item_index_;
 
-  // The action that took place during the call to RunMenuAt.
-  MenuAction menu_action_;
-
-  // A list of listeners to call when the menu opens.
-  base::ObserverList<MenuListener> listeners_;
-
-  // Keep track of whether the listeners have already been called at least
-  // once.
-  bool listeners_called_;
-
-  // See comment in MenuMessageHook for details on these.
-  NativeMenuWin* menu_to_select_;
-  int position_to_select_;
-
   // If we're a submenu, this is our parent.
   NativeMenuWin* parent_;
 
@@ -155,13 +104,6 @@
   // running.
   bool* destroyed_flag_;
 
-  base::WeakPtrFactory<NativeMenuWin> menu_to_select_factory_;
-
-  // Ugly: a static pointer to the instance of this class that currently
-  // has a menu open, because our hook function that receives keyboard
-  // events doesn't have a mechanism to get a user data pointer.
-  static NativeMenuWin* open_native_menu_win_;
-
   DISALLOW_COPY_AND_ASSIGN(NativeMenuWin);
 };
 
diff --git a/ui/views/controls/menu/submenu_view.cc b/ui/views/controls/menu/submenu_view.cc
index 5fba696..1e2de11 100644
--- a/ui/views/controls/menu/submenu_view.cc
+++ b/ui/views/controls/menu/submenu_view.cc
@@ -160,10 +160,9 @@
                                    child->GetPreferredSize().width());
     }
   }
-  if (max_minor_text_width_ > 0) {
-    max_minor_text_width_ +=
-        GetMenuItem()->GetMenuConfig().label_to_minor_text_padding;
-  }
+  if (max_minor_text_width_ > 0)
+    max_minor_text_width_ += MenuConfig::instance().label_to_minor_text_padding;
+
   // Finish calculating our optimum width.
   gfx::Insets insets = GetInsets();
   int width = std::max(max_complex_width,
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc
index fecc19060..0d0fd29 100644
--- a/ui/views/controls/textfield/textfield_unittest.cc
+++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -27,6 +27,7 @@
 #include "ui/events/event_processor.h"
 #include "ui/events/event_utils.h"
 #include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/test/event_generator.h"
 #include "ui/gfx/render_text.h"
 #include "ui/strings/grit/ui_strings.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
@@ -51,10 +52,6 @@
 #include "ui/events/event_utils.h"
 #endif
 
-#if defined(OS_MACOSX) && !defined(USE_AURA)
-#include "ui/events/test/event_generator.h"
-#endif
-
 using base::ASCIIToUTF16;
 using base::UTF8ToUTF16;
 using base::WideToUTF16;
@@ -145,8 +142,10 @@
   // Checks whether the key event is from EventGenerator on Windows which will
   // generate key event for WM_CHAR.
   // The MockInputMethod will insert char on WM_KEYDOWN so ignore WM_CHAR here.
-  if (key->is_char() && key->HasNativeEvent())
+  if (key->is_char() && key->HasNativeEvent()) {
+    key->SetHandled();
     return;
+  }
 
   bool handled = !IsTextInputTypeNone() && HasComposition();
   ClearStates();
@@ -436,13 +435,10 @@
     // don't want parallel tests to steal active status either, so fake it.
 #if defined(OS_MACOSX) && !defined(USE_AURA)
     fake_activation_ = test::WidgetTest::FakeWidgetIsActiveAlways();
-
-    // This is only used on Mac. See comment regarding |event_generator_| below.
+#endif
     event_generator_.reset(
         new ui::test::EventGenerator(GetContext(), widget_->GetNativeWindow()));
-#endif
   }
-
   ui::MenuModel* GetContextMenuModel() {
     test_api_->UpdateContextMenu();
     return test_api_->context_menu_contents();
@@ -467,17 +463,7 @@
 
  protected:
   void SendKeyPress(ui::KeyboardCode key_code, int flags) {
-#if defined(OS_MACOSX) && !defined(USE_AURA)
-    // The Mac EventGenerator hooks in before IME. It sends events first to an
-    // NSResponder, which is necessary to interpret keyboard events into
-    // appropriate editing commands.
     event_generator_->PressKey(key_code, flags);
-#else
-    // TODO(shuchen): making EventGenerator support input method and using
-    // EventGenerator here. crbug.com/512315.
-    ui::KeyEvent event(ui::ET_KEY_PRESSED, key_code, flags);
-    input_method_->DispatchKeyEvent(&event);
-#endif
   }
 
   void SendKeyEvent(ui::KeyboardCode key_code,
@@ -669,11 +655,7 @@
  private:
   ui::ClipboardType copied_to_clipboard_;
   scoped_ptr<test::WidgetTest::FakeActivation> fake_activation_;
-
-#if defined(OS_MACOSX) && !defined(USE_AURA)
   scoped_ptr<ui::test::EventGenerator> event_generator_;
-#endif
-
   DISALLOW_COPY_AND_ASSIGN(TextfieldTest);
 };
 
diff --git a/ui/views/corewm/cursor_height_provider_win.cc b/ui/views/corewm/cursor_height_provider_win.cc
index 16d37cee..f9d4f98d 100644
--- a/ui/views/corewm/cursor_height_provider_win.cc
+++ b/ui/views/corewm/cursor_height_provider_win.cc
@@ -104,17 +104,48 @@
   if (data == NULL)
     return kDefaultHeight;
 
-  const int cursor_height = GetSystemMetrics(SM_CYCURSOR);
-  // Crash data seems to indicate cursor_height may be bigger than the bitmap.
-  int i = std::max(0, static_cast<int>(bitmap_info.bmiHeader.biHeight) -
-                   cursor_height);
-  for (; i < bitmap_info.bmiHeader.biHeight; ++i) {
-    if (!IsRowTransparent(data, row_size, last_byte_mask, i)) {
-      i--;
+  // There are 2 types of cursors: Ones that cover the area underneath
+  // completely (i.e. hand cursor) and ones that partially cover
+  // and partially blend with background (i. e. I-beam cursor).
+  // These will have either 1 square mask or 2 masks stacked on top
+  // of each other (xor mask and and mask).
+  const bool has_xor_mask =
+      bitmap_info.bmiHeader.biHeight == 2 * bitmap_info.bmiHeader.biWidth;
+  const int cursor_height =
+      has_xor_mask ? static_cast<int>(bitmap_info.bmiHeader.biHeight / 2)
+                   : static_cast<int>(bitmap_info.bmiHeader.biHeight);
+  int xor_offset;
+  if (has_xor_mask) {
+    for (xor_offset = 0; xor_offset < cursor_height; ++xor_offset) {
+      const uint32_t row_start = row_size * xor_offset;
+      const uint32_t row_boundary = row_start + row_size;
+      for (uint32_t i = row_start; i < row_boundary; ++i)
+        data.get()[i] = ~(data.get()[i]);
+      if (!IsRowTransparent(data, row_size, last_byte_mask, xor_offset)) {
+        break;
+      }
+    }
+  } else {
+    xor_offset = cursor_height;
+  }
+
+  int and_offset;
+
+  for (and_offset = has_xor_mask ? cursor_height : 0;
+       and_offset < bitmap_info.bmiHeader.biHeight; ++and_offset) {
+    if (!IsRowTransparent(data, row_size, last_byte_mask, and_offset)) {
       break;
     }
   }
-  return bitmap_info.bmiHeader.biHeight - i - icon.yHotspot;
+  if (has_xor_mask) {
+    and_offset -= cursor_height;
+  }
+  const int offset = std::min(xor_offset, and_offset);
+
+  DeleteObject(icon.hbmColor);
+  DeleteObject(icon.hbmMask);
+
+  return cursor_height - offset - icon.yHotspot + 1;
 }
 
 }  // namespace
diff --git a/ui/views/test/event_generator_delegate_mac.mm b/ui/views/test/event_generator_delegate_mac.mm
index 64b93d79..74c3edc 100644
--- a/ui/views/test/event_generator_delegate_mac.mm
+++ b/ui/views/test/event_generator_delegate_mac.mm
@@ -284,6 +284,12 @@
                             gfx::Point* point) const override {}
   void ConvertPointFromHost(const ui::EventTarget* hosted_target,
                             gfx::Point* point) const override {}
+  void DispatchKeyEventToIME(EventTarget* target,
+                             ui::KeyEvent* event) override {
+    // InputMethodMac does not send native events nor do the necessary
+    // translation. Key events must be handled natively by an NSResponder which
+    // translates keyboard events into editing commands.
+  }
 
  private:
   friend struct base::DefaultSingletonTraits<EventGeneratorDelegateMac>;
diff --git a/ui/views/views.gyp b/ui/views/views.gyp
index 328999b..30471e4a 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -101,6 +101,8 @@
       'controls/menu/display_change_listener_mac.cc',
       'controls/menu/menu_config.cc',
       'controls/menu/menu_config.h',
+      'controls/menu/menu_config_chromeos.cc',
+      'controls/menu/menu_config_linux.cc',
       'controls/menu/menu_config_mac.mm',
       'controls/menu/menu_config_win.cc',
       'controls/menu/menu_controller.cc',
@@ -344,9 +346,6 @@
       'window/window_shape.h',
     ],
     'views_win_sources': [
-      'controls/menu/menu_2.cc',
-      'controls/menu/menu_2.h',
-      'controls/menu/menu_wrapper.h',
       'widget/widget_hwnd_utils.cc',
       'widget/widget_hwnd_utils.h',
       'win/fullscreen_handler.cc',
@@ -375,7 +374,6 @@
       'bubble/tray_bubble_view.cc',
       'bubble/tray_bubble_view.h',
       'controls/menu/display_change_listener_aura.cc',
-      'controls/menu/menu_config_aura.cc',
       'controls/menu/menu_event_dispatcher.cc',
       'controls/menu/menu_event_dispatcher.h',
       'controls/menu/menu_key_event_handler.cc',
@@ -502,10 +500,10 @@
       'test/focus_manager_test.h',
       'test/menu_runner_test_api.cc',
       'test/menu_runner_test_api.h',
-      'test/slider_test_api.cc',
-      'test/slider_test_api.h',
       'test/scoped_views_test_helper.cc',
       'test/scoped_views_test_helper.h',
+      'test/slider_test_api.cc',
+      'test/slider_test_api.h',
       'test/test_views.cc',
       'test/test_views.h',
       'test/test_views_delegate.h',
@@ -544,6 +542,7 @@
       'animation/bounds_animator_unittest.cc',
       'animation/ink_drop_animation_controller_factory_unittest.cc',
       'animation/ink_drop_animation_unittest.cc',
+      'animation/ink_drop_delegate_unittest.cc',
       'bubble/bubble_border_unittest.cc',
       'bubble/bubble_delegate_unittest.cc',
       'bubble/bubble_frame_view_unittest.cc',
@@ -695,6 +694,9 @@
           'sources/': [
             ['exclude', 'linux_ui'],
           ],
+          'sources!': [
+            'controls/menu/menu_config_linux.cc',
+          ],
         }],
         ['OS=="win"', {
           'sources': [
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index a5dfc22..9ebb62d 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -1413,7 +1413,7 @@
   DWORD obj_id = static_cast<DWORD>(static_cast<DWORD_PTR>(l_param));
 
   // Accessibility readers will send an OBJID_CLIENT message
-  if (OBJID_CLIENT == obj_id) {
+  if (static_cast<DWORD>(OBJID_CLIENT) == obj_id) {
     // Retrieve MSAA dispatch object for the root view.
     base::win::ScopedComPtr<IAccessible> root(
         delegate_->GetNativeViewAccessible());
diff --git a/win8/delegate_execute/BUILD.gn b/win8/delegate_execute/BUILD.gn
index 87cc1b1..3f409825 100644
--- a/win8/delegate_execute/BUILD.gn
+++ b/win8/delegate_execute/BUILD.gn
@@ -19,6 +19,7 @@
   deps = [
     ":lib",
     ":version_resources",
+    "//base:base_static",
   ]
 }
 
diff --git a/win8/delegate_execute/delegate_execute_util_unittest.cc b/win8/delegate_execute/delegate_execute_util_unittest.cc
index 63a5075..47916fdf 100644
--- a/win8/delegate_execute/delegate_execute_util_unittest.cc
+++ b/win8/delegate_execute/delegate_execute_util_unittest.cc
@@ -47,16 +47,16 @@
       this_exe,
       delegate_execute::CommandLineFromParameters(NULL),
       base::string16());
-  EXPECT_EQ(1, cl.argv().size());
+  EXPECT_EQ(1u, cl.argv().size());
   EXPECT_EQ(this_exe.value(), cl.GetProgram().value());
 
   // Empty params with arg contains the arg.
   cl = delegate_execute::MakeChromeCommandLine(
       this_exe, delegate_execute::CommandLineFromParameters(NULL),
       base::string16(kSomeArgument));
-  EXPECT_EQ(2, cl.argv().size());
+  EXPECT_EQ(2u, cl.argv().size());
   EXPECT_EQ(this_exe.value(), cl.GetProgram().value());
-  EXPECT_EQ(1, cl.GetArgs().size());
+  EXPECT_EQ(1u, cl.GetArgs().size());
   EXPECT_EQ(base::string16(kSomeArgument), cl.GetArgs()[0]);
 
   // Params with switchs and args plus arg contains the arg.
@@ -66,11 +66,11 @@
                              base::ASCIIToUTF16(kSomeSwitch).c_str(),
                              kOtherArgument).c_str()),
       base::string16(kSomeArgument));
-  EXPECT_EQ(5, cl.argv().size());
+  EXPECT_EQ(5u, cl.argv().size());
   EXPECT_EQ(this_exe.value(), cl.GetProgram().value());
   EXPECT_TRUE(cl.HasSwitch(kSomeSwitch));
   base::CommandLine::StringVector args(cl.GetArgs());
-  EXPECT_EQ(2, args.size());
+  EXPECT_EQ(2u, args.size());
   EXPECT_NE(
       args.end(),
       std::find(args.begin(), args.end(), base::string16(kOtherArgument)));